authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-27 18:23:50+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-27 18:59:44-05:00
log87dc60e8de58a392fe6e5e6b4dd5c41f487d367a
tree4f76d7c2b0a51a4c917bb31b539bb54fe33fd542
parent720a5f87d402740045cc28650726c42adb521166

stage2: implement builtin_call


2 files changed, 85 insertions(+), 7 deletions(-)

src/Sema.zig+64-5
...@@ -13154,9 +13154,59 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13154,9 +13154,59 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13154}13154}
1315513155
13156fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {13156fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
13157 const tracy = trace(@src());
13158 defer tracy.end();
13159
13157 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;13160 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
13158 const src = inst_data.src();13161 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
13159 return sema.fail(block, src, "TODO: Sema.zirBuiltinCall", .{});13162 const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
13163 const args_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
13164 const call_src = inst_data.src();
13165
13166 const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index);
13167 var func = sema.resolveInst(extra.data.callee);
13168 const options = sema.resolveInst(extra.data.options);
13169 const args = sema.resolveInst(extra.data.args);
13170
13171 const modifier: std.builtin.CallOptions.Modifier = modifier: {
13172 const export_options_ty = try sema.getBuiltinType(block, options_src, "CallOptions");
13173 const coerced_options = try sema.coerce(block, export_options_ty, options, options_src);
13174 const options_val = try sema.resolveConstValue(block, options_src, coerced_options);
13175 const fields = options_val.castTag(.@"struct").?.data;
13176 const struct_obj = export_options_ty.castTag(.@"struct").?.data;
13177 const modifier_index = struct_obj.fields.getIndex("modifier").?;
13178 const stack_index = struct_obj.fields.getIndex("stack").?;
13179 if (!fields[stack_index].isNull()) {
13180 return sema.fail(block, options_src, "TODO: implement @call with stack", .{});
13181 }
13182 break :modifier fields[modifier_index].toEnum(std.builtin.CallOptions.Modifier);
13183 };
13184
13185 const args_ty = sema.typeOf(args);
13186 if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) {
13187 return sema.fail(block, args_src, "expected a tuple, found {}", .{args_ty});
13188 }
13189
13190 var resolved_args: []Air.Inst.Ref = undefined;
13191
13192 // Desugar bound functions here
13193 if (sema.typeOf(func).tag() == .bound_fn) {
13194 const bound_func = try sema.resolveValue(block, func_src, func);
13195 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
13196 func = bound_data.func_inst;
13197 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1);
13198 resolved_args[0] = bound_data.arg0_inst;
13199 for (resolved_args[1..]) |*resolved, i| {
13200 resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
13201 }
13202 } else {
13203 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount());
13204 for (resolved_args) |*resolved, i| {
13205 resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
13206 }
13207 }
13208
13209 return sema.analyzeCall(block, func, func_src, call_src, modifier, false, resolved_args);
13160}13210}
1316113211
13162fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {13212fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -14684,10 +14734,8 @@ fn tupleFieldVal(...@@ -14684,10 +14734,8 @@ fn tupleFieldVal(
14684 field_name_src: LazySrcLoc,14734 field_name_src: LazySrcLoc,
14685 tuple_ty: Type,14735 tuple_ty: Type,
14686) CompileError!Air.Inst.Ref {14736) CompileError!Air.Inst.Ref {
14687 const tuple = tuple_ty.castTag(.tuple).?.data;
14688
14689 if (mem.eql(u8, field_name, "len")) {14737 if (mem.eql(u8, field_name, "len")) {
14690 return sema.addIntUnsigned(Type.usize, tuple.types.len);14738 return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount());
14691 }14739 }
1469214740
14693 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {14741 const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {
...@@ -14695,7 +14743,18 @@ fn tupleFieldVal(...@@ -14695,7 +14743,18 @@ fn tupleFieldVal(
14695 tuple_ty, field_name, @errorName(err),14743 tuple_ty, field_name, @errorName(err),
14696 });14744 });
14697 };14745 };
14746 return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty);
14747}
1469814748
14749fn tupleFieldValByIndex(
14750 sema: *Sema,
14751 block: *Block,
14752 src: LazySrcLoc,
14753 tuple_byval: Air.Inst.Ref,
14754 field_index: u32,
14755 tuple_ty: Type,
14756) CompileError!Air.Inst.Ref {
14757 const tuple = tuple_ty.castTag(.tuple).?.data;
14699 const field_ty = tuple.types[field_index];14758 const field_ty = tuple.types[field_index];
1470014759
14701 if (tuple.values[field_index].tag() != .unreachable_value) {14760 if (tuple.values[field_index].tag() != .unreachable_value) {
test/behavior/call.zig+21-2
...@@ -3,6 +3,21 @@ const std = @import("std");...@@ -3,6 +3,21 @@ const std = @import("std");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
55
6test "super basic invocations" {
7 const foo = struct {
8 fn foo() i32 {
9 return 1234;
10 }
11 }.foo;
12 try expect(@call(.{}, foo, .{}) == 1234);
13 comptime try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234);
14 {
15 // comptime call without comptime keyword
16 const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
17 comptime try expect(result);
18 }
19}
20
6test "basic invocations" {21test "basic invocations" {
7 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO22 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
823
...@@ -34,7 +49,10 @@ test "basic invocations" {...@@ -34,7 +49,10 @@ test "basic invocations" {
34}49}
3550
36test "tuple parameters" {51test "tuple parameters" {
37 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO52 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
3856
39 const add = struct {57 const add = struct {
40 fn add(a: i32, b: i32) i32 {58 fn add(a: i32, b: i32) i32 {
...@@ -47,7 +65,8 @@ test "tuple parameters" {...@@ -47,7 +65,8 @@ test "tuple parameters" {
47 try expect(@call(.{}, add, .{ 12, b }) == 46);65 try expect(@call(.{}, add, .{ 12, b }) == 46);
48 try expect(@call(.{}, add, .{ a, b }) == 46);66 try expect(@call(.{}, add, .{ a, b }) == 46);
49 try expect(@call(.{}, add, .{ 12, 34 }) == 46);67 try expect(@call(.{}, add, .{ 12, 34 }) == 46);
50 comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46);68 if (builtin.zig_backend == .stage1) comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46); // TODO
69 try expect(comptime @call(.{}, add, .{ 12, 34 }) == 46);
51 {70 {
52 const separate_args0 = .{ a, b };71 const separate_args0 = .{ a, b };
53 const separate_args1 = .{ a, 34 };72 const separate_args1 = .{ a, 34 };