Skip to content

Commit 48d14b8

Browse files
committed
AstGen: restore local variable is never mutated error
1 parent fa721a0 commit 48d14b8

File tree

1 file changed

+49
-28
lines changed

1 file changed

+49
-28
lines changed

lib/std/zig/AstGen.zig

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ const ResultInfo = struct {
285285
/// The expression must generate a pointer rather than a value. For example, the left hand side
286286
/// of an assignment uses this kind of result location.
287287
ref,
288+
/// Same as `ty` but will not mark variables as being used as an lvalue.
289+
pseudo_ref,
288290
/// The expression must generate a pointer rather than a value, and the pointer will be coerced
289291
/// by other code to this type, which is guaranteed by earlier instructions to be a pointer type.
290292
ref_coerced_ty: Zir.Inst.Ref,
@@ -320,7 +322,7 @@ const ResultInfo = struct {
320322
/// the given node.
321323
fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index) !?Zir.Inst.Ref {
322324
return switch (rl) {
323-
.discard, .none, .ref, .inferred_ptr, .destructure => null,
325+
.discard, .none, .ref, .pseudo_ref, .inferred_ptr, .destructure => null,
324326
.ty, .coerced_ty => |ty_ref| ty_ref,
325327
.ref_coerced_ty => |ptr_ty| try gz.addUnNode(.elem_type, ptr_ty, node),
326328
.ptr => |ptr| {
@@ -970,7 +972,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
970972
const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs);
971973
_ = try gz.addUnNode(.validate_deref, lhs, node);
972974
switch (ri.rl) {
973-
.ref, .ref_coerced_ty => return lhs,
975+
.ref, .pseudo_ref, .ref_coerced_ty => return lhs,
974976
else => {
975977
const result = try gz.addUnNode(.load, lhs, node);
976978
return rvalue(gz, ri, result, node);
@@ -991,7 +993,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
991993
return rvalue(gz, ri, result, node);
992994
},
993995
.unwrap_optional => switch (ri.rl) {
994-
.ref, .ref_coerced_ty => {
996+
.ref, .pseudo_ref, .ref_coerced_ty => {
995997
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
996998

997999
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
@@ -1053,7 +1055,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
10531055
return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch");
10541056
}
10551057
switch (ri.rl) {
1056-
.ref, .ref_coerced_ty => return orelseCatchExpr(
1058+
.ref, .pseudo_ref, .ref_coerced_ty => return orelseCatchExpr(
10571059
gz,
10581060
scope,
10591061
ri,
@@ -1080,7 +1082,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
10801082
}
10811083
},
10821084
.@"orelse" => switch (ri.rl) {
1083-
.ref, .ref_coerced_ty => return orelseCatchExpr(
1085+
.ref, .pseudo_ref, .ref_coerced_ty => return orelseCatchExpr(
10841086
gz,
10851087
scope,
10861088
ri,
@@ -1523,7 +1525,7 @@ fn arrayInitExpr(
15231525
}
15241526
return Zir.Inst.Ref.void_value;
15251527
},
1526-
.ref => {
1528+
.ref, .pseudo_ref => {
15271529
const result = try arrayInitExprAnon(gz, scope, node, array_init.ast.elements);
15281530
return gz.addUnTok(.ref, result, tree.firstToken(node));
15291531
},
@@ -1697,7 +1699,7 @@ fn structInitExpr(
16971699
const val = try gz.addUnNode(.struct_init_empty_result, ty_inst, node);
16981700
return rvalue(gz, ri, val, node);
16991701
},
1700-
.none, .ref, .inferred_ptr => {
1702+
.none, .ref, .pseudo_ref, .inferred_ptr => {
17011703
return rvalue(gz, ri, .empty_struct, node);
17021704
},
17031705
.destructure => |destructure| {
@@ -1830,7 +1832,7 @@ fn structInitExpr(
18301832
}
18311833
return .void_value;
18321834
},
1833-
.ref => {
1835+
.ref, .pseudo_ref => {
18341836
const result = try structInitExprAnon(gz, scope, node, struct_init);
18351837
return gz.addUnTok(.ref, result, tree.firstToken(node));
18361838
},
@@ -5912,21 +5914,25 @@ fn tryExpr(
59125914
const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
59135915

59145916
const operand_ri: ResultInfo = switch (ri.rl) {
5917+
.pseudo_ref => .{ .rl = .pseudo_ref, .ctx = .error_handling_expr },
59155918
.ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = .error_handling_expr },
59165919
else => .{ .rl = .none, .ctx = .error_handling_expr },
59175920
};
59185921
// This could be a pointer or value depending on the `ri` parameter.
59195922
const operand = try reachableExpr(parent_gz, scope, operand_ri, operand_node, node);
5920-
const block_tag: Zir.Inst.Tag = if (operand_ri.rl == .ref) .try_ptr else .@"try";
5923+
const block_tag: Zir.Inst.Tag = switch (ri.rl) {
5924+
.ref, .pseudo_ref, .ref_coerced_ty => .try_ptr,
5925+
else => .@"try",
5926+
};
59215927
const try_inst = try parent_gz.makeBlockInst(block_tag, node);
59225928
try parent_gz.instructions.append(astgen.gpa, try_inst);
59235929

59245930
var else_scope = parent_gz.makeSubBlock(scope);
59255931
defer else_scope.unstack();
59265932

5927-
const err_tag = switch (ri.rl) {
5928-
.ref, .ref_coerced_ty => Zir.Inst.Tag.err_union_code_ptr,
5929-
else => Zir.Inst.Tag.err_union_code,
5933+
const err_tag: Zir.Inst.Tag = switch (ri.rl) {
5934+
.ref, .pseudo_ref, .ref_coerced_ty => .err_union_code_ptr,
5935+
else => .err_union_code,
59305936
};
59315937
const err_code = try else_scope.addUnNode(err_tag, operand, node);
59325938
try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
@@ -5936,7 +5942,7 @@ fn tryExpr(
59365942
try else_scope.setTryBody(try_inst, operand);
59375943
const result = try_inst.toRef();
59385944
switch (ri.rl) {
5939-
.ref, .ref_coerced_ty => return result,
5945+
.ref, .pseudo_ref, .ref_coerced_ty => return result,
59405946
else => return rvalue(parent_gz, ri, result, node),
59415947
}
59425948
}
@@ -5977,6 +5983,7 @@ fn orelseCatchExpr(
59775983
defer block_scope.unstack();
59785984

59795985
const operand_ri: ResultInfo = switch (block_scope.break_result_info.rl) {
5986+
.pseudo_ref => .{ .rl = .pseudo_ref, .ctx = if (do_err_trace) .error_handling_expr else .none },
59805987
.ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = if (do_err_trace) .error_handling_expr else .none },
59815988
else => .{ .rl = .none, .ctx = if (do_err_trace) .error_handling_expr else .none },
59825989
};
@@ -5999,7 +6006,7 @@ fn orelseCatchExpr(
59996006
// This could be a pointer or value depending on `unwrap_op`.
60006007
const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);
60016008
const then_result = switch (ri.rl) {
6002-
.ref, .ref_coerced_ty => unwrapped_payload,
6009+
.ref, .pseudo_ref, .ref_coerced_ty => unwrapped_payload,
60036010
else => try rvalue(&then_scope, block_scope.break_result_info, unwrapped_payload, node),
60046011
};
60056012
_ = try then_scope.addBreakWithSrcNode(.@"break", block, then_result, node);
@@ -6071,8 +6078,9 @@ fn fieldAccess(
60716078
) InnerError!Zir.Inst.Ref {
60726079
switch (ri.rl) {
60736080
.ref, .ref_coerced_ty => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node),
6081+
.pseudo_ref => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .pseudo_ref }, node),
60746082
else => {
6075-
const ptr = try addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node);
6083+
const ptr = try addFieldAccess(.field_ptr, gz, scope, .{ .rl = .pseudo_ref }, node);
60766084
const result = try gz.addUnNode(.load, ptr, node);
60776085
return rvalue(gz, ri, result, node);
60786086
},
@@ -6125,8 +6133,18 @@ fn arrayAccess(
61256133

61266134
return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs });
61276135
},
6136+
.pseudo_ref => {
6137+
const lhs = try expr(gz, scope, .{ .rl = .pseudo_ref }, node_datas[node].lhs);
6138+
6139+
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
6140+
6141+
const rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[node].rhs);
6142+
try emitDbgStmt(gz, cursor);
6143+
6144+
return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs });
6145+
},
61286146
else => {
6129-
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
6147+
const lhs = try expr(gz, scope, .{ .rl = .pseudo_ref }, node_datas[node].lhs);
61306148

61316149
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
61326150

@@ -7204,7 +7222,7 @@ fn switchExprErrUnion(
72047222
switch (node_ty) {
72057223
.@"catch" => {
72067224
const case_result = switch (ri.rl) {
7207-
.ref, .ref_coerced_ty => unwrapped_payload,
7225+
.ref, .pseudo_ref, .ref_coerced_ty => unwrapped_payload,
72087226
else => try rvalue(
72097227
&case_scope,
72107228
block_scope.break_result_info,
@@ -8308,6 +8326,7 @@ fn localVarRef(
83088326
) else local_ptr.ptr;
83098327

83108328
switch (ri.rl) {
8329+
.pseudo_ref => return ptr_inst,
83118330
.ref, .ref_coerced_ty => {
83128331
local_ptr.used_as_lvalue = true;
83138332
return ptr_inst;
@@ -8352,7 +8371,7 @@ fn localVarRef(
83528371

83538372
if (found_namespaces_out > 0 and found_needs_tunnel) {
83548373
switch (ri.rl) {
8355-
.ref, .ref_coerced_ty => return tunnelThroughClosure(
8374+
.ref, .pseudo_ref, .ref_coerced_ty => return tunnelThroughClosure(
83568375
gz,
83578376
ident,
83588377
found_namespaces_out,
@@ -8373,7 +8392,7 @@ fn localVarRef(
83738392
}
83748393

83758394
switch (ri.rl) {
8376-
.ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
8395+
.ref, .pseudo_ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
83778396
else => {
83788397
const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
83798398
return rvalueNoCoercePreRef(gz, ri, result, ident);
@@ -9106,18 +9125,20 @@ fn builtinCall(
91069125
const result = try gz.addExtendedMultiOpPayloadIndex(.compile_log, payload_index, params.len);
91079126
return rvalue(gz, ri, result, node);
91089127
},
9109-
.field => {
9110-
if (ri.rl == .ref or ri.rl == .ref_coerced_ty) {
9128+
.field => switch (ri.rl) {
9129+
.ref, .pseudo_ref, .ref_coerced_ty => {
91119130
return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
91129131
.lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]),
91139132
.field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]),
91149133
});
9115-
}
9116-
const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{
9117-
.lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
9118-
.field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]),
9119-
});
9120-
return rvalue(gz, ri, result, node);
9134+
},
9135+
else => {
9136+
const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{
9137+
.lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
9138+
.field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]),
9139+
});
9140+
return rvalue(gz, ri, result, node);
9141+
},
91219142
},
91229143

91239144
// zig fmt: off
@@ -10984,7 +11005,7 @@ fn rvalueInner(
1098411005
_ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
1098511006
return .void_value;
1098611007
},
10987-
.ref, .ref_coerced_ty => {
11008+
.ref, .pseudo_ref, .ref_coerced_ty => {
1098811009
const coerced_result = if (allow_coerce_pre_ref and ri.rl == .ref_coerced_ty) res: {
1098911010
const ptr_ty = ri.rl.ref_coerced_ty;
1099011011
break :res try gz.addPlNode(.coerce_ptr_elem_ty, src_node, Zir.Inst.Bin{

0 commit comments

Comments
 (0)