| author | |
| committer | |
| log | 7e56028bc7c00b884c92e2948728cbc47e5a8a09 |
| tree | 660b8f5e027066e728fbd88db5e58385940aa2d7 |
| parent | 6c7e66613d57aec2f2949c065ea6431ff6c31f88 |
| parent | ecc246efa2c133aaab73032a18fed5b2c15e08ce |
closes #7730
closes #76628 files changed, 404 insertions(+), 106 deletions(-)
src/Module.zig+1-1| ... | @@ -2453,7 +2453,7 @@ pub fn analyzeIsNull( | ... | @@ -2453,7 +2453,7 @@ pub fn analyzeIsNull( |
| 2453 | return self.constBool(scope, src, bool_value); | 2453 | return self.constBool(scope, src, bool_value); |
| 2454 | } | 2454 | } |
| 2455 | const b = try self.requireRuntimeBlock(scope, src); | 2455 | const b = try self.requireRuntimeBlock(scope, src); |
| 2456 | const inst_tag: Inst.Tag = if (invert_logic) .isnonnull else .isnull; | 2456 | const inst_tag: Inst.Tag = if (invert_logic) .is_non_null else .is_null; |
| 2457 | return self.addUnOp(b, src, Type.initTag(.bool), inst_tag, operand); | 2457 | return self.addUnOp(b, src, Type.initTag(.bool), inst_tag, operand); |
| 2458 | } | 2458 | } |
| 2459 | 2459 |
src/astgen.zig+94-28| ... | @@ -118,7 +118,6 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { | ... | @@ -118,7 +118,6 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { |
| 118 | .LabeledBlock, | 118 | .LabeledBlock, |
| 119 | .Break, | 119 | .Break, |
| 120 | .PtrType, | 120 | .PtrType, |
| 121 | .GroupedExpression, | ||
| 122 | .ArrayType, | 121 | .ArrayType, |
| 123 | .ArrayTypeSentinel, | 122 | .ArrayTypeSentinel, |
| 124 | .EnumLiteral, | 123 | .EnumLiteral, |
| ... | @@ -129,7 +128,6 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { | ... | @@ -129,7 +128,6 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { |
| 129 | .ErrorUnion, | 128 | .ErrorUnion, |
| 130 | .MergeErrorSets, | 129 | .MergeErrorSets, |
| 131 | .Range, | 130 | .Range, |
| 132 | .OrElse, | ||
| 133 | .Await, | 131 | .Await, |
| 134 | .BitNot, | 132 | .BitNot, |
| 135 | .Negation, | 133 | .Negation, |
| ... | @@ -168,7 +166,14 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { | ... | @@ -168,7 +166,14 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { |
| 168 | }, | 166 | }, |
| 169 | 167 | ||
| 170 | // can be assigned to | 168 | // can be assigned to |
| 171 | .UnwrapOptional, .Deref, .Period, .ArrayAccess, .Identifier => {}, | 169 | .UnwrapOptional, |
| 170 | .Deref, | ||
| 171 | .Period, | ||
| 172 | .ArrayAccess, | ||
| 173 | .Identifier, | ||
| 174 | .GroupedExpression, | ||
| 175 | .OrElse, | ||
| 176 | => {}, | ||
| 172 | } | 177 | } |
| 173 | return expr(mod, scope, .ref, node); | 178 | return expr(mod, scope, .ref, node); |
| 174 | } | 179 | } |
| ... | @@ -913,8 +918,12 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si | ... | @@ -913,8 +918,12 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si |
| 913 | const tree = scope.tree(); | 918 | const tree = scope.tree(); |
| 914 | const src = tree.token_locs[node.rtoken].start; | 919 | const src = tree.token_locs[node.rtoken].start; |
| 915 | 920 | ||
| 916 | const operand = try expr(mod, scope, .ref, node.lhs); | 921 | const operand = try expr(mod, scope, rl, node.lhs); |
| 917 | return rlWrapPtr(mod, scope, rl, try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand)); | 922 | const op: zir.Inst.Tag = switch (rl) { |
| 923 | .ref => .optional_payload_safe_ptr, | ||
| 924 | else => .optional_payload_safe, | ||
| 925 | }; | ||
| 926 | return addZIRUnOp(mod, scope, src, op, operand); | ||
| 918 | } | 927 | } |
| 919 | 928 | ||
| 920 | fn containerField( | 929 | fn containerField( |
| ... | @@ -1110,6 +1119,7 @@ fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Erro | ... | @@ -1110,6 +1119,7 @@ fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Erro |
| 1110 | } | 1119 | } |
| 1111 | 1120 | ||
| 1112 | // analyzing the error set results in a decl ref, so we might need to dereference it | 1121 | // analyzing the error set results in a decl ref, so we might need to dereference it |
| 1122 | // TODO remove all callsites to rlWrapPtr | ||
| 1113 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{})); | 1123 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{})); |
| 1114 | } | 1124 | } |
| 1115 | 1125 | ||
| ... | @@ -1123,11 +1133,61 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!* | ... | @@ -1123,11 +1133,61 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!* |
| 1123 | } | 1133 | } |
| 1124 | 1134 | ||
| 1125 | fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst { | 1135 | fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst { |
| 1126 | return orelseCatchExpr(mod, scope, rl, node.lhs, node.op_token, .iserr, .unwrap_err_unsafe, node.rhs, node.payload); | 1136 | switch (rl) { |
| 1137 | .ref => return orelseCatchExpr( | ||
| 1138 | mod, | ||
| 1139 | scope, | ||
| 1140 | rl, | ||
| 1141 | node.lhs, | ||
| 1142 | node.op_token, | ||
| 1143 | .is_err_ptr, | ||
| 1144 | .err_union_payload_unsafe_ptr, | ||
| 1145 | .err_union_code_ptr, | ||
| 1146 | node.rhs, | ||
| 1147 | node.payload, | ||
| 1148 | ), | ||
| 1149 | else => return orelseCatchExpr( | ||
| 1150 | mod, | ||
| 1151 | scope, | ||
| 1152 | rl, | ||
| 1153 | node.lhs, | ||
| 1154 | node.op_token, | ||
| 1155 | .is_err, | ||
| 1156 | .err_union_payload_unsafe, | ||
| 1157 | .err_union_code, | ||
| 1158 | node.rhs, | ||
| 1159 | node.payload, | ||
| 1160 | ), | ||
| 1161 | } | ||
| 1127 | } | 1162 | } |
| 1128 | 1163 | ||
| 1129 | fn orelseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { | 1164 | fn orelseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { |
| 1130 | return orelseCatchExpr(mod, scope, rl, node.lhs, node.op_token, .isnull, .unwrap_optional_unsafe, node.rhs, null); | 1165 | switch (rl) { |
| 1166 | .ref => return orelseCatchExpr( | ||
| 1167 | mod, | ||
| 1168 | scope, | ||
| 1169 | rl, | ||
| 1170 | node.lhs, | ||
| 1171 | node.op_token, | ||
| 1172 | .is_null_ptr, | ||
| 1173 | .optional_payload_unsafe_ptr, | ||
| 1174 | undefined, | ||
| 1175 | node.rhs, | ||
| 1176 | null, | ||
| 1177 | ), | ||
| 1178 | else => return orelseCatchExpr( | ||
| 1179 | mod, | ||
| 1180 | scope, | ||
| 1181 | rl, | ||
| 1182 | node.lhs, | ||
| 1183 | node.op_token, | ||
| 1184 | .is_null, | ||
| 1185 | .optional_payload_unsafe, | ||
| 1186 | undefined, | ||
| 1187 | node.rhs, | ||
| 1188 | null, | ||
| 1189 | ), | ||
| 1190 | } | ||
| 1131 | } | 1191 | } |
| 1132 | 1192 | ||
| 1133 | fn orelseCatchExpr( | 1193 | fn orelseCatchExpr( |
| ... | @@ -1138,17 +1198,13 @@ fn orelseCatchExpr( | ... | @@ -1138,17 +1198,13 @@ fn orelseCatchExpr( |
| 1138 | op_token: ast.TokenIndex, | 1198 | op_token: ast.TokenIndex, |
| 1139 | cond_op: zir.Inst.Tag, | 1199 | cond_op: zir.Inst.Tag, |
| 1140 | unwrap_op: zir.Inst.Tag, | 1200 | unwrap_op: zir.Inst.Tag, |
| 1201 | unwrap_code_op: zir.Inst.Tag, | ||
| 1141 | rhs: *ast.Node, | 1202 | rhs: *ast.Node, |
| 1142 | payload_node: ?*ast.Node, | 1203 | payload_node: ?*ast.Node, |
| 1143 | ) InnerError!*zir.Inst { | 1204 | ) InnerError!*zir.Inst { |
| 1144 | const tree = scope.tree(); | 1205 | const tree = scope.tree(); |
| 1145 | const src = tree.token_locs[op_token].start; | 1206 | const src = tree.token_locs[op_token].start; |
| 1146 | 1207 | ||
| 1147 | const operand_ptr = try expr(mod, scope, .ref, lhs); | ||
| 1148 | // TODO we could avoid an unnecessary copy if .iserr, .isnull took a pointer | ||
| 1149 | const err_union = try addZIRUnOp(mod, scope, src, .deref, operand_ptr); | ||
| 1150 | const cond = try addZIRUnOp(mod, scope, src, cond_op, err_union); | ||
| 1151 | |||
| 1152 | var block_scope: Scope.GenZIR = .{ | 1208 | var block_scope: Scope.GenZIR = .{ |
| 1153 | .parent = scope, | 1209 | .parent = scope, |
| 1154 | .decl = scope.ownerDecl().?, | 1210 | .decl = scope.ownerDecl().?, |
| ... | @@ -1157,14 +1213,8 @@ fn orelseCatchExpr( | ... | @@ -1157,14 +1213,8 @@ fn orelseCatchExpr( |
| 1157 | }; | 1213 | }; |
| 1158 | defer block_scope.instructions.deinit(mod.gpa); | 1214 | defer block_scope.instructions.deinit(mod.gpa); |
| 1159 | 1215 | ||
| 1160 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ | ||
| 1161 | .condition = cond, | ||
| 1162 | .then_body = undefined, // populated below | ||
| 1163 | .else_body = undefined, // populated below | ||
| 1164 | }, .{}); | ||
| 1165 | |||
| 1166 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ | 1216 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ |
| 1167 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | 1217 | .instructions = undefined, // populated below |
| 1168 | }); | 1218 | }); |
| 1169 | 1219 | ||
| 1170 | // Most result location types can be forwarded directly; however | 1220 | // Most result location types can be forwarded directly; however |
| ... | @@ -1175,9 +1225,18 @@ fn orelseCatchExpr( | ... | @@ -1175,9 +1225,18 @@ fn orelseCatchExpr( |
| 1175 | .discard, .none, .ty, .ptr, .ref => rl, | 1225 | .discard, .none, .ty, .ptr, .ref => rl, |
| 1176 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, | 1226 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, |
| 1177 | }; | 1227 | }; |
| 1228 | // This could be a pointer or value depending on the `rl` parameter. | ||
| 1229 | const operand = try expr(mod, &block_scope.base, branch_rl, lhs); | ||
| 1230 | const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand); | ||
| 1231 | |||
| 1232 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ | ||
| 1233 | .condition = cond, | ||
| 1234 | .then_body = undefined, // populated below | ||
| 1235 | .else_body = undefined, // populated below | ||
| 1236 | }, .{}); | ||
| 1178 | 1237 | ||
| 1179 | var then_scope: Scope.GenZIR = .{ | 1238 | var then_scope: Scope.GenZIR = .{ |
| 1180 | .parent = scope, | 1239 | .parent = &block_scope.base, |
| 1181 | .decl = block_scope.decl, | 1240 | .decl = block_scope.decl, |
| 1182 | .arena = block_scope.arena, | 1241 | .arena = block_scope.arena, |
| 1183 | .instructions = .{}, | 1242 | .instructions = .{}, |
| ... | @@ -1193,12 +1252,11 @@ fn orelseCatchExpr( | ... | @@ -1193,12 +1252,11 @@ fn orelseCatchExpr( |
| 1193 | if (mem.eql(u8, err_name, "_")) | 1252 | if (mem.eql(u8, err_name, "_")) |
| 1194 | break :blk &then_scope.base; | 1253 | break :blk &then_scope.base; |
| 1195 | 1254 | ||
| 1196 | const unwrapped_err_ptr = try addZIRUnOp(mod, &then_scope.base, src, .unwrap_err_code, operand_ptr); | ||
| 1197 | err_val_scope = .{ | 1255 | err_val_scope = .{ |
| 1198 | .parent = &then_scope.base, | 1256 | .parent = &then_scope.base, |
| 1199 | .gen_zir = &then_scope, | 1257 | .gen_zir = &then_scope, |
| 1200 | .name = err_name, | 1258 | .name = err_name, |
| 1201 | .inst = try addZIRUnOp(mod, &then_scope.base, src, .deref, unwrapped_err_ptr), | 1259 | .inst = try addZIRUnOp(mod, &then_scope.base, src, unwrap_code_op, operand), |
| 1202 | }; | 1260 | }; |
| 1203 | break :blk &err_val_scope.base; | 1261 | break :blk &err_val_scope.base; |
| 1204 | }; | 1262 | }; |
| ... | @@ -1209,22 +1267,26 @@ fn orelseCatchExpr( | ... | @@ -1209,22 +1267,26 @@ fn orelseCatchExpr( |
| 1209 | }, .{}); | 1267 | }, .{}); |
| 1210 | 1268 | ||
| 1211 | var else_scope: Scope.GenZIR = .{ | 1269 | var else_scope: Scope.GenZIR = .{ |
| 1212 | .parent = scope, | 1270 | .parent = &block_scope.base, |
| 1213 | .decl = block_scope.decl, | 1271 | .decl = block_scope.decl, |
| 1214 | .arena = block_scope.arena, | 1272 | .arena = block_scope.arena, |
| 1215 | .instructions = .{}, | 1273 | .instructions = .{}, |
| 1216 | }; | 1274 | }; |
| 1217 | defer else_scope.instructions.deinit(mod.gpa); | 1275 | defer else_scope.instructions.deinit(mod.gpa); |
| 1218 | 1276 | ||
| 1219 | const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand_ptr); | 1277 | // This could be a pointer or value depending on `unwrap_op`. |
| 1278 | const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand); | ||
| 1220 | _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{ | 1279 | _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{ |
| 1221 | .block = block, | 1280 | .block = block, |
| 1222 | .operand = unwrapped_payload, | 1281 | .operand = unwrapped_payload, |
| 1223 | }, .{}); | 1282 | }, .{}); |
| 1224 | 1283 | ||
| 1284 | // All branches have been generated, add the instructions to the block. | ||
| 1285 | block.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items); | ||
| 1286 | |||
| 1225 | condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) }; | 1287 | condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) }; |
| 1226 | condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) }; | 1288 | condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) }; |
| 1227 | return rlWrapPtr(mod, scope, rl, &block.base); | 1289 | return &block.base; |
| 1228 | } | 1290 | } |
| 1229 | 1291 | ||
| 1230 | /// Return whether the identifier names of two tokens are equal. Resolves @"" | 1292 | /// Return whether the identifier names of two tokens are equal. Resolves @"" |
| ... | @@ -1253,6 +1315,7 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix | ... | @@ -1253,6 +1315,7 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix |
| 1253 | const lhs = try expr(mod, scope, .ref, node.lhs); | 1315 | const lhs = try expr(mod, scope, .ref, node.lhs); |
| 1254 | const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?); | 1316 | const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?); |
| 1255 | 1317 | ||
| 1318 | // TODO remove all callsites to rlWrapPtr | ||
| 1256 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{})); | 1319 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{})); |
| 1257 | } | 1320 | } |
| 1258 | 1321 | ||
| ... | @@ -1263,6 +1326,7 @@ fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Array | ... | @@ -1263,6 +1326,7 @@ fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Array |
| 1263 | const array_ptr = try expr(mod, scope, .ref, node.lhs); | 1326 | const array_ptr = try expr(mod, scope, .ref, node.lhs); |
| 1264 | const index = try expr(mod, scope, .none, node.index_expr); | 1327 | const index = try expr(mod, scope, .none, node.index_expr); |
| 1265 | 1328 | ||
| 1329 | // TODO remove all callsites to rlWrapPtr | ||
| 1266 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{})); | 1330 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{})); |
| 1267 | } | 1331 | } |
| 1268 | 1332 | ||
| ... | @@ -1420,13 +1484,13 @@ const CondKind = union(enum) { | ... | @@ -1420,13 +1484,13 @@ const CondKind = union(enum) { |
| 1420 | const cond_ptr = try expr(mod, &block_scope.base, .ref, cond_node); | 1484 | const cond_ptr = try expr(mod, &block_scope.base, .ref, cond_node); |
| 1421 | self.* = .{ .optional = cond_ptr }; | 1485 | self.* = .{ .optional = cond_ptr }; |
| 1422 | const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr); | 1486 | const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr); |
| 1423 | return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result); | 1487 | return try addZIRUnOp(mod, &block_scope.base, src, .is_non_null, result); |
| 1424 | }, | 1488 | }, |
| 1425 | .err_union => { | 1489 | .err_union => { |
| 1426 | const err_ptr = try expr(mod, &block_scope.base, .ref, cond_node); | 1490 | const err_ptr = try expr(mod, &block_scope.base, .ref, cond_node); |
| 1427 | self.* = .{ .err_union = err_ptr }; | 1491 | self.* = .{ .err_union = err_ptr }; |
| 1428 | const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr); | 1492 | const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr); |
| 1429 | return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result); | 1493 | return try addZIRUnOp(mod, &block_scope.base, src, .is_err, result); |
| 1430 | }, | 1494 | }, |
| 1431 | } | 1495 | } |
| 1432 | } | 1496 | } |
| ... | @@ -1456,7 +1520,7 @@ const CondKind = union(enum) { | ... | @@ -1456,7 +1520,7 @@ const CondKind = union(enum) { |
| 1456 | fn elseSubScope(self: CondKind, mod: *Module, else_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope { | 1520 | fn elseSubScope(self: CondKind, mod: *Module, else_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope { |
| 1457 | if (self != .err_union) return &else_scope.base; | 1521 | if (self != .err_union) return &else_scope.base; |
| 1458 | 1522 | ||
| 1459 | const payload_ptr = try addZIRUnOp(mod, &else_scope.base, src, .unwrap_err_unsafe, self.err_union.?); | 1523 | const payload_ptr = try addZIRUnOp(mod, &else_scope.base, src, .err_union_payload_unsafe_ptr, self.err_union.?); |
| 1460 | 1524 | ||
| 1461 | const payload = payload_node.?.castTag(.Payload).?; | 1525 | const payload = payload_node.?.castTag(.Payload).?; |
| 1462 | const ident_node = payload.error_symbol.castTag(.Identifier).?; | 1526 | const ident_node = payload.error_symbol.castTag(.Identifier).?; |
| ... | @@ -2264,6 +2328,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo | ... | @@ -2264,6 +2328,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo |
| 2264 | .local_ptr => { | 2328 | .local_ptr => { |
| 2265 | const local_ptr = s.cast(Scope.LocalPtr).?; | 2329 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 2266 | if (mem.eql(u8, local_ptr.name, ident_name)) { | 2330 | if (mem.eql(u8, local_ptr.name, ident_name)) { |
| 2331 | // TODO remove all callsites to rlWrapPtr | ||
| 2267 | return rlWrapPtr(mod, scope, rl, local_ptr.ptr); | 2332 | return rlWrapPtr(mod, scope, rl, local_ptr.ptr); |
| 2268 | } | 2333 | } |
| 2269 | s = local_ptr.parent; | 2334 | s = local_ptr.parent; |
| ... | @@ -3047,6 +3112,7 @@ fn rlWrapVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, resul | ... | @@ -3047,6 +3112,7 @@ fn rlWrapVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, resul |
| 3047 | 3112 | ||
| 3048 | /// TODO go over all the callsites and see where we can introduce "by-value" ZIR instructions | 3113 | /// TODO go over all the callsites and see where we can introduce "by-value" ZIR instructions |
| 3049 | /// to save ZIR memory. For example, see DeclVal vs DeclRef. | 3114 | /// to save ZIR memory. For example, see DeclVal vs DeclRef. |
| 3115 | /// Do not add additional callsites to this function. | ||
| 3050 | fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerError!*zir.Inst { | 3116 | fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerError!*zir.Inst { |
| 3051 | if (rl == .ref) return ptr; | 3117 | if (rl == .ref) return ptr; |
| 3052 | 3118 |
src/codegen.zig+31-6| ... | @@ -860,9 +860,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -860,9 +860,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 860 | .dbg_stmt => return self.genDbgStmt(inst.castTag(.dbg_stmt).?), | 860 | .dbg_stmt => return self.genDbgStmt(inst.castTag(.dbg_stmt).?), |
| 861 | .floatcast => return self.genFloatCast(inst.castTag(.floatcast).?), | 861 | .floatcast => return self.genFloatCast(inst.castTag(.floatcast).?), |
| 862 | .intcast => return self.genIntCast(inst.castTag(.intcast).?), | 862 | .intcast => return self.genIntCast(inst.castTag(.intcast).?), |
| 863 | .isnonnull => return self.genIsNonNull(inst.castTag(.isnonnull).?), | 863 | .is_non_null => return self.genIsNonNull(inst.castTag(.is_non_null).?), |
| 864 | .isnull => return self.genIsNull(inst.castTag(.isnull).?), | 864 | .is_non_null_ptr => return self.genIsNonNullPtr(inst.castTag(.is_non_null_ptr).?), |
| 865 | .iserr => return self.genIsErr(inst.castTag(.iserr).?), | 865 | .is_null => return self.genIsNull(inst.castTag(.is_null).?), |
| 866 | .is_null_ptr => return self.genIsNullPtr(inst.castTag(.is_null_ptr).?), | ||
| 867 | .is_err => return self.genIsErr(inst.castTag(.is_err).?), | ||
| 868 | .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?), | ||
| 866 | .load => return self.genLoad(inst.castTag(.load).?), | 869 | .load => return self.genLoad(inst.castTag(.load).?), |
| 867 | .loop => return self.genLoop(inst.castTag(.loop).?), | 870 | .loop => return self.genLoop(inst.castTag(.loop).?), |
| 868 | .not => return self.genNot(inst.castTag(.not).?), | 871 | .not => return self.genNot(inst.castTag(.not).?), |
| ... | @@ -874,7 +877,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -874,7 +877,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 874 | .sub => return self.genSub(inst.castTag(.sub).?), | 877 | .sub => return self.genSub(inst.castTag(.sub).?), |
| 875 | .switchbr => return self.genSwitch(inst.castTag(.switchbr).?), | 878 | .switchbr => return self.genSwitch(inst.castTag(.switchbr).?), |
| 876 | .unreach => return MCValue{ .unreach = {} }, | 879 | .unreach => return MCValue{ .unreach = {} }, |
| 877 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), | 880 | .optional_payload => return self.genOptionalPayload(inst.castTag(.optional_payload).?), |
| 881 | .optional_payload_ptr => return self.genOptionalPayloadPtr(inst.castTag(.optional_payload_ptr).?), | ||
| 878 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), | 882 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), |
| 879 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), | 883 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), |
| 880 | .xor => return self.genXor(inst.castTag(.xor).?), | 884 | .xor => return self.genXor(inst.castTag(.xor).?), |
| ... | @@ -1118,12 +1122,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1118,12 +1122,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1118 | } | 1122 | } |
| 1119 | } | 1123 | } |
| 1120 | 1124 | ||
| 1121 | fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | 1125 | fn genOptionalPayload(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 1122 | // No side effects, so if it's unreferenced, do nothing. | 1126 | // No side effects, so if it's unreferenced, do nothing. |
| 1123 | if (inst.base.isUnused()) | 1127 | if (inst.base.isUnused()) |
| 1124 | return MCValue.dead; | 1128 | return MCValue.dead; |
| 1125 | switch (arch) { | 1129 | switch (arch) { |
| 1126 | else => return self.fail(inst.base.src, "TODO implement unwrap optional for {}", .{self.target.cpu.arch}), | 1130 | else => return self.fail(inst.base.src, "TODO implement .optional_payload for {}", .{self.target.cpu.arch}), |
| 1131 | } | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | fn genOptionalPayloadPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 1135 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1136 | if (inst.base.isUnused()) | ||
| 1137 | return MCValue.dead; | ||
| 1138 | switch (arch) { | ||
| 1139 | else => return self.fail(inst.base.src, "TODO implement .optional_payload_ptr for {}", .{self.target.cpu.arch}), | ||
| 1127 | } | 1140 | } |
| 1128 | } | 1141 | } |
| 1129 | 1142 | ||
| ... | @@ -2306,6 +2319,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2306,6 +2319,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2306 | } | 2319 | } |
| 2307 | } | 2320 | } |
| 2308 | 2321 | ||
| 2322 | fn genIsNullPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 2323 | return self.fail(inst.base.src, "TODO load the operand and call genIsNull", .{}); | ||
| 2324 | } | ||
| 2325 | |||
| 2309 | fn genIsNonNull(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | 2326 | fn genIsNonNull(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 2310 | // Here you can specialize this instruction if it makes sense to, otherwise the default | 2327 | // Here you can specialize this instruction if it makes sense to, otherwise the default |
| 2311 | // will call genIsNull and invert the result. | 2328 | // will call genIsNull and invert the result. |
| ... | @@ -2314,12 +2331,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2314,12 +2331,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2314 | } | 2331 | } |
| 2315 | } | 2332 | } |
| 2316 | 2333 | ||
| 2334 | fn genIsNonNullPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 2335 | return self.fail(inst.base.src, "TODO load the operand and call genIsNonNull", .{}); | ||
| 2336 | } | ||
| 2337 | |||
| 2317 | fn genIsErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | 2338 | fn genIsErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 2318 | switch (arch) { | 2339 | switch (arch) { |
| 2319 | else => return self.fail(inst.base.src, "TODO implement iserr for {}", .{self.target.cpu.arch}), | 2340 | else => return self.fail(inst.base.src, "TODO implement iserr for {}", .{self.target.cpu.arch}), |
| 2320 | } | 2341 | } |
| 2321 | } | 2342 | } |
| 2322 | 2343 | ||
| 2344 | fn genIsErrPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 2345 | return self.fail(inst.base.src, "TODO load the operand and call genIsErr", .{}); | ||
| 2346 | } | ||
| 2347 | |||
| 2323 | fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue { | 2348 | fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue { |
| 2324 | // A loop is a setup to be able to jump back to the beginning. | 2349 | // A loop is a setup to be able to jump back to the beginning. |
| 2325 | const start_index = self.code.items.len; | 2350 | const start_index = self.code.items.len; |
src/ir.zig+24-8| ... | @@ -73,9 +73,18 @@ pub const Inst = struct { | ... | @@ -73,9 +73,18 @@ pub const Inst = struct { |
| 73 | condbr, | 73 | condbr, |
| 74 | constant, | 74 | constant, |
| 75 | dbg_stmt, | 75 | dbg_stmt, |
| 76 | isnonnull, | 76 | // ?T => bool |
| 77 | isnull, | 77 | is_null, |
| 78 | iserr, | 78 | // ?T => bool (inverted logic) |
| 79 | is_non_null, | ||
| 80 | // *?T => bool | ||
| 81 | is_null_ptr, | ||
| 82 | // *?T => bool (inverted logic) | ||
| 83 | is_non_null_ptr, | ||
| 84 | // E!T => bool | ||
| 85 | is_err, | ||
| 86 | // *E!T => bool | ||
| 87 | is_err_ptr, | ||
| 79 | booland, | 88 | booland, |
| 80 | boolor, | 89 | boolor, |
| 81 | /// Read a value from a pointer. | 90 | /// Read a value from a pointer. |
| ... | @@ -93,7 +102,10 @@ pub const Inst = struct { | ... | @@ -93,7 +102,10 @@ pub const Inst = struct { |
| 93 | not, | 102 | not, |
| 94 | floatcast, | 103 | floatcast, |
| 95 | intcast, | 104 | intcast, |
| 96 | unwrap_optional, | 105 | // ?T => T |
| 106 | optional_payload, | ||
| 107 | // *?T => *T | ||
| 108 | optional_payload_ptr, | ||
| 97 | wrap_optional, | 109 | wrap_optional, |
| 98 | xor, | 110 | xor, |
| 99 | switchbr, | 111 | switchbr, |
| ... | @@ -111,14 +123,18 @@ pub const Inst = struct { | ... | @@ -111,14 +123,18 @@ pub const Inst = struct { |
| 111 | .ret, | 123 | .ret, |
| 112 | .bitcast, | 124 | .bitcast, |
| 113 | .not, | 125 | .not, |
| 114 | .isnonnull, | 126 | .is_non_null, |
| 115 | .isnull, | 127 | .is_non_null_ptr, |
| 116 | .iserr, | 128 | .is_null, |
| 129 | .is_null_ptr, | ||
| 130 | .is_err, | ||
| 131 | .is_err_ptr, | ||
| 117 | .ptrtoint, | 132 | .ptrtoint, |
| 118 | .floatcast, | 133 | .floatcast, |
| 119 | .intcast, | 134 | .intcast, |
| 120 | .load, | 135 | .load, |
| 121 | .unwrap_optional, | 136 | .optional_payload, |
| 137 | .optional_payload_ptr, | ||
| 122 | .wrap_optional, | 138 | .wrap_optional, |
| 123 | => UnOp, | 139 | => UnOp, |
| 124 | 140 |
src/test.zig+4-1| ... | @@ -696,7 +696,10 @@ pub const TestContext = struct { | ... | @@ -696,7 +696,10 @@ pub const TestContext = struct { |
| 696 | var all_errors = try comp.getAllErrorsAlloc(); | 696 | var all_errors = try comp.getAllErrorsAlloc(); |
| 697 | defer all_errors.deinit(allocator); | 697 | defer all_errors.deinit(allocator); |
| 698 | if (all_errors.list.len != 0) { | 698 | if (all_errors.list.len != 0) { |
| 699 | std.debug.print("\nErrors occurred updating the compilation:\n{s}\n", .{hr}); | 699 | std.debug.print( |
| 700 | "\nCase '{s}': unexpected errors at update_index={d}:\n{s}\n", | ||
| 701 | .{ case.name, update_index, hr }, | ||
| 702 | ); | ||
| 700 | for (all_errors.list) |err_msg| { | 703 | for (all_errors.list) |err_msg| { |
| 701 | switch (err_msg) { | 704 | switch (err_msg) { |
| 702 | .src => |src| { | 705 | .src => |src| { |
src/zir.zig+93-37| ... | @@ -174,11 +174,17 @@ pub const Inst = struct { | ... | @@ -174,11 +174,17 @@ pub const Inst = struct { |
| 174 | /// Make an integer type out of signedness and bit count. | 174 | /// Make an integer type out of signedness and bit count. |
| 175 | inttype, | 175 | inttype, |
| 176 | /// Return a boolean false if an optional is null. `x != null` | 176 | /// Return a boolean false if an optional is null. `x != null` |
| 177 | isnonnull, | 177 | is_non_null, |
| 178 | /// Return a boolean true if an optional is null. `x == null` | 178 | /// Return a boolean true if an optional is null. `x == null` |
| 179 | isnull, | 179 | is_null, |
| 180 | /// Return a boolean false if an optional is null. `x.* != null` | ||
| 181 | is_non_null_ptr, | ||
| 182 | /// Return a boolean true if an optional is null. `x.* == null` | ||
| 183 | is_null_ptr, | ||
| 180 | /// Return a boolean true if value is an error | 184 | /// Return a boolean true if value is an error |
| 181 | iserr, | 185 | is_err, |
| 186 | /// Return a boolean true if dereferenced pointer is an error | ||
| 187 | is_err_ptr, | ||
| 182 | /// A labeled block of code that loops forever. At the end of the body it is implied | 188 | /// A labeled block of code that loops forever. At the end of the body it is implied |
| 183 | /// to repeat; no explicit "repeat" instruction terminates loop bodies. | 189 | /// to repeat; no explicit "repeat" instruction terminates loop bodies. |
| 184 | loop, | 190 | loop, |
| ... | @@ -278,16 +284,42 @@ pub const Inst = struct { | ... | @@ -278,16 +284,42 @@ pub const Inst = struct { |
| 278 | optional_type, | 284 | optional_type, |
| 279 | /// Create a union type. | 285 | /// Create a union type. |
| 280 | union_type, | 286 | union_type, |
| 281 | /// Unwraps an optional value 'lhs.?' | 287 | /// ?T => T with safety. |
| 282 | unwrap_optional_safe, | 288 | /// Given an optional value, returns the payload value, with a safety check that |
| 283 | /// Same as previous, but without safety checks. Used for orelse, if and while | 289 | /// the value is non-null. Used for `orelse`, `if` and `while`. |
| 284 | unwrap_optional_unsafe, | 290 | optional_payload_safe, |
| 285 | /// Gets the payload of an error union | 291 | /// ?T => T without safety. |
| 286 | unwrap_err_safe, | 292 | /// Given an optional value, returns the payload value. No safety checks. |
| 287 | /// Same as previous, but without safety checks. Used for orelse, if and while | 293 | optional_payload_unsafe, |
| 288 | unwrap_err_unsafe, | 294 | /// *?T => *T with safety. |
| 289 | /// Gets the error code value of an error union | 295 | /// Given a pointer to an optional value, returns a pointer to the payload value, |
| 290 | unwrap_err_code, | 296 | /// with a safety check that the value is non-null. Used for `orelse`, `if` and `while`. |
| 297 | optional_payload_safe_ptr, | ||
| 298 | /// *?T => *T without safety. | ||
| 299 | /// Given a pointer to an optional value, returns a pointer to the payload value. | ||
| 300 | /// No safety checks. | ||
| 301 | optional_payload_unsafe_ptr, | ||
| 302 | /// E!T => T with safety. | ||
| 303 | /// Given an error union value, returns the payload value, with a safety check | ||
| 304 | /// that the value is not an error. Used for catch, if, and while. | ||
| 305 | err_union_payload_safe, | ||
| 306 | /// E!T => T without safety. | ||
| 307 | /// Given an error union value, returns the payload value. No safety checks. | ||
| 308 | err_union_payload_unsafe, | ||
| 309 | /// *E!T => *T with safety. | ||
| 310 | /// Given a pointer to an error union value, returns a pointer to the payload value, | ||
| 311 | /// with a safety check that the value is not an error. Used for catch, if, and while. | ||
| 312 | err_union_payload_safe_ptr, | ||
| 313 | /// *E!T => *T without safety. | ||
| 314 | /// Given a pointer to a error union value, returns a pointer to the payload value. | ||
| 315 | /// No safety checks. | ||
| 316 | err_union_payload_unsafe_ptr, | ||
| 317 | /// E!T => E without safety. | ||
| 318 | /// Given an error union value, returns the error code. No safety checks. | ||
| 319 | err_union_code, | ||
| 320 | /// *E!T => E without safety. | ||
| 321 | /// Given a pointer to an error union value, returns the error code. No safety checks. | ||
| 322 | err_union_code_ptr, | ||
| 291 | /// Takes a *E!T and raises a compiler error if T != void | 323 | /// Takes a *E!T and raises a compiler error if T != void |
| 292 | ensure_err_payload_void, | 324 | ensure_err_payload_void, |
| 293 | /// Create a enum literal, | 325 | /// Create a enum literal, |
| ... | @@ -320,9 +352,12 @@ pub const Inst = struct { | ... | @@ -320,9 +352,12 @@ pub const Inst = struct { |
| 320 | .compileerror, | 352 | .compileerror, |
| 321 | .deref, | 353 | .deref, |
| 322 | .@"return", | 354 | .@"return", |
| 323 | .isnull, | 355 | .is_null, |
| 324 | .isnonnull, | 356 | .is_non_null, |
| 325 | .iserr, | 357 | .is_null_ptr, |
| 358 | .is_non_null_ptr, | ||
| 359 | .is_err, | ||
| 360 | .is_err_ptr, | ||
| 326 | .ptrtoint, | 361 | .ptrtoint, |
| 327 | .ensure_result_used, | 362 | .ensure_result_used, |
| 328 | .ensure_result_non_error, | 363 | .ensure_result_non_error, |
| ... | @@ -341,11 +376,16 @@ pub const Inst = struct { | ... | @@ -341,11 +376,16 @@ pub const Inst = struct { |
| 341 | .mut_slice_type, | 376 | .mut_slice_type, |
| 342 | .const_slice_type, | 377 | .const_slice_type, |
| 343 | .optional_type, | 378 | .optional_type, |
| 344 | .unwrap_optional_safe, | 379 | .optional_payload_safe, |
| 345 | .unwrap_optional_unsafe, | 380 | .optional_payload_unsafe, |
| 346 | .unwrap_err_safe, | 381 | .optional_payload_safe_ptr, |
| 347 | .unwrap_err_unsafe, | 382 | .optional_payload_unsafe_ptr, |
| 348 | .unwrap_err_code, | 383 | .err_union_payload_safe, |
| 384 | .err_union_payload_unsafe, | ||
| 385 | .err_union_payload_safe_ptr, | ||
| 386 | .err_union_payload_unsafe_ptr, | ||
| 387 | .err_union_code, | ||
| 388 | .err_union_code_ptr, | ||
| 349 | .ensure_err_payload_void, | 389 | .ensure_err_payload_void, |
| 350 | .anyframe_type, | 390 | .anyframe_type, |
| 351 | .bitnot, | 391 | .bitnot, |
| ... | @@ -495,9 +535,12 @@ pub const Inst = struct { | ... | @@ -495,9 +535,12 @@ pub const Inst = struct { |
| 495 | .int, | 535 | .int, |
| 496 | .intcast, | 536 | .intcast, |
| 497 | .inttype, | 537 | .inttype, |
| 498 | .isnonnull, | 538 | .is_non_null, |
| 499 | .isnull, | 539 | .is_null, |
| 500 | .iserr, | 540 | .is_non_null_ptr, |
| 541 | .is_null_ptr, | ||
| 542 | .is_err, | ||
| 543 | .is_err_ptr, | ||
| 501 | .mod_rem, | 544 | .mod_rem, |
| 502 | .mul, | 545 | .mul, |
| 503 | .mulwrap, | 546 | .mulwrap, |
| ... | @@ -525,11 +568,16 @@ pub const Inst = struct { | ... | @@ -525,11 +568,16 @@ pub const Inst = struct { |
| 525 | .typeof, | 568 | .typeof, |
| 526 | .xor, | 569 | .xor, |
| 527 | .optional_type, | 570 | .optional_type, |
| 528 | .unwrap_optional_safe, | 571 | .optional_payload_safe, |
| 529 | .unwrap_optional_unsafe, | 572 | .optional_payload_unsafe, |
| 530 | .unwrap_err_safe, | 573 | .optional_payload_safe_ptr, |
| 531 | .unwrap_err_unsafe, | 574 | .optional_payload_unsafe_ptr, |
| 532 | .unwrap_err_code, | 575 | .err_union_payload_safe, |
| 576 | .err_union_payload_unsafe, | ||
| 577 | .err_union_payload_safe_ptr, | ||
| 578 | .err_union_payload_unsafe_ptr, | ||
| 579 | .err_union_code, | ||
| 580 | .err_union_code_ptr, | ||
| 533 | .ptr_type, | 581 | .ptr_type, |
| 534 | .ensure_err_payload_void, | 582 | .ensure_err_payload_void, |
| 535 | .enum_literal, | 583 | .enum_literal, |
| ... | @@ -1540,14 +1588,18 @@ const DumpTzir = struct { | ... | @@ -1540,14 +1588,18 @@ const DumpTzir = struct { |
| 1540 | .ret, | 1588 | .ret, |
| 1541 | .bitcast, | 1589 | .bitcast, |
| 1542 | .not, | 1590 | .not, |
| 1543 | .isnonnull, | 1591 | .is_non_null, |
| 1544 | .isnull, | 1592 | .is_non_null_ptr, |
| 1545 | .iserr, | 1593 | .is_null, |
| 1594 | .is_null_ptr, | ||
| 1595 | .is_err, | ||
| 1596 | .is_err_ptr, | ||
| 1546 | .ptrtoint, | 1597 | .ptrtoint, |
| 1547 | .floatcast, | 1598 | .floatcast, |
| 1548 | .intcast, | 1599 | .intcast, |
| 1549 | .load, | 1600 | .load, |
| 1550 | .unwrap_optional, | 1601 | .optional_payload, |
| 1602 | .optional_payload_ptr, | ||
| 1551 | .wrap_optional, | 1603 | .wrap_optional, |
| 1552 | => { | 1604 | => { |
| 1553 | const un_op = inst.cast(ir.Inst.UnOp).?; | 1605 | const un_op = inst.cast(ir.Inst.UnOp).?; |
| ... | @@ -1637,14 +1689,18 @@ const DumpTzir = struct { | ... | @@ -1637,14 +1689,18 @@ const DumpTzir = struct { |
| 1637 | .ret, | 1689 | .ret, |
| 1638 | .bitcast, | 1690 | .bitcast, |
| 1639 | .not, | 1691 | .not, |
| 1640 | .isnonnull, | 1692 | .is_non_null, |
| 1641 | .isnull, | 1693 | .is_null, |
| 1642 | .iserr, | 1694 | .is_non_null_ptr, |
| 1695 | .is_null_ptr, | ||
| 1696 | .is_err, | ||
| 1697 | .is_err_ptr, | ||
| 1643 | .ptrtoint, | 1698 | .ptrtoint, |
| 1644 | .floatcast, | 1699 | .floatcast, |
| 1645 | .intcast, | 1700 | .intcast, |
| 1646 | .load, | 1701 | .load, |
| 1647 | .unwrap_optional, | 1702 | .optional_payload, |
| 1703 | .optional_payload_ptr, | ||
| 1648 | .wrap_optional, | 1704 | .wrap_optional, |
| 1649 | => { | 1705 | => { |
| 1650 | const un_op = inst.cast(ir.Inst.UnOp).?; | 1706 | const un_op = inst.cast(ir.Inst.UnOp).?; |
src/zir_sema.zig+110-25| ... | @@ -127,18 +127,26 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! | ... | @@ -127,18 +127,26 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 127 | .cmp_gt => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_gt).?, .gt), | 127 | .cmp_gt => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_gt).?, .gt), |
| 128 | .cmp_neq => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_neq).?, .neq), | 128 | .cmp_neq => return analyzeInstCmp(mod, scope, old_inst.castTag(.cmp_neq).?, .neq), |
| 129 | .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?), | 129 | .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?), |
| 130 | .isnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnull).?, true), | 130 | .is_null => return isNull(mod, scope, old_inst.castTag(.is_null).?, false), |
| 131 | .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false), | 131 | .is_non_null => return isNull(mod, scope, old_inst.castTag(.is_non_null).?, true), |
| 132 | .iserr => return analyzeInstIsErr(mod, scope, old_inst.castTag(.iserr).?), | 132 | .is_null_ptr => return isNullPtr(mod, scope, old_inst.castTag(.is_null_ptr).?, false), |
| 133 | .is_non_null_ptr => return isNullPtr(mod, scope, old_inst.castTag(.is_non_null_ptr).?, true), | ||
| 134 | .is_err => return isErr(mod, scope, old_inst.castTag(.is_err).?), | ||
| 135 | .is_err_ptr => return isErrPtr(mod, scope, old_inst.castTag(.is_err_ptr).?), | ||
| 133 | .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?), | 136 | .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?), |
| 134 | .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?), | 137 | .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?), |
| 135 | .typeof_peer => return analyzeInstTypeOfPeer(mod, scope, old_inst.castTag(.typeof_peer).?), | 138 | .typeof_peer => return analyzeInstTypeOfPeer(mod, scope, old_inst.castTag(.typeof_peer).?), |
| 136 | .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?), | 139 | .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?), |
| 137 | .unwrap_optional_safe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_safe).?, true), | 140 | .optional_payload_safe => return optionalPayload(mod, scope, old_inst.castTag(.optional_payload_safe).?, true), |
| 138 | .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false), | 141 | .optional_payload_unsafe => return optionalPayload(mod, scope, old_inst.castTag(.optional_payload_unsafe).?, false), |
| 139 | .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true), | 142 | .optional_payload_safe_ptr => return optionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_safe_ptr).?, true), |
| 140 | .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false), | 143 | .optional_payload_unsafe_ptr => return optionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_unsafe_ptr).?, false), |
| 141 | .unwrap_err_code => return analyzeInstUnwrapErrCode(mod, scope, old_inst.castTag(.unwrap_err_code).?), | 144 | .err_union_payload_safe => return errorUnionPayload(mod, scope, old_inst.castTag(.err_union_payload_safe).?, true), |
| 145 | .err_union_payload_unsafe => return errorUnionPayload(mod, scope, old_inst.castTag(.err_union_payload_unsafe).?, false), | ||
| 146 | .err_union_payload_safe_ptr => return errorUnionPayloadPtr(mod, scope, old_inst.castTag(.err_union_payload_safe_ptr).?, true), | ||
| 147 | .err_union_payload_unsafe_ptr => return errorUnionPayloadPtr(mod, scope, old_inst.castTag(.err_union_payload_unsafe_ptr).?, false), | ||
| 148 | .err_union_code => return errorUnionCode(mod, scope, old_inst.castTag(.err_union_code).?), | ||
| 149 | .err_union_code_ptr => return errorUnionCodePtr(mod, scope, old_inst.castTag(.err_union_code_ptr).?), | ||
| 142 | .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?), | 150 | .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?), |
| 143 | .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?), | 151 | .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?), |
| 144 | .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?), | 152 | .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?), |
| ... | @@ -1104,48 +1112,109 @@ fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiter | ... | @@ -1104,48 +1112,109 @@ fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiter |
| 1104 | }); | 1112 | }); |
| 1105 | } | 1113 | } |
| 1106 | 1114 | ||
| 1107 | fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { | 1115 | /// Pointer in, pointer out. |
| 1116 | fn optionalPayloadPtr( | ||
| 1117 | mod: *Module, | ||
| 1118 | scope: *Scope, | ||
| 1119 | unwrap: *zir.Inst.UnOp, | ||
| 1120 | safety_check: bool, | ||
| 1121 | ) InnerError!*Inst { | ||
| 1108 | const tracy = trace(@src()); | 1122 | const tracy = trace(@src()); |
| 1109 | defer tracy.end(); | 1123 | defer tracy.end(); |
| 1110 | const operand = try resolveInst(mod, scope, unwrap.positionals.operand); | ||
| 1111 | assert(operand.ty.zigTypeTag() == .Pointer); | ||
| 1112 | 1124 | ||
| 1113 | const elem_type = operand.ty.elemType(); | 1125 | const optional_ptr = try resolveInst(mod, scope, unwrap.positionals.operand); |
| 1114 | if (elem_type.zigTypeTag() != .Optional) { | 1126 | assert(optional_ptr.ty.zigTypeTag() == .Pointer); |
| 1115 | return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{elem_type}); | 1127 | |
| 1128 | const opt_type = optional_ptr.ty.elemType(); | ||
| 1129 | if (opt_type.zigTypeTag() != .Optional) { | ||
| 1130 | return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{opt_type}); | ||
| 1116 | } | 1131 | } |
| 1117 | 1132 | ||
| 1118 | const child_type = try elem_type.optionalChildAlloc(scope.arena()); | 1133 | const child_type = try opt_type.optionalChildAlloc(scope.arena()); |
| 1119 | const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One); | 1134 | const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, !optional_ptr.ty.isConstPtr(), .One); |
| 1120 | 1135 | ||
| 1121 | if (operand.value()) |val| { | 1136 | if (optional_ptr.value()) |pointer_val| { |
| 1137 | const val = try pointer_val.pointerDeref(scope.arena()); | ||
| 1122 | if (val.isNull()) { | 1138 | if (val.isNull()) { |
| 1123 | return mod.fail(scope, unwrap.base.src, "unable to unwrap null", .{}); | 1139 | return mod.fail(scope, unwrap.base.src, "unable to unwrap null", .{}); |
| 1124 | } | 1140 | } |
| 1141 | // The same Value represents the pointer to the optional and the payload. | ||
| 1125 | return mod.constInst(scope, unwrap.base.src, .{ | 1142 | return mod.constInst(scope, unwrap.base.src, .{ |
| 1126 | .ty = child_pointer, | 1143 | .ty = child_pointer, |
| 1144 | .val = pointer_val, | ||
| 1145 | }); | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | const b = try mod.requireRuntimeBlock(scope, unwrap.base.src); | ||
| 1149 | if (safety_check and mod.wantSafety(scope)) { | ||
| 1150 | const is_non_null = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_non_null_ptr, optional_ptr); | ||
| 1151 | try mod.addSafetyCheck(b, is_non_null, .unwrap_null); | ||
| 1152 | } | ||
| 1153 | return mod.addUnOp(b, unwrap.base.src, child_pointer, .optional_payload_ptr, optional_ptr); | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | /// Value in, value out. | ||
| 1157 | fn optionalPayload( | ||
| 1158 | mod: *Module, | ||
| 1159 | scope: *Scope, | ||
| 1160 | unwrap: *zir.Inst.UnOp, | ||
| 1161 | safety_check: bool, | ||
| 1162 | ) InnerError!*Inst { | ||
| 1163 | const tracy = trace(@src()); | ||
| 1164 | defer tracy.end(); | ||
| 1165 | |||
| 1166 | const operand = try resolveInst(mod, scope, unwrap.positionals.operand); | ||
| 1167 | const opt_type = operand.ty; | ||
| 1168 | if (opt_type.zigTypeTag() != .Optional) { | ||
| 1169 | return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{opt_type}); | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | const child_type = try opt_type.optionalChildAlloc(scope.arena()); | ||
| 1173 | |||
| 1174 | if (operand.value()) |val| { | ||
| 1175 | if (val.isNull()) { | ||
| 1176 | return mod.fail(scope, unwrap.base.src, "unable to unwrap null", .{}); | ||
| 1177 | } | ||
| 1178 | return mod.constInst(scope, unwrap.base.src, .{ | ||
| 1179 | .ty = child_type, | ||
| 1127 | .val = val, | 1180 | .val = val, |
| 1128 | }); | 1181 | }); |
| 1129 | } | 1182 | } |
| 1130 | 1183 | ||
| 1131 | const b = try mod.requireRuntimeBlock(scope, unwrap.base.src); | 1184 | const b = try mod.requireRuntimeBlock(scope, unwrap.base.src); |
| 1132 | if (safety_check and mod.wantSafety(scope)) { | 1185 | if (safety_check and mod.wantSafety(scope)) { |
| 1133 | const is_non_null = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .isnonnull, operand); | 1186 | const is_non_null = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_non_null, operand); |
| 1134 | try mod.addSafetyCheck(b, is_non_null, .unwrap_null); | 1187 | try mod.addSafetyCheck(b, is_non_null, .unwrap_null); |
| 1135 | } | 1188 | } |
| 1136 | return mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional, operand); | 1189 | return mod.addUnOp(b, unwrap.base.src, child_type, .optional_payload, operand); |
| 1137 | } | 1190 | } |
| 1138 | 1191 | ||
| 1139 | fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { | 1192 | /// Value in, value out |
| 1193 | fn errorUnionPayload(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { | ||
| 1140 | const tracy = trace(@src()); | 1194 | const tracy = trace(@src()); |
| 1141 | defer tracy.end(); | 1195 | defer tracy.end(); |
| 1142 | return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{}); | 1196 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.errorUnionPayload", .{}); |
| 1143 | } | 1197 | } |
| 1144 | 1198 | ||
| 1145 | fn analyzeInstUnwrapErrCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | 1199 | /// Pointer in, pointer out |
| 1200 | fn errorUnionPayloadPtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { | ||
| 1146 | const tracy = trace(@src()); | 1201 | const tracy = trace(@src()); |
| 1147 | defer tracy.end(); | 1202 | defer tracy.end(); |
| 1148 | return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErrCode", .{}); | 1203 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.errorUnionPayloadPtr", .{}); |
| 1204 | } | ||
| 1205 | |||
| 1206 | /// Value in, value out | ||
| 1207 | fn errorUnionCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | ||
| 1208 | const tracy = trace(@src()); | ||
| 1209 | defer tracy.end(); | ||
| 1210 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.errorUnionCode", .{}); | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | /// Pointer in, value out | ||
| 1214 | fn errorUnionCodePtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | ||
| 1215 | const tracy = trace(@src()); | ||
| 1216 | defer tracy.end(); | ||
| 1217 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.errorUnionCodePtr", .{}); | ||
| 1149 | } | 1218 | } |
| 1150 | 1219 | ||
| 1151 | fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | 1220 | fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { |
| ... | @@ -2074,20 +2143,36 @@ fn analyzeInstBoolOp(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerEr | ... | @@ -2074,20 +2143,36 @@ fn analyzeInstBoolOp(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerEr |
| 2074 | return mod.addBinOp(b, inst.base.src, bool_type, if (is_bool_or) .boolor else .booland, lhs, rhs); | 2143 | return mod.addBinOp(b, inst.base.src, bool_type, if (is_bool_or) .boolor else .booland, lhs, rhs); |
| 2075 | } | 2144 | } |
| 2076 | 2145 | ||
| 2077 | fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst { | 2146 | fn isNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst { |
| 2078 | const tracy = trace(@src()); | 2147 | const tracy = trace(@src()); |
| 2079 | defer tracy.end(); | 2148 | defer tracy.end(); |
| 2080 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 2149 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| 2081 | return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic); | 2150 | return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic); |
| 2082 | } | 2151 | } |
| 2083 | 2152 | ||
| 2084 | fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 2153 | fn isNullPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst { |
| 2154 | const tracy = trace(@src()); | ||
| 2155 | defer tracy.end(); | ||
| 2156 | const ptr = try resolveInst(mod, scope, inst.positionals.operand); | ||
| 2157 | const loaded = try mod.analyzeDeref(scope, inst.base.src, ptr, ptr.src); | ||
| 2158 | return mod.analyzeIsNull(scope, inst.base.src, loaded, invert_logic); | ||
| 2159 | } | ||
| 2160 | |||
| 2161 | fn isErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | ||
| 2085 | const tracy = trace(@src()); | 2162 | const tracy = trace(@src()); |
| 2086 | defer tracy.end(); | 2163 | defer tracy.end(); |
| 2087 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | 2164 | const operand = try resolveInst(mod, scope, inst.positionals.operand); |
| 2088 | return mod.analyzeIsErr(scope, inst.base.src, operand); | 2165 | return mod.analyzeIsErr(scope, inst.base.src, operand); |
| 2089 | } | 2166 | } |
| 2090 | 2167 | ||
| 2168 | fn isErrPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | ||
| 2169 | const tracy = trace(@src()); | ||
| 2170 | defer tracy.end(); | ||
| 2171 | const ptr = try resolveInst(mod, scope, inst.positionals.operand); | ||
| 2172 | const loaded = try mod.analyzeDeref(scope, inst.base.src, ptr, ptr.src); | ||
| 2173 | return mod.analyzeIsErr(scope, inst.base.src, loaded); | ||
| 2174 | } | ||
| 2175 | |||
| 2091 | fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst { | 2176 | fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst { |
| 2092 | const tracy = trace(@src()); | 2177 | const tracy = trace(@src()); |
| 2093 | defer tracy.end(); | 2178 | defer tracy.end(); |
test/stage2/test.zig+47| ... | @@ -1462,4 +1462,51 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1462,4 +1462,51 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1462 | "", | 1462 | "", |
| 1463 | ); | 1463 | ); |
| 1464 | } | 1464 | } |
| 1465 | { | ||
| 1466 | var case = ctx.exe("orelse at comptime", linux_x64); | ||
| 1467 | case.addCompareOutput( | ||
| 1468 | \\export fn _start() noreturn { | ||
| 1469 | \\ const i: ?u64 = 0; | ||
| 1470 | \\ const orelsed = i orelse 5; | ||
| 1471 | \\ assert(orelsed == 0); | ||
| 1472 | \\ exit(); | ||
| 1473 | \\} | ||
| 1474 | \\fn assert(b: bool) void { | ||
| 1475 | \\ if (!b) unreachable; | ||
| 1476 | \\} | ||
| 1477 | \\fn exit() noreturn { | ||
| 1478 | \\ asm volatile ("syscall" | ||
| 1479 | \\ : | ||
| 1480 | \\ : [number] "{rax}" (231), | ||
| 1481 | \\ [arg1] "{rdi}" (0) | ||
| 1482 | \\ : "rcx", "r11", "memory" | ||
| 1483 | \\ ); | ||
| 1484 | \\ unreachable; | ||
| 1485 | \\} | ||
| 1486 | , | ||
| 1487 | "", | ||
| 1488 | ); | ||
| 1489 | case.addCompareOutput( | ||
| 1490 | \\export fn _start() noreturn { | ||
| 1491 | \\ const i: ?u64 = null; | ||
| 1492 | \\ const orelsed = i orelse 5; | ||
| 1493 | \\ assert(orelsed == 5); | ||
| 1494 | \\ exit(); | ||
| 1495 | \\} | ||
| 1496 | \\fn assert(b: bool) void { | ||
| 1497 | \\ if (!b) unreachable; | ||
| 1498 | \\} | ||
| 1499 | \\fn exit() noreturn { | ||
| 1500 | \\ asm volatile ("syscall" | ||
| 1501 | \\ : | ||
| 1502 | \\ : [number] "{rax}" (231), | ||
| 1503 | \\ [arg1] "{rdi}" (0) | ||
| 1504 | \\ : "rcx", "r11", "memory" | ||
| 1505 | \\ ); | ||
| 1506 | \\ unreachable; | ||
| 1507 | \\} | ||
| 1508 | , | ||
| 1509 | "", | ||
| 1510 | ); | ||
| 1511 | } | ||
| 1465 | } | 1512 | } |