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