diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-02-27 18:23:50 +0200 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-02-27 18:59:44 -0500 |
| commit | 87dc60e8de58a392fe6e5e6b4dd5c41f487d367a (patch) | |
| tree | 4f76d7c2b0a51a4c917bb31b539bb54fe33fd542 | |
| parent | 720a5f87d402740045cc28650726c42adb521166 (diff) | |
| download | zig-87dc60e8de58a392fe6e5e6b4dd5c41f487d367a.tar.gz zig-87dc60e8de58a392fe6e5e6b4dd5c41f487d367a.zip | |
stage2: implement builtin_call
| -rw-r--r-- | src/Sema.zig | 69 | ||||
| -rw-r--r-- | test/behavior/call.zig | 23 |
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 }; |
