| ... | @@ -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 side | 20 | /// 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 |
| 46 | | 48 | |
| 47 | /// Turn Zig AST into untyped ZIR istructions. | 49 | /// Turn Zig AST into untyped ZIR istructions. |
| 48 | pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { | 50 | pub 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. |
| 63 | | 192 | |
| 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 | } |
| 171 | | 299 | |
| ... | @@ -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's | 316 | // 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 | } |
| 428 | | 556 | |
| 429 | fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { | 557 | fn 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 | } |
| 432 | | 560 | |
| 433 | fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { | 561 | fn 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; |
| 543 | | 671 | |
| 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; |
| 547 | | 675 | |
| 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's | 947 | // 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 | }; |
| 825 | | 953 | |
| ... | @@ -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's | 1077 | // 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 | }; |
| 955 | | 1083 | |
| ... | @@ -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 | }, |