| author | |
| committer | |
| log | fb28349349483c5e1c9523b19c2158cb465cf4e9 |
| tree | 9943dadd549168087d653d2145642f4752736539 |
| parent | bf014d529a8373d43f92b0dd5c8a5d8509150ca9 |
4 files changed, 120 insertions(+), 22 deletions(-)
src-self-hosted/Module.zig+11-1| ... | ... | @@ -2570,7 +2570,17 @@ pub fn analyzeIsNull( |
| 2570 | 2570 | operand: *Inst, |
| 2571 | 2571 | invert_logic: bool, |
| 2572 | 2572 | ) InnerError!*Inst { |
| 2573 | return self.fail(scope, src, "TODO implement analysis of isnull and isnotnull", .{}); | |
| 2573 | if (operand.value()) |opt_val| { | |
| 2574 | const is_null = opt_val.isNull(); | |
| 2575 | return self.constBool(scope, src, invert_logic); | |
| 2576 | } | |
| 2577 | const b = try self.requireRuntimeBlock(scope, src); | |
| 2578 | const inst_tag: Inst.Tag = if (invert_logic) .isnonnull else .isnull; | |
| 2579 | return self.addUnOp(b, src, Type.initTag(.bool), inst_tag, operand); | |
| 2580 | } | |
| 2581 | ||
| 2582 | pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst { | |
| 2583 | return self.fail(scope, src, "TODO implement analysis of iserr", .{}); | |
| 2574 | 2584 | } |
| 2575 | 2585 | |
| 2576 | 2586 | /// Asserts that lhs and rhs types are both numeric. |
src-self-hosted/astgen.zig+90-4| ... | ... | @@ -275,9 +275,9 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 275 | 275 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), |
| 276 | 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 277 | 277 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), |
| 278 | .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), | |
| 278 | 279 | |
| 279 | 280 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 280 | .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), | |
| 281 | 281 | .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}), |
| 282 | 282 | .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}), |
| 283 | 283 | .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}), |
| ... | ... | @@ -750,6 +750,93 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!* |
| 750 | 750 | }); |
| 751 | 751 | } |
| 752 | 752 | |
| 753 | fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst { | |
| 754 | const tree = scope.tree(); | |
| 755 | const src = tree.token_locs[node.op_token].start; | |
| 756 | ||
| 757 | const err_union_ptr = try expr(mod, scope, .ref, node.lhs); | |
| 758 | // TODO we could avoid an unnecessary copy if .iserr took a pointer | |
| 759 | const err_union = try addZIRUnOp(mod, scope, src, .deref, err_union_ptr); | |
| 760 | const cond = try addZIRUnOp(mod, scope, src, .iserr, err_union); | |
| 761 | ||
| 762 | var block_scope: Scope.GenZIR = .{ | |
| 763 | .parent = scope, | |
| 764 | .decl = scope.decl().?, | |
| 765 | .arena = scope.arena(), | |
| 766 | .instructions = .{}, | |
| 767 | }; | |
| 768 | defer block_scope.instructions.deinit(mod.gpa); | |
| 769 | ||
| 770 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ | |
| 771 | .condition = cond, | |
| 772 | .then_body = undefined, // populated below | |
| 773 | .else_body = undefined, // populated below | |
| 774 | }, .{}); | |
| 775 | ||
| 776 | const block = try addZIRInstBlock(mod, scope, src, .{ | |
| 777 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | |
| 778 | }); | |
| 779 | ||
| 780 | // Most result location types can be forwarded directly; however | |
| 781 | // if we need to write to a pointer which has an inferred type, | |
| 782 | // proper type inference requires peer type resolution on the if's | |
| 783 | // branches. | |
| 784 | const branch_rl: ResultLoc = switch (rl) { | |
| 785 | .discard, .none, .ty, .ptr, .ref => rl, | |
| 786 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, | |
| 787 | }; | |
| 788 | ||
| 789 | var err_scope: Scope.GenZIR = .{ | |
| 790 | .parent = scope, | |
| 791 | .decl = block_scope.decl, | |
| 792 | .arena = block_scope.arena, | |
| 793 | .instructions = .{}, | |
| 794 | }; | |
| 795 | defer err_scope.instructions.deinit(mod.gpa); | |
| 796 | ||
| 797 | var err_val_scope: Scope.LocalVal = undefined; | |
| 798 | const err_sub_scope = blk: { | |
| 799 | const payload = node.payload orelse | |
| 800 | break :blk &err_scope.base; | |
| 801 | ||
| 802 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); | |
| 803 | if (mem.eql(u8, err_name, "_")) | |
| 804 | break :blk &err_scope.base; | |
| 805 | ||
| 806 | const unwrapped_err_ptr = try addZIRUnOp(mod, &err_scope.base, src, .unwrap_err_code, err_union_ptr); | |
| 807 | err_val_scope = .{ | |
| 808 | .parent = &err_scope.base, | |
| 809 | .gen_zir = &err_scope, | |
| 810 | .name = err_name, | |
| 811 | .inst = try addZIRUnOp(mod, &err_scope.base, src, .deref, unwrapped_err_ptr), | |
| 812 | }; | |
| 813 | break :blk &err_val_scope.base; | |
| 814 | }; | |
| 815 | ||
| 816 | _ = try addZIRInst(mod, &err_scope.base, src, zir.Inst.Break, .{ | |
| 817 | .block = block, | |
| 818 | .operand = try expr(mod, err_sub_scope, branch_rl, node.rhs), | |
| 819 | }, .{}); | |
| 820 | ||
| 821 | var not_err_scope: Scope.GenZIR = .{ | |
| 822 | .parent = scope, | |
| 823 | .decl = block_scope.decl, | |
| 824 | .arena = block_scope.arena, | |
| 825 | .instructions = .{}, | |
| 826 | }; | |
| 827 | defer not_err_scope.instructions.deinit(mod.gpa); | |
| 828 | ||
| 829 | const unwrapped_payload = try addZIRUnOp(mod, &not_err_scope.base, src, .unwrap_err_unsafe, err_union_ptr); | |
| 830 | _ = try addZIRInst(mod, &not_err_scope.base, src, zir.Inst.Break, .{ | |
| 831 | .block = block, | |
| 832 | .operand = unwrapped_payload, | |
| 833 | }, .{}); | |
| 834 | ||
| 835 | condbr.positionals.then_body = .{ .instructions = try err_scope.arena.dupe(*zir.Inst, err_scope.instructions.items) }; | |
| 836 | condbr.positionals.else_body = .{ .instructions = try not_err_scope.arena.dupe(*zir.Inst, not_err_scope.instructions.items) }; | |
| 837 | return rlWrap(mod, scope, rl, &block.base); | |
| 838 | } | |
| 839 | ||
| 753 | 840 | /// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating. |
| 754 | 841 | /// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used. |
| 755 | 842 | fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { |
| ... | ... | @@ -1317,7 +1404,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1317 | 1404 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block }, |
| 1318 | 1405 | }; |
| 1319 | 1406 | |
| 1320 | var index_scope: Scope.LocalPtr = undefined; | |
| 1407 | var index_scope: Scope.LocalVal = undefined; | |
| 1321 | 1408 | const then_sub_scope = blk: { |
| 1322 | 1409 | const payload = for_node.payload.castTag(.PointerIndexPayload).?; |
| 1323 | 1410 | const is_ptr = payload.ptr_token != null; |
| ... | ... | @@ -1335,12 +1422,11 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1335 | 1422 | if (mem.eql(u8, index_name, "_")) { |
| 1336 | 1423 | break :blk &then_scope.base; |
| 1337 | 1424 | } |
| 1338 | // TODO ensure this is const | |
| 1339 | 1425 | index_scope = .{ |
| 1340 | 1426 | .parent = &then_scope.base, |
| 1341 | 1427 | .gen_zir = &then_scope, |
| 1342 | 1428 | .name = index_name, |
| 1343 | .ptr = index_ptr, | |
| 1429 | .inst = index, | |
| 1344 | 1430 | }; |
| 1345 | 1431 | break :blk &index_scope.base; |
| 1346 | 1432 | }; |
src-self-hosted/zir.zig+4| ... | ... | @@ -253,6 +253,8 @@ pub const Inst = struct { |
| 253 | 253 | unwrap_err_safe, |
| 254 | 254 | /// Same as previous, but without safety checks. Used for orelse, if and while |
| 255 | 255 | unwrap_err_unsafe, |
| 256 | /// Gets the error code value of an error union | |
| 257 | unwrap_err_code, | |
| 256 | 258 | /// Takes a *E!T and raises a compiler error if T != void |
| 257 | 259 | ensure_err_payload_void, |
| 258 | 260 | /// Enum literal |
| ... | ... | @@ -298,6 +300,7 @@ pub const Inst = struct { |
| 298 | 300 | .unwrap_optional_unsafe, |
| 299 | 301 | .unwrap_err_safe, |
| 300 | 302 | .unwrap_err_unsafe, |
| 303 | .unwrap_err_code, | |
| 301 | 304 | .ensure_err_payload_void, |
| 302 | 305 | .anyframe_type, |
| 303 | 306 | .bitnot, |
| ... | ... | @@ -454,6 +457,7 @@ pub const Inst = struct { |
| 454 | 457 | .unwrap_optional_unsafe, |
| 455 | 458 | .unwrap_err_safe, |
| 456 | 459 | .unwrap_err_unsafe, |
| 460 | .unwrap_err_code, | |
| 457 | 461 | .ptr_type, |
| 458 | 462 | .ensure_err_payload_void, |
| 459 | 463 | .enum_literal, |
src-self-hosted/zir_sema.zig+15-17| ... | ... | @@ -120,6 +120,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 120 | 120 | .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false), |
| 121 | 121 | .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true), |
| 122 | 122 | .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false), |
| 123 | .unwrap_err_code => return analyzeInstUnwrapErrCode(mod, scope, old_inst.castTag(.unwrap_err_code).?), | |
| 123 | 124 | .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?), |
| 124 | 125 | .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?), |
| 125 | 126 | .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?), |
| ... | ... | @@ -800,11 +801,12 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp |
| 800 | 801 | const operand = try resolveInst(mod, scope, unwrap.positionals.operand); |
| 801 | 802 | assert(operand.ty.zigTypeTag() == .Pointer); |
| 802 | 803 | |
| 803 | if (operand.ty.elemType().zigTypeTag() != .Optional) { | |
| 804 | return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{operand.ty.elemType()}); | |
| 804 | const elem_type = operand.ty.elemType(); | |
| 805 | if (elem_type.zigTypeTag() != .Optional) { | |
| 806 | return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{elem_type}); | |
| 805 | 807 | } |
| 806 | 808 | |
| 807 | const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena()); | |
| 809 | const child_type = try elem_type.optionalChildAlloc(scope.arena()); | |
| 808 | 810 | const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One); |
| 809 | 811 | |
| 810 | 812 | if (operand.value()) |val| { |
| ... | ... | @@ -829,6 +831,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf |
| 829 | 831 | return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{}); |
| 830 | 832 | } |
| 831 | 833 | |
| 834 | fn analyzeInstUnwrapErrCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | |
| 835 | return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErrCode", .{}); | |
| 836 | } | |
| 837 | ||
| 832 | 838 | fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { |
| 833 | 839 | return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{}); |
| 834 | 840 | } |
| ... | ... | @@ -964,7 +970,8 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr |
| 964 | 970 | const entry = if (val.cast(Value.Payload.ErrorSet)) |payload| |
| 965 | 971 | (payload.fields.getEntry(field_name) orelse |
| 966 | 972 | return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).* |
| 967 | else try mod.getErrorValue(field_name); | |
| 973 | else | |
| 974 | try mod.getErrorValue(field_name); | |
| 968 | 975 | |
| 969 | 976 | const error_payload = try scope.arena().create(Value.Payload.Error); |
| 970 | 977 | error_payload.* = .{ |
| ... | ... | @@ -1298,17 +1305,7 @@ fn analyzeInstCmp( |
| 1298 | 1305 | { |
| 1299 | 1306 | // comparing null with optionals |
| 1300 | 1307 | const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs; |
| 1301 | if (opt_operand.value()) |opt_val| { | |
| 1302 | const is_null = opt_val.isNull(); | |
| 1303 | return mod.constBool(scope, inst.base.src, if (op == .eq) is_null else !is_null); | |
| 1304 | } | |
| 1305 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | |
| 1306 | const inst_tag: Inst.Tag = switch (op) { | |
| 1307 | .eq => .isnull, | |
| 1308 | .neq => .isnonnull, | |
| 1309 | else => unreachable, | |
| 1310 | }; | |
| 1311 | return mod.addUnOp(b, inst.base.src, Type.initTag(.bool), inst_tag, opt_operand); | |
| 1308 | return mod.analyzeIsNull(scope, inst.base.src, opt_operand, op == .neq); | |
| 1312 | 1309 | } else if (is_equality_cmp and |
| 1313 | 1310 | ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr()))) |
| 1314 | 1311 | { |
| ... | ... | @@ -1356,8 +1353,9 @@ fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, inver |
| 1356 | 1353 | return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic); |
| 1357 | 1354 | } |
| 1358 | 1355 | |
| 1359 | fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst { | |
| 1360 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstIsErr", .{}); | |
| 1356 | fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 1357 | const operand = try resolveInst(mod, scope, inst.positionals.operand); | |
| 1358 | return mod.analyzeIsErr(scope, inst.base.src, operand); | |
| 1361 | 1359 | } |
| 1362 | 1360 | |
| 1363 | 1361 | fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst { |