aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Sema.zig69
-rw-r--r--test/behavior/call.zig23
2 files changed, 85 insertions, 7 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 7f32444774..1fdc9e02eb 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -13154,9 +13154,59 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
}
fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const tracy = trace(@src());
+ defer tracy.end();
+
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- return sema.fail(block, src, "TODO: Sema.zirBuiltinCall", .{});
+ const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+ const args_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
+ const call_src = inst_data.src();
+
+ const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index);
+ var func = sema.resolveInst(extra.data.callee);
+ const options = sema.resolveInst(extra.data.options);
+ const args = sema.resolveInst(extra.data.args);
+
+ const modifier: std.builtin.CallOptions.Modifier = modifier: {
+ const export_options_ty = try sema.getBuiltinType(block, options_src, "CallOptions");
+ const coerced_options = try sema.coerce(block, export_options_ty, options, options_src);
+ const options_val = try sema.resolveConstValue(block, options_src, coerced_options);
+ const fields = options_val.castTag(.@"struct").?.data;
+ const struct_obj = export_options_ty.castTag(.@"struct").?.data;
+ const modifier_index = struct_obj.fields.getIndex("modifier").?;
+ const stack_index = struct_obj.fields.getIndex("stack").?;
+ if (!fields[stack_index].isNull()) {
+ return sema.fail(block, options_src, "TODO: implement @call with stack", .{});
+ }
+ break :modifier fields[modifier_index].toEnum(std.builtin.CallOptions.Modifier);
+ };
+
+ const args_ty = sema.typeOf(args);
+ if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) {
+ return sema.fail(block, args_src, "expected a tuple, found {}", .{args_ty});
+ }
+
+ var resolved_args: []Air.Inst.Ref = undefined;
+
+ // Desugar bound functions here
+ if (sema.typeOf(func).tag() == .bound_fn) {
+ const bound_func = try sema.resolveValue(block, func_src, func);
+ const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
+ func = bound_data.func_inst;
+ resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1);
+ resolved_args[0] = bound_data.arg0_inst;
+ for (resolved_args[1..]) |*resolved, i| {
+ resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
+ }
+ } else {
+ resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount());
+ for (resolved_args) |*resolved, i| {
+ resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
+ }
+ }
+
+ return sema.analyzeCall(block, func, func_src, call_src, modifier, false, resolved_args);
}
fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -14684,10 +14734,8 @@ fn tupleFieldVal(
field_name_src: LazySrcLoc,
tuple_ty: Type,
) CompileError!Air.Inst.Ref {
- const tuple = tuple_ty.castTag(.tuple).?.data;
-
if (mem.eql(u8, field_name, "len")) {
- return sema.addIntUnsigned(Type.usize, tuple.types.len);
+ return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount());
}
const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {
@@ -14695,7 +14743,18 @@ fn tupleFieldVal(
tuple_ty, field_name, @errorName(err),
});
};
+ return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty);
+}
+fn tupleFieldValByIndex(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ tuple_byval: Air.Inst.Ref,
+ field_index: u32,
+ tuple_ty: Type,
+) CompileError!Air.Inst.Ref {
+ const tuple = tuple_ty.castTag(.tuple).?.data;
const field_ty = tuple.types[field_index];
if (tuple.values[field_index].tag() != .unreachable_value) {
diff --git a/test/behavior/call.zig b/test/behavior/call.zig
index 69e8fc6570..57bc0fb3f7 100644
--- a/test/behavior/call.zig
+++ b/test/behavior/call.zig
@@ -3,6 +3,21 @@ const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
+test "super basic invocations" {
+ const foo = struct {
+ fn foo() i32 {
+ return 1234;
+ }
+ }.foo;
+ try expect(@call(.{}, foo, .{}) == 1234);
+ comptime try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234);
+ {
+ // comptime call without comptime keyword
+ const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
+ comptime try expect(result);
+ }
+}
+
test "basic invocations" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
@@ -34,7 +49,10 @@ test "basic invocations" {
}
test "tuple parameters" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const add = struct {
fn add(a: i32, b: i32) i32 {
@@ -47,7 +65,8 @@ test "tuple parameters" {
try expect(@call(.{}, add, .{ 12, b }) == 46);
try expect(@call(.{}, add, .{ a, b }) == 46);
try expect(@call(.{}, add, .{ 12, 34 }) == 46);
- comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46);
+ if (builtin.zig_backend == .stage1) comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46); // TODO
+ try expect(comptime @call(.{}, add, .{ 12, 34 }) == 46);
{
const separate_args0 = .{ a, b };
const separate_args1 = .{ a, 34 };