Commit c95a34b68f

Veikka Tuominen <git@vexu.eu>
2022-10-18 12:45:06
stage2: improve source location of assignment
1 parent 34e4b07
src/AstGen.zig
@@ -232,7 +232,7 @@ pub const ResultLoc = union(enum) {
     coerced_ty: Zir.Inst.Ref,
     /// The expression must store its result into this typed pointer. The result instruction
     /// from the expression must be ignored.
-    ptr: Zir.Inst.Ref,
+    ptr: PtrResultLoc,
     /// The expression must store its result into this allocation, which has an inferred type.
     /// The result instruction from the expression must be ignored.
     /// Always an instruction with tag `alloc_inferred`.
@@ -242,6 +242,11 @@ pub const ResultLoc = union(enum) {
     /// The result instruction from the expression must be ignored.
     block_ptr: *GenZir,
 
+    const PtrResultLoc = struct {
+        inst: Zir.Inst.Ref,
+        src_node: ?Ast.Node.Index = null,
+    };
+
     pub const Strategy = struct {
         elide_store_to_block_ptr_instructions: bool,
         tag: Tag,
@@ -1380,8 +1385,8 @@ fn arrayInitExpr(
             const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
             return rvalue(gz, rl, result, node);
         },
-        .ptr => |ptr_inst| {
-            return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array);
+        .ptr => |ptr_res| {
+            return arrayInitExprRlPtr(gz, scope, rl, node, ptr_res.inst, array_init.ast.elements, types.array);
         },
         .inferred_ptr => |ptr_inst| {
             if (types.array == .none) {
@@ -1513,7 +1518,7 @@ fn arrayInitExprRlPtrInner(
         });
         astgen.extra.items[extra_index] = refToIndex(elem_ptr).?;
         extra_index += 1;
-        _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init);
+        _ = try expr(gz, scope, .{ .ptr = .{ .inst = elem_ptr } }, elem_init);
     }
 
     const tag: Zir.Inst.Tag = if (gz.force_comptime)
@@ -1631,7 +1636,7 @@ fn structInitExpr(
             const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);
             return rvalue(gz, rl, result, node);
         },
-        .ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst),
+        .ptr => |ptr_res| return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_res.inst),
         .inferred_ptr => |ptr_inst| {
             if (struct_init.ast.type_expr == 0) {
                 // We treat this case differently so that we don't get a crash when
@@ -1739,7 +1744,7 @@ fn structInitExprRlPtrInner(
         });
         astgen.extra.items[extra_index] = refToIndex(field_ptr).?;
         extra_index += 1;
-        _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
+        _ = try expr(gz, scope, .{ .ptr = .{ .inst = field_ptr } }, field_init);
     }
 
     const tag: Zir.Inst.Tag = if (gz.force_comptime)
@@ -2998,7 +3003,7 @@ fn varDecl(
                     }
                 };
                 gz.rl_ty_inst = type_inst;
-                break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
+                break :a .{ .alloc = alloc, .result_loc = .{ .ptr = .{ .inst = alloc } } };
             } else a: {
                 const alloc = alloc: {
                     if (align_inst == .none) {
@@ -3098,7 +3103,10 @@ fn assign(gz: *GenZir, scope: *Scope, infix_node: Ast.Node.Index) InnerError!voi
         }
     }
     const lvalue = try lvalExpr(gz, scope, lhs);
-    _ = try expr(gz, scope, .{ .ptr = lvalue }, rhs);
+    _ = try expr(gz, scope, .{ .ptr = .{
+        .inst = lvalue,
+        .src_node = infix_node,
+    } }, rhs);
 }
 
 fn assignOp(
@@ -6729,7 +6737,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
     }
 
     const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node, true)) .{
-        .ptr = try gz.addNode(.ret_ptr, node),
+        .ptr = .{ .inst = try gz.addNode(.ret_ptr, node) },
     } else .{
         .ty = try gz.addNode(.ret_type, node),
     };
@@ -6748,7 +6756,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
         },
         .always => {
             // Value is always an error. Emit both error defers and regular defers.
-            const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
+            const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr.inst, node) else operand;
             try genDefers(gz, defer_outer, scope, .{ .both = err_code });
             try emitDbgStmt(gz, ret_line, ret_column);
             try gz.addRet(rl, operand, node);
@@ -6765,7 +6773,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
             }
 
             // Emit conditional branch for generating errdefers.
-            const result = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
+            const result = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr.inst, node) else operand;
             const is_non_err = try gz.addUnNode(.is_non_err, result, node);
             const condbr = try gz.addCondBr(.condbr, node);
 
@@ -7337,7 +7345,10 @@ fn as(
             const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
             return rvalue(gz, rl, result, node);
         },
-        .ptr, .inferred_ptr => |result_ptr| {
+        .ptr => |result_ptr| {
+            return asRlPtr(gz, scope, rl, node, result_ptr.inst, rhs, dest_type);
+        },
+        .inferred_ptr => |result_ptr| {
             return asRlPtr(gz, scope, rl, node, result_ptr, rhs, dest_type);
         },
         .block_ptr => |block_scope| {
@@ -9570,9 +9581,9 @@ fn rvalue(
                 }),
             }
         },
-        .ptr => |ptr_inst| {
-            _ = try gz.addPlNode(.store_node, src_node, Zir.Inst.Bin{
-                .lhs = ptr_inst,
+        .ptr => |ptr_res| {
+            _ = try gz.addPlNode(.store_node, ptr_res.src_node orelse src_node, Zir.Inst.Bin{
+                .lhs = ptr_res.inst,
                 .rhs = result,
             });
             return result;
@@ -10445,11 +10456,16 @@ const GenZir = struct {
                 gz.break_result_loc = parent_rl;
             },
 
-            .discard, .none, .ptr, .ref => {
+            .discard, .none, .ref => {
                 gz.rl_ty_inst = .none;
                 gz.break_result_loc = parent_rl;
             },
 
+            .ptr => |ptr_res| {
+                gz.rl_ty_inst = .none;
+                gz.break_result_loc = .{ .ptr = .{ .inst = ptr_res.inst } };
+            },
+
             .inferred_ptr => |ptr| {
                 gz.rl_ty_inst = .none;
                 gz.rl_ptr = ptr;
@@ -11610,7 +11626,7 @@ const GenZir = struct {
 
     fn addRet(gz: *GenZir, rl: ResultLoc, operand: Zir.Inst.Ref, node: Ast.Node.Index) !void {
         switch (rl) {
-            .ptr => |ret_ptr| _ = try gz.addUnNode(.ret_load, ret_ptr, node),
+            .ptr => |ptr_res| _ = try gz.addUnNode(.ret_load, ptr_res.inst, node),
             .ty, .ty_shift_operand => _ = try gz.addUnNode(.ret_node, operand, node),
             else => unreachable,
         }
src/Module.zig
@@ -2878,6 +2878,32 @@ pub const SrcLoc = struct {
                 };
                 return nodeToSpan(tree, full.ast.type_expr);
             },
+            .node_offset_store_ptr => |node_off| {
+                const tree = try src_loc.file_scope.getTree(gpa);
+                const node_tags = tree.nodes.items(.tag);
+                const node_datas = tree.nodes.items(.data);
+                const node = src_loc.declRelativeToNodeIndex(node_off);
+
+                switch (node_tags[node]) {
+                    .assign => {
+                        return nodeToSpan(tree, node_datas[node].lhs);
+                    },
+                    else => return nodeToSpan(tree, node),
+                }
+            },
+            .node_offset_store_operand => |node_off| {
+                const tree = try src_loc.file_scope.getTree(gpa);
+                const node_tags = tree.nodes.items(.tag);
+                const node_datas = tree.nodes.items(.data);
+                const node = src_loc.declRelativeToNodeIndex(node_off);
+
+                switch (node_tags[node]) {
+                    .assign => {
+                        return nodeToSpan(tree, node_datas[node].rhs);
+                    },
+                    else => return nodeToSpan(tree, node),
+                }
+            },
         }
     }
 
@@ -3213,6 +3239,12 @@ pub const LazySrcLoc = union(enum) {
     /// The source location points to the type of an array or struct initializer.
     /// The Decl is determined contextually.
     node_offset_init_ty: i32,
+    /// The source location points to the LHS of an assignment.
+    /// The Decl is determined contextually.
+    node_offset_store_ptr: i32,
+    /// The source location points to the RHS of an assignment.
+    /// The Decl is determined contextually.
+    node_offset_store_operand: i32,
 
     pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
 
@@ -3296,6 +3328,8 @@ pub const LazySrcLoc = union(enum) {
             .node_offset_container_tag,
             .node_offset_field_default,
             .node_offset_init_ty,
+            .node_offset_store_ptr,
+            .node_offset_store_operand,
             => .{
                 .file_scope = decl.getFileScope(),
                 .parent_decl_node = decl.src_node,
src/Sema.zig
@@ -4639,8 +4639,8 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
         try sema.addToInferredErrorSet(operand);
     }
 
-    const ptr_src = src; // TODO better soruce location
-    const operand_src = src; // TODO better soruce location
+    const ptr_src: LazySrcLoc = .{ .node_offset_store_ptr = inst_data.src_node };
+    const operand_src: LazySrcLoc = .{ .node_offset_store_operand = inst_data.src_node };
     const air_tag: Air.Inst.Tag = if (is_ret) .ret_ptr else .store;
     return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
 }
test/cases/compile_errors/any_typed_null_to_any_typed_optional.zig
@@ -7,5 +7,5 @@ pub export fn entry() void {
 // backend=stage2
 // target=native
 //
-// :3:21: error: expected type '?*anyopaque', found '?usize'
-// :3:21: note: optional type child 'usize' cannot cast into optional type child '*anyopaque'
+// :3:9: error: expected type '?*anyopaque', found '?usize'
+// :3:9: note: optional type child 'usize' cannot cast into optional type child '*anyopaque'
test/cases/compile_errors/assign_through_constant_pointer.zig
@@ -7,4 +7,4 @@ export fn f() void {
 // backend=stage2
 // target=native
 //
-// :3:13: error: cannot assign to constant
+// :3:7: error: cannot assign to constant
test/cases/compile_errors/assign_through_constant_slice.zig
@@ -7,4 +7,4 @@ export fn f() void {
 // backend=stage2
 // target=native
 //
-// :3:13: error: cannot assign to constant
+// :3:7: error: cannot assign to constant
test/cases/compile_errors/assign_to_constant_field.zig
@@ -10,4 +10,4 @@ export fn derp() void {
 // backend=stage2
 // target=native
 //
-// :6:15: error: cannot assign to constant
+// :6:6: error: cannot assign to constant
test/cases/compile_errors/assign_to_constant_variable.zig
@@ -75,7 +75,7 @@ export fn entry18() void {
 // backend=stage2
 // target=native
 //
-// :3:9: error: cannot assign to constant
+// :3:5: error: cannot assign to constant
 // :7:7: error: cannot assign to constant
 // :11:7: error: cannot assign to constant
 // :15:7: error: cannot assign to constant
test/cases/compile_errors/call_assigned_to_constant.zig
@@ -20,5 +20,5 @@ export fn entry1() void {
 // backend=stage2
 // target=native
 //
-// :12:14: error: cannot assign to constant
-// :16:14: error: cannot assign to constant
+// :12:5: error: cannot assign to constant
+// :16:5: error: cannot assign to constant
test/cases/compile_errors/comptime_store_in_comptime_switch_in_runtime_if.zig
@@ -21,5 +21,5 @@ pub export fn entry() void {
 // backend=stage2
 // target=native
 //
-// :13:27: error: store to comptime variable depends on runtime condition
+// :13:25: error: store to comptime variable depends on runtime condition
 // :11:16: note: runtime condition here
test/cases/compile_errors/global_var_struct_init_in_comptim_block.zig
@@ -0,0 +1,14 @@
+const Foo = struct {
+    x: i32,
+};
+var x: Foo = .{ .x = 2 };
+comptime {
+    x = .{ .x = 3 };
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :6:17: error: unable to evaluate comptime expression
+// :6:17: note: operation is runtime due to this operand
test/cases/compile_errors/non-const_expression_function_call_with_struct_return_value_outside_function.zig
@@ -14,6 +14,6 @@ export fn entry() usize { return @sizeOf(@TypeOf(a)); }
 // backend=stage2
 // target=native
 //
-// :6:26: error: unable to evaluate comptime expression
-// :6:26: note: operation is runtime due to this operand
+// :6:24: error: unable to evaluate comptime expression
+// :6:5: note: operation is runtime due to this operand
 // :4:17: note: called from here
test/cases/compile_errors/reassign_to_slice_parameter.zig
@@ -9,4 +9,4 @@ export fn entry() void {
 // backend=llvm
 // target=native
 //
-// :2:10: error: cannot assign to constant
+// :2:5: error: cannot assign to constant
test/cases/compile_errors/reference_to_const_data.zig
@@ -23,7 +23,7 @@ export fn qux() void {
 // backend=stage2
 // target=native
 //
-// :3:14: error: cannot assign to constant
-// :7:13: error: cannot assign to constant
-// :11:13: error: cannot assign to constant
-// :19:13: error: cannot assign to constant
+// :3:8: error: cannot assign to constant
+// :7:8: error: cannot assign to constant
+// :11:8: error: cannot assign to constant
+// :19:8: error: cannot assign to constant
test/cases/compile_errors/write_to_const_global_variable.zig
@@ -8,4 +8,4 @@ export fn entry() void { f(); }
 // backend=stage2
 // target=native
 //
-// :3:9: error: cannot assign to constant
+// :3:5: error: cannot assign to constant
test/cases/x86_64-linux/comptime_var.0.zig
@@ -8,5 +8,5 @@ pub fn main() void {
 // output_mode=Exe
 // target=x86_64-linux
 //
-// :4:21: error: store to comptime variable depends on runtime condition
+// :4:19: error: store to comptime variable depends on runtime condition
 // :4:11: note: runtime condition here
test/cases/x86_64-linux/comptime_var.1.zig
@@ -9,5 +9,5 @@ pub fn main() void {
 
 // error
 //
-// :6:21: error: store to comptime variable depends on runtime condition
+// :6:19: error: store to comptime variable depends on runtime condition
 // :4:13: note: runtime condition here
test/cases/x86_64-macos/comptime_var.0.zig
@@ -8,5 +8,5 @@ pub fn main() void {
 // output_mode=Exe
 // target=x86_64-macos
 //
-// :4:21: error: store to comptime variable depends on runtime condition
+// :4:19: error: store to comptime variable depends on runtime condition
 // :4:11: note: runtime condition here
test/cases/x86_64-macos/comptime_var.1.zig
@@ -9,5 +9,5 @@ pub fn main() void {
 
 // error
 //
-// :6:21: error: store to comptime variable depends on runtime condition
+// :6:19: error: store to comptime variable depends on runtime condition
 // :4:13: note: runtime condition here