authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-18 22:42:35+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-18 22:42:35+03:00
loge4aefc6d0f9b08a98f566cb8280a6195c08f7a82
treef78b06d39025fd8bc1e40647023e9012eb80987b
parent2b45e23477605e15fecec3566b3dc90b71e2f7a7
signature Commit is signed but in an unrecognized format.

stage2: split ref from lvalue and add compile error for invalid assignments


3 files changed, 153 insertions(+), 23 deletions(-)

src-self-hosted/astgen.zig+145-15
...@@ -20,6 +20,8 @@ pub const ResultLoc = union(enum) {...@@ -20,6 +20,8 @@ pub const ResultLoc = union(enum) {
20 /// The expression must generate a pointer rather than a value. For example, the left hand side20 /// The expression must generate a pointer rather than a value. For example, the left hand side
21 /// of an assignment uses an "LValue" result location.21 /// of an assignment uses an "LValue" result location.
22 lvalue,22 lvalue,
23 /// The expression must generate a pointer
24 ref,
23 /// The expression will be type coerced into this type, but it will be evaluated as an rvalue.25 /// The expression will be type coerced into this type, but it will be evaluated as an rvalue.
24 ty: *zir.Inst,26 ty: *zir.Inst,
25 /// The expression must store its result into this typed pointer.27 /// The expression must store its result into this typed pointer.
...@@ -46,6 +48,132 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z...@@ -46,6 +48,132 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z
4648
47/// Turn Zig AST into untyped ZIR istructions.49/// Turn Zig AST into untyped ZIR istructions.
48pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst {50pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst {
51 if (rl == .lvalue) {
52 switch (node.tag) {
53 .Root => unreachable,
54 .Use => unreachable,
55 .TestDecl => unreachable,
56 .DocComment => unreachable,
57 .VarDecl => unreachable,
58 .SwitchCase => unreachable,
59 .SwitchElse => unreachable,
60 .Else => unreachable,
61 .Payload => unreachable,
62 .PointerPayload => unreachable,
63 .PointerIndexPayload => unreachable,
64 .ErrorTag => unreachable,
65 .FieldInitializer => unreachable,
66 .ContainerField => unreachable,
67
68 .Assign,
69 .AssignBitAnd,
70 .AssignBitOr,
71 .AssignBitShiftLeft,
72 .AssignBitShiftRight,
73 .AssignBitXor,
74 .AssignDiv,
75 .AssignSub,
76 .AssignSubWrap,
77 .AssignMod,
78 .AssignAdd,
79 .AssignAddWrap,
80 .AssignMul,
81 .AssignMulWrap,
82 .Add,
83 .AddWrap,
84 .Sub,
85 .SubWrap,
86 .Mul,
87 .MulWrap,
88 .Div,
89 .Mod,
90 .BitAnd,
91 .BitOr,
92 .BitShiftLeft,
93 .BitShiftRight,
94 .BitXor,
95 .BangEqual,
96 .EqualEqual,
97 .GreaterThan,
98 .GreaterOrEqual,
99 .LessThan,
100 .LessOrEqual,
101 .ArrayCat,
102 .ArrayMult,
103 .BoolAnd,
104 .BoolOr,
105 .Asm,
106 .StringLiteral,
107 .IntegerLiteral,
108 .Call,
109 .Unreachable,
110 .Return,
111 .If,
112 .While,
113 .BoolNot,
114 .AddressOf,
115 .FloatLiteral,
116 .UndefinedLiteral,
117 .BoolLiteral,
118 .NullLiteral,
119 .OptionalType,
120 .Block,
121 .LabeledBlock,
122 .Break,
123 .PtrType,
124 .GroupedExpression,
125 .ArrayType,
126 .ArrayTypeSentinel,
127 .EnumLiteral,
128 .MultilineStringLiteral,
129 .CharLiteral,
130 .Defer,
131 .Catch,
132 .ErrorUnion,
133 .MergeErrorSets,
134 .Range,
135 .OrElse,
136 .Await,
137 .BitNot,
138 .Negation,
139 .NegationWrap,
140 .Resume,
141 .Try,
142 .SliceType,
143 .Slice,
144 .ArrayInitializer,
145 .ArrayInitializerDot,
146 .StructInitializer,
147 .StructInitializerDot,
148 .Switch,
149 .For,
150 .Suspend,
151 .Continue,
152 .AnyType,
153 .ErrorType,
154 .FnProto,
155 .AnyFrameType,
156 .ErrorSetDecl,
157 .ContainerDecl,
158 .Comptime,
159 .Nosuspend,
160 => return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}),
161
162 // @field can be assigned to
163 .BuiltinCall => {
164 const call = node.castTag(.BuiltinCall).?;
165 const tree = scope.tree();
166 const builtin_name = tree.tokenSlice(call.builtin_token);
167
168 if (!mem.eql(u8, builtin_name, "@field")) {
169 return mod.failNode(scope, node, "invalid left-hand side to assignment", .{});
170 }
171 },
172
173 // can be assigned to
174 .UnwrapOptional, .Deref, .Period, .ArrayAccess, .Identifier => {},
175 }
176 }
49 switch (node.tag) {177 switch (node.tag) {
50 .Root => unreachable, // Top-level declaration.178 .Root => unreachable, // Top-level declaration.
51 .Use => unreachable, // Top-level declaration.179 .Use => unreachable, // Top-level declaration.
...@@ -60,6 +188,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -60,6 +188,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
60 .PointerIndexPayload => unreachable, // Handled explicitly.188 .PointerIndexPayload => unreachable, // Handled explicitly.
61 .ErrorTag => unreachable, // Handled explicitly.189 .ErrorTag => unreachable, // Handled explicitly.
62 .FieldInitializer => unreachable, // Handled explicitly.190 .FieldInitializer => unreachable, // Handled explicitly.
191 .ContainerField => unreachable, // Handled explicitly.
63192
64 .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)),193 .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)),
65 .AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)),194 .AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)),
...@@ -165,7 +294,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -165,7 +294,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
165 .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),294 .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),
166 .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}),295 .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}),
167 .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),296 .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),
168 .ContainerField => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerField", .{}),
169 }297 }
170}298}
171299
...@@ -188,7 +316,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr...@@ -188,7 +316,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr
188 // proper type inference requires peer type resolution on the block's316 // proper type inference requires peer type resolution on the block's
189 // break operand expressions.317 // break operand expressions.
190 const branch_rl: ResultLoc = switch (label.result_loc) {318 const branch_rl: ResultLoc = switch (label.result_loc) {
191 .discard, .none, .ty, .ptr, .lvalue => label.result_loc,319 .discard, .none, .ty, .ptr, .lvalue, .ref => label.result_loc,
192 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst },320 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst },
193 };321 };
194 const operand = try expr(mod, parent_scope, branch_rl, rhs);322 const operand = try expr(mod, parent_scope, branch_rl, rhs);
...@@ -427,7 +555,7 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr...@@ -427,7 +555,7 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr
427}555}
428556
429fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {557fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
430 return expr(mod, scope, .lvalue, node.rhs);558 return expr(mod, scope, .ref, node.rhs);
431}559}
432560
433fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {561fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
...@@ -541,9 +669,9 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si...@@ -541,9 +669,9 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si
541 const tree = scope.tree();669 const tree = scope.tree();
542 const src = tree.token_locs[node.rtoken].start;670 const src = tree.token_locs[node.rtoken].start;
543671
544 const operand = try expr(mod, scope, .lvalue, node.lhs);672 const operand = try expr(mod, scope, .ref, node.lhs);
545 const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand);673 const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand);
546 if (rl == .lvalue) return unwrapped_ptr;674 if (rl == .lvalue or rl == .ref) return unwrapped_ptr;
547675
548 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));676 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
549}677}
...@@ -718,13 +846,13 @@ const CondKind = union(enum) {...@@ -718,13 +846,13 @@ const CondKind = union(enum) {
718 return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node);846 return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node);
719 },847 },
720 .optional => {848 .optional => {
721 const cond_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);849 const cond_ptr = try expr(mod, &block_scope.base, .ref, cond_node);
722 self.* = .{ .optional = cond_ptr };850 self.* = .{ .optional = cond_ptr };
723 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);851 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);
724 return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result);852 return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result);
725 },853 },
726 .err_union => {854 .err_union => {
727 const err_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);855 const err_ptr = try expr(mod, &block_scope.base, .ref, cond_node);
728 self.* = .{ .err_union = err_ptr };856 self.* = .{ .err_union = err_ptr };
729 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr);857 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr);
730 return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result);858 return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result);
...@@ -819,7 +947,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -819,7 +947,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
819 // proper type inference requires peer type resolution on the if's947 // proper type inference requires peer type resolution on the if's
820 // branches.948 // branches.
821 const branch_rl: ResultLoc = switch (rl) {949 const branch_rl: ResultLoc = switch (rl) {
822 .discard, .none, .ty, .ptr, .lvalue => rl,950 .discard, .none, .ty, .ptr, .lvalue, .ref => rl,
823 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },951 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
824 };952 };
825953
...@@ -949,7 +1077,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -949,7 +1077,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
949 // proper type inference requires peer type resolution on the while's1077 // proper type inference requires peer type resolution on the while's
950 // branches.1078 // branches.
951 const branch_rl: ResultLoc = switch (rl) {1079 const branch_rl: ResultLoc = switch (rl) {
952 .discard, .none, .ty, .ptr, .lvalue => rl,1080 .discard, .none, .ty, .ptr, .lvalue, .ref => rl,
953 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },1081 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },
954 };1082 };
9551083
...@@ -1080,7 +1208,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo...@@ -1080,7 +1208,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
1080 .local_ptr => {1208 .local_ptr => {
1081 const local_ptr = s.cast(Scope.LocalPtr).?;1209 const local_ptr = s.cast(Scope.LocalPtr).?;
1082 if (mem.eql(u8, local_ptr.name, ident_name)) {1210 if (mem.eql(u8, local_ptr.name, ident_name)) {
1083 if (rl == .lvalue) {1211 if (rl == .lvalue or rl == .ref) {
1084 return local_ptr.ptr;1212 return local_ptr.ptr;
1085 } else {1213 } else {
1086 const result = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr);1214 const result = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr);
...@@ -1344,7 +1472,8 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I...@@ -1344,7 +1472,8 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I
1344 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);1472 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
1345 return result;1473 return result;
1346 },1474 },
1347 .lvalue => {1475 .lvalue => unreachable,
1476 .ref => {
1348 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);1477 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
1349 return addZIRUnOp(mod, scope, result.src, .ref, result);1478 return addZIRUnOp(mod, scope, result.src, .ref, result);
1350 },1479 },
...@@ -1395,9 +1524,10 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa...@@ -1395,9 +1524,10 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
1395 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);1524 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
1396 return result;1525 return result;
1397 },1526 },
1398 .lvalue => {1527 .lvalue => unreachable,
1399 const operand = try expr(mod, scope, .lvalue, params[1]);1528 .ref => {
1400 const result = try addZIRBinOp(mod, scope, src, .bitcast_lvalue, dest_type, operand);1529 const operand = try expr(mod, scope, .ref, params[1]);
1530 const result = try addZIRBinOp(mod, scope, src, .bitcast_ref, dest_type, operand);
1401 return result;1531 return result;
1402 },1532 },
1403 .ty => |result_ty| {1533 .ty => |result_ty| {
...@@ -1662,7 +1792,7 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr...@@ -1662,7 +1792,7 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr
1662 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);1792 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
1663 return result;1793 return result;
1664 },1794 },
1665 .lvalue => {1795 .lvalue, .ref => {
1666 // We need a pointer but we have a value.1796 // We need a pointer but we have a value.
1667 return addZIRUnOp(mod, scope, result.src, .ref, result);1797 return addZIRUnOp(mod, scope, result.src, .ref, result);
1668 },1798 },
src-self-hosted/zir.zig+5-5
...@@ -62,11 +62,11 @@ pub const Inst = struct {...@@ -62,11 +62,11 @@ pub const Inst = struct {
62 bitand,62 bitand,
63 /// TODO delete this instruction, it has no purpose.63 /// TODO delete this instruction, it has no purpose.
64 bitcast,64 bitcast,
65 /// An arbitrary typed pointer, which is to be used as an L-Value, is pointer-casted65 /// An arbitrary typed pointer is pointer-casted to a new Pointer.
66 /// to a new L-Value. The destination type is given by LHS. The cast is to be evaluated66 /// The destination type is given by LHS. The cast is to be evaluated
67 /// as if it were a bit-cast operation from the operand pointer element type to the67 /// as if it were a bit-cast operation from the operand pointer element type to the
68 /// provided destination type.68 /// provided destination type.
69 bitcast_lvalue,69 bitcast_ref,
70 /// A typed result location pointer is bitcasted to a new result location pointer.70 /// A typed result location pointer is bitcasted to a new result location pointer.
71 /// The new result location pointer has an inferred type.71 /// The new result location pointer has an inferred type.
72 bitcast_result_ptr,72 bitcast_result_ptr,
...@@ -258,7 +258,7 @@ pub const Inst = struct {...@@ -258,7 +258,7 @@ pub const Inst = struct {
258 .ensure_result_non_error,258 .ensure_result_non_error,
259 .bitcast_result_ptr,259 .bitcast_result_ptr,
260 .ref,260 .ref,
261 .bitcast_lvalue,261 .bitcast_ref,
262 .typeof,262 .typeof,
263 .single_const_ptr_type,263 .single_const_ptr_type,
264 .single_mut_ptr_type,264 .single_mut_ptr_type,
...@@ -349,7 +349,7 @@ pub const Inst = struct {...@@ -349,7 +349,7 @@ pub const Inst = struct {
349 .@"asm",349 .@"asm",
350 .bitand,350 .bitand,
351 .bitcast,351 .bitcast,
352 .bitcast_lvalue,352 .bitcast_ref,
353 .bitcast_result_ptr,353 .bitcast_result_ptr,
354 .bitor,354 .bitor,
355 .block,355 .block,
src-self-hosted/zir_sema.zig+3-3
...@@ -29,7 +29,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -29,7 +29,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
29 .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?),29 .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?),
30 .alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?),30 .alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?),
31 .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),31 .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),
32 .bitcast_lvalue => return analyzeInstBitCastLValue(mod, scope, old_inst.castTag(.bitcast_lvalue).?),32 .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),
33 .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),33 .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),
34 .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?),34 .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?),
35 .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?),35 .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?),
...@@ -299,8 +299,8 @@ fn analyzeInstCoerceResultBlockPtr(...@@ -299,8 +299,8 @@ fn analyzeInstCoerceResultBlockPtr(
299 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});299 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});
300}300}
301301
302fn analyzeInstBitCastLValue(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {302fn analyzeInstBitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
303 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastLValue", .{});303 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastRef", .{});
304}304}
305305
306fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {306fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {