| ... | ... | @@ -18,9 +18,7 @@ pub const ResultLoc = union(enum) { |
| 18 | 18 | /// The expression has an inferred type, and it will be evaluated as an rvalue. |
| 19 | 19 | none, |
| 20 | 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. |
| 22 | | lvalue, |
| 23 | | /// The expression must generate a pointer |
| 21 | /// of an assignment uses this kind of result location. |
| 24 | 22 | ref, |
| 25 | 23 | /// The expression will be type coerced into this type, but it will be evaluated as an rvalue. |
| 26 | 24 | ty: *zir.Inst, |
| ... | ... | @@ -46,134 +44,136 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z |
| 46 | 44 | return expr(mod, scope, type_rl, type_node); |
| 47 | 45 | } |
| 48 | 46 | |
| 49 | | /// Turn Zig AST into untyped ZIR istructions. |
| 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 | | }, |
| 47 | fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { |
| 48 | switch (node.tag) { |
| 49 | .Root => unreachable, |
| 50 | .Use => unreachable, |
| 51 | .TestDecl => unreachable, |
| 52 | .DocComment => unreachable, |
| 53 | .VarDecl => unreachable, |
| 54 | .SwitchCase => unreachable, |
| 55 | .SwitchElse => unreachable, |
| 56 | .Else => unreachable, |
| 57 | .Payload => unreachable, |
| 58 | .PointerPayload => unreachable, |
| 59 | .PointerIndexPayload => unreachable, |
| 60 | .ErrorTag => unreachable, |
| 61 | .FieldInitializer => unreachable, |
| 62 | .ContainerField => unreachable, |
| 63 | |
| 64 | .Assign, |
| 65 | .AssignBitAnd, |
| 66 | .AssignBitOr, |
| 67 | .AssignBitShiftLeft, |
| 68 | .AssignBitShiftRight, |
| 69 | .AssignBitXor, |
| 70 | .AssignDiv, |
| 71 | .AssignSub, |
| 72 | .AssignSubWrap, |
| 73 | .AssignMod, |
| 74 | .AssignAdd, |
| 75 | .AssignAddWrap, |
| 76 | .AssignMul, |
| 77 | .AssignMulWrap, |
| 78 | .Add, |
| 79 | .AddWrap, |
| 80 | .Sub, |
| 81 | .SubWrap, |
| 82 | .Mul, |
| 83 | .MulWrap, |
| 84 | .Div, |
| 85 | .Mod, |
| 86 | .BitAnd, |
| 87 | .BitOr, |
| 88 | .BitShiftLeft, |
| 89 | .BitShiftRight, |
| 90 | .BitXor, |
| 91 | .BangEqual, |
| 92 | .EqualEqual, |
| 93 | .GreaterThan, |
| 94 | .GreaterOrEqual, |
| 95 | .LessThan, |
| 96 | .LessOrEqual, |
| 97 | .ArrayCat, |
| 98 | .ArrayMult, |
| 99 | .BoolAnd, |
| 100 | .BoolOr, |
| 101 | .Asm, |
| 102 | .StringLiteral, |
| 103 | .IntegerLiteral, |
| 104 | .Call, |
| 105 | .Unreachable, |
| 106 | .Return, |
| 107 | .If, |
| 108 | .While, |
| 109 | .BoolNot, |
| 110 | .AddressOf, |
| 111 | .FloatLiteral, |
| 112 | .UndefinedLiteral, |
| 113 | .BoolLiteral, |
| 114 | .NullLiteral, |
| 115 | .OptionalType, |
| 116 | .Block, |
| 117 | .LabeledBlock, |
| 118 | .Break, |
| 119 | .PtrType, |
| 120 | .GroupedExpression, |
| 121 | .ArrayType, |
| 122 | .ArrayTypeSentinel, |
| 123 | .EnumLiteral, |
| 124 | .MultilineStringLiteral, |
| 125 | .CharLiteral, |
| 126 | .Defer, |
| 127 | .Catch, |
| 128 | .ErrorUnion, |
| 129 | .MergeErrorSets, |
| 130 | .Range, |
| 131 | .OrElse, |
| 132 | .Await, |
| 133 | .BitNot, |
| 134 | .Negation, |
| 135 | .NegationWrap, |
| 136 | .Resume, |
| 137 | .Try, |
| 138 | .SliceType, |
| 139 | .Slice, |
| 140 | .ArrayInitializer, |
| 141 | .ArrayInitializerDot, |
| 142 | .StructInitializer, |
| 143 | .StructInitializerDot, |
| 144 | .Switch, |
| 145 | .For, |
| 146 | .Suspend, |
| 147 | .Continue, |
| 148 | .AnyType, |
| 149 | .ErrorType, |
| 150 | .FnProto, |
| 151 | .AnyFrameType, |
| 152 | .ErrorSetDecl, |
| 153 | .ContainerDecl, |
| 154 | .Comptime, |
| 155 | .Nosuspend, |
| 156 | => return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}), |
| 157 | |
| 158 | // @field can be assigned to |
| 159 | .BuiltinCall => { |
| 160 | const call = node.castTag(.BuiltinCall).?; |
| 161 | const tree = scope.tree(); |
| 162 | const builtin_name = tree.tokenSlice(call.builtin_token); |
| 163 | |
| 164 | if (!mem.eql(u8, builtin_name, "@field")) { |
| 165 | return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}); |
| 166 | } |
| 167 | }, |
| 172 | 168 | |
| 173 | | // can be assigned to |
| 174 | | .UnwrapOptional, .Deref, .Period, .ArrayAccess, .Identifier => {}, |
| 175 | | } |
| 169 | // can be assigned to |
| 170 | .UnwrapOptional, .Deref, .Period, .ArrayAccess, .Identifier => {}, |
| 176 | 171 | } |
| 172 | return expr(mod, scope, .ref, node); |
| 173 | } |
| 174 | |
| 175 | /// Turn Zig AST into untyped ZIR istructions. |
| 176 | pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { |
| 177 | 177 | switch (node.tag) { |
| 178 | 178 | .Root => unreachable, // Top-level declaration. |
| 179 | 179 | .Use => unreachable, // Top-level declaration. |
| ... | ... | @@ -317,7 +317,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr |
| 317 | 317 | // proper type inference requires peer type resolution on the block's |
| 318 | 318 | // break operand expressions. |
| 319 | 319 | const branch_rl: ResultLoc = switch (label.result_loc) { |
| 320 | | .discard, .none, .ty, .ptr, .lvalue, .ref => label.result_loc, |
| 320 | .discard, .none, .ty, .ptr, .ref => label.result_loc, |
| 321 | 321 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst }, |
| 322 | 322 | }; |
| 323 | 323 | const operand = try expr(mod, parent_scope, branch_rl, rhs); |
| ... | ... | @@ -524,7 +524,7 @@ fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) Inne |
| 524 | 524 | return; |
| 525 | 525 | } |
| 526 | 526 | } |
| 527 | | const lvalue = try expr(mod, scope, .lvalue, infix_node.lhs); |
| 527 | const lvalue = try lvalExpr(mod, scope, infix_node.lhs); |
| 528 | 528 | _ = try expr(mod, scope, .{ .ptr = lvalue }, infix_node.rhs); |
| 529 | 529 | } |
| 530 | 530 | |
| ... | ... | @@ -534,7 +534,7 @@ fn assignOp( |
| 534 | 534 | infix_node: *ast.Node.SimpleInfixOp, |
| 535 | 535 | op_inst_tag: zir.Inst.Tag, |
| 536 | 536 | ) InnerError!void { |
| 537 | | const lhs_ptr = try expr(mod, scope, .lvalue, infix_node.lhs); |
| 537 | const lhs_ptr = try lvalExpr(mod, scope, infix_node.lhs); |
| 538 | 538 | const lhs = try addZIRUnOp(mod, scope, lhs_ptr.src, .deref, lhs_ptr); |
| 539 | 539 | const lhs_type = try addZIRUnOp(mod, scope, lhs_ptr.src, .typeof, lhs); |
| 540 | 540 | const rhs = try expr(mod, scope, .{ .ty = lhs_type }, infix_node.rhs); |
| ... | ... | @@ -794,7 +794,7 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix |
| 794 | 794 | const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?); |
| 795 | 795 | |
| 796 | 796 | const pointer = try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{}); |
| 797 | | if (rl == .ref or rl == .lvalue) return pointer; |
| 797 | if (rl == .ref) return pointer; |
| 798 | 798 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, pointer)); |
| 799 | 799 | } |
| 800 | 800 | |
| ... | ... | @@ -1020,7 +1020,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1020 | 1020 | // proper type inference requires peer type resolution on the if's |
| 1021 | 1021 | // branches. |
| 1022 | 1022 | const branch_rl: ResultLoc = switch (rl) { |
| 1023 | | .discard, .none, .ty, .ptr, .lvalue, .ref => rl, |
| 1023 | .discard, .none, .ty, .ptr, .ref => rl, |
| 1024 | 1024 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, |
| 1025 | 1025 | }; |
| 1026 | 1026 | |
| ... | ... | @@ -1150,7 +1150,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1150 | 1150 | // proper type inference requires peer type resolution on the while's |
| 1151 | 1151 | // branches. |
| 1152 | 1152 | const branch_rl: ResultLoc = switch (rl) { |
| 1153 | | .discard, .none, .ty, .ptr, .lvalue, .ref => rl, |
| 1153 | .discard, .none, .ty, .ptr, .ref => rl, |
| 1154 | 1154 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block }, |
| 1155 | 1155 | }; |
| 1156 | 1156 | |
| ... | ... | @@ -1535,7 +1535,6 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I |
| 1535 | 1535 | _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); |
| 1536 | 1536 | return result; |
| 1537 | 1537 | }, |
| 1538 | | .lvalue => unreachable, |
| 1539 | 1538 | .ref => { |
| 1540 | 1539 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); |
| 1541 | 1540 | return addZIRUnOp(mod, scope, result.src, .ref, result); |
| ... | ... | @@ -1583,7 +1582,6 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa |
| 1583 | 1582 | _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); |
| 1584 | 1583 | return result; |
| 1585 | 1584 | }, |
| 1586 | | .lvalue => unreachable, |
| 1587 | 1585 | .ref => { |
| 1588 | 1586 | const operand = try expr(mod, scope, .ref, params[1]); |
| 1589 | 1587 | const result = try addZIRBinOp(mod, scope, src, .bitcast_ref, dest_type, operand); |
| ... | ... | @@ -1851,7 +1849,7 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr |
| 1851 | 1849 | _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); |
| 1852 | 1850 | return result; |
| 1853 | 1851 | }, |
| 1854 | | .lvalue, .ref => { |
| 1852 | .ref => { |
| 1855 | 1853 | // We need a pointer but we have a value. |
| 1856 | 1854 | return addZIRUnOp(mod, scope, result.src, .ref, result); |
| 1857 | 1855 | }, |
| ... | ... | @@ -1886,7 +1884,7 @@ fn rlWrapVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, resul |
| 1886 | 1884 | } |
| 1887 | 1885 | |
| 1888 | 1886 | fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerError!*zir.Inst { |
| 1889 | | if (rl == .lvalue or rl == .ref) return ptr; |
| 1887 | if (rl == .ref) return ptr; |
| 1890 | 1888 | |
| 1891 | 1889 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, ptr.src, .deref, ptr)); |
| 1892 | 1890 | } |