From a947f97331595df4ee340bbcfcef7241555c687b Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 21 Nov 2023 13:23:24 +0200 Subject: [PATCH 1/2] Sema: fix bad error location on field init with field access Closes #14753 --- src/Module.zig | 17 +++++++++++++++-- src/Sema.zig | 4 ++-- ...invalid_field_in_struct_value_expression.zig | 9 +++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 828ceb734a..3b554553f7 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1467,6 +1467,14 @@ pub const SrcLoc = struct { const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len)); return Span{ .start = start, .end = end, .main = start }; }, + .node_offset_field_name_init => |node_off| { + const tree = try src_loc.file_scope.getTree(gpa); + const node = src_loc.declRelativeToNodeIndex(node_off); + const tok_index = tree.firstToken(node) - 2; + const start = tree.tokens.items(.start)[tok_index]; + const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len)); + return Span{ .start = start, .end = end, .main = start }; + }, .node_offset_deref_ptr => |node_off| { const tree = try src_loc.file_scope.getTree(gpa); const node = src_loc.declRelativeToNodeIndex(node_off); @@ -2132,10 +2140,14 @@ pub const LazySrcLoc = union(enum) { /// The payload is offset from the containing Decl AST node. /// The source location points to the field name of: /// * a field access expression (`a.b`), or - /// * the callee of a method call (`a.b()`), or - /// * the operand ("b" node) of a field initialization expression (`.a = b`), or + /// * the callee of a method call (`a.b()`) /// The Decl is determined contextually. node_offset_field_name: i32, + /// The payload is offset from the containing Decl AST node. + /// The source location points to the field name of the operand ("b" node) + /// of a field initialization expression (`.a = b`) + /// The Decl is determined contextually. + node_offset_field_name_init: i32, /// The source location points to the pointer of a pointer deref expression, /// found by taking this AST node index offset from the containing /// Decl AST node, which points to a pointer deref AST node. Next, navigate @@ -2374,6 +2386,7 @@ pub const LazySrcLoc = union(enum) { .node_offset_slice_sentinel, .node_offset_call_func, .node_offset_field_name, + .node_offset_field_name_init, .node_offset_deref_ptr, .node_offset_asm_source, .node_offset_asm_ret_ty, diff --git a/src/Sema.zig b/src/Sema.zig index d8f87f50e0..a15699c867 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9931,7 +9931,7 @@ fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = inst_data.src(); - const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; + const field_name_src: LazySrcLoc = .{ .node_offset_field_name_init = inst_data.src_node }; const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start)); const object_ptr = try sema.resolveInst(extra.lhs); @@ -19921,7 +19921,7 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; const ty_src = inst_data.src(); - const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; + const field_name_src: LazySrcLoc = .{ .node_offset_field_name_init = inst_data.src_node }; const wrapped_aggregate_ty = sema.resolveType(block, ty_src, extra.container_type) catch |err| switch (err) { // Since this is a ZIR instruction that returns a type, encountering // generic poison should not result in a failed compilation, but the diff --git a/test/cases/compile_errors/invalid_field_in_struct_value_expression.zig b/test/cases/compile_errors/invalid_field_in_struct_value_expression.zig index f1cd96d8e7..251559824e 100644 --- a/test/cases/compile_errors/invalid_field_in_struct_value_expression.zig +++ b/test/cases/compile_errors/invalid_field_in_struct_value_expression.zig @@ -21,6 +21,13 @@ pub export fn entry() void { dump(.{ .field_1 = 123, .field_3 = 456 }); } +pub export fn entry1() void { + const x = Object{ + .abc = 1, + }; + _ = x; +} + // error // backend=stage2 // target=native @@ -29,3 +36,5 @@ pub export fn entry() void { // :1:11: note: struct declared here // :21:30: error: no field named 'field_3' in struct 'tmp.Object' // :15:16: note: struct declared here +// :26:10: error: no field named 'abc' in struct 'tmp.Object' +// :15:16: note: struct declared here From d63298da65df7fa2712bf9e9d65d36cd91af22fa Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 21 Nov 2023 13:44:03 +0200 Subject: [PATCH 2/2] InternPool: handle `funcZirBodyInst` for `func_coerced` Closes #18039 --- src/InternPool.zig | 7 +++++++ test/behavior/call.zig | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/InternPool.zig b/src/InternPool.zig index 10016a9329..11204287f6 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -8301,6 +8301,13 @@ pub fn funcZirBodyInst(ip: *const InternPool, i: Index) Zir.Inst.Index { assert(ip.items.items(.tag)[func_decl_index] == .func_decl); break :b ip.items.items(.data)[func_decl_index] + zir_body_inst_field_index; }, + .func_coerced => { + const datas = ip.items.items(.data); + const uncoerced_func_index: Index = @enumFromInt(ip.extra.items[ + datas[@intFromEnum(i)] + std.meta.fieldIndex(Tag.FuncCoerced, "func").? + ]); + return ip.funcZirBodyInst(uncoerced_func_index); + }, else => unreachable, }; return @enumFromInt(ip.extra.items[extra_index]); diff --git a/test/behavior/call.zig b/test/behavior/call.zig index a476ba1788..b579f85213 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -499,3 +499,24 @@ test "call inline fn through pointer" { const f = &S.foo; try f(123); } + +test "call coerced function" { + const T = struct { + x: f64, + const T = @This(); + usingnamespace Implement(1); + const F = fn (comptime f64) type; + const Implement: F = opaque { + fn implementer(comptime val: anytype) type { + return opaque { + fn incr(self: T) T { + return .{ .x = self.x + val }; + } + }; + } + }.implementer; + }; + + const a = T{ .x = 3 }; + try std.testing.expect(a.incr().x == 4); +}