authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-26 12:34:41+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-26 19:50:56-07:00
logfb28349349483c5e1c9523b19c2158cb465cf4e9
tree9943dadd549168087d653d2145642f4752736539
parentbf014d529a8373d43f92b0dd5c8a5d8509150ca9

stage2: astgen catch


4 files changed, 120 insertions(+), 22 deletions(-)

src-self-hosted/Module.zig+11-1
...@@ -2570,7 +2570,17 @@ pub fn analyzeIsNull(...@@ -2570,7 +2570,17 @@ pub fn analyzeIsNull(
2570 operand: *Inst,2570 operand: *Inst,
2571 invert_logic: bool,2571 invert_logic: bool,
2572) InnerError!*Inst {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
2582pub 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}
25752585
2576/// Asserts that lhs and rhs types are both numeric.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,9 +275,9 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
275 .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),275 .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),
276 .For => return forExpr(mod, scope, rl, node.castTag(.For).?),276 .For => return forExpr(mod, scope, rl, node.castTag(.For).?),
277 .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),277 .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
278 .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),
278279
279 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),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 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),281 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
282 .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),282 .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),
283 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),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,6 +750,93 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*
750 });750 });
751}751}
752752
753fn 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/// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.840/// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.
754/// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used.841/// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used.
755fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {842fn 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,7 +1404,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
1317 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block },1404 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block },
1318 };1405 };
13191406
1320 var index_scope: Scope.LocalPtr = undefined;1407 var index_scope: Scope.LocalVal = undefined;
1321 const then_sub_scope = blk: {1408 const then_sub_scope = blk: {
1322 const payload = for_node.payload.castTag(.PointerIndexPayload).?;1409 const payload = for_node.payload.castTag(.PointerIndexPayload).?;
1323 const is_ptr = payload.ptr_token != null;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,12 +1422,11 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
1335 if (mem.eql(u8, index_name, "_")) {1422 if (mem.eql(u8, index_name, "_")) {
1336 break :blk &then_scope.base;1423 break :blk &then_scope.base;
1337 }1424 }
1338 // TODO ensure this is const
1339 index_scope = .{1425 index_scope = .{
1340 .parent = &then_scope.base,1426 .parent = &then_scope.base,
1341 .gen_zir = &then_scope,1427 .gen_zir = &then_scope,
1342 .name = index_name,1428 .name = index_name,
1343 .ptr = index_ptr,1429 .inst = index,
1344 };1430 };
1345 break :blk &index_scope.base;1431 break :blk &index_scope.base;
1346 };1432 };
src-self-hosted/zir.zig+4
...@@ -253,6 +253,8 @@ pub const Inst = struct {...@@ -253,6 +253,8 @@ pub const Inst = struct {
253 unwrap_err_safe,253 unwrap_err_safe,
254 /// Same as previous, but without safety checks. Used for orelse, if and while254 /// Same as previous, but without safety checks. Used for orelse, if and while
255 unwrap_err_unsafe,255 unwrap_err_unsafe,
256 /// Gets the error code value of an error union
257 unwrap_err_code,
256 /// Takes a *E!T and raises a compiler error if T != void258 /// Takes a *E!T and raises a compiler error if T != void
257 ensure_err_payload_void,259 ensure_err_payload_void,
258 /// Enum literal260 /// Enum literal
...@@ -298,6 +300,7 @@ pub const Inst = struct {...@@ -298,6 +300,7 @@ pub const Inst = struct {
298 .unwrap_optional_unsafe,300 .unwrap_optional_unsafe,
299 .unwrap_err_safe,301 .unwrap_err_safe,
300 .unwrap_err_unsafe,302 .unwrap_err_unsafe,
303 .unwrap_err_code,
301 .ensure_err_payload_void,304 .ensure_err_payload_void,
302 .anyframe_type,305 .anyframe_type,
303 .bitnot,306 .bitnot,
...@@ -454,6 +457,7 @@ pub const Inst = struct {...@@ -454,6 +457,7 @@ pub const Inst = struct {
454 .unwrap_optional_unsafe,457 .unwrap_optional_unsafe,
455 .unwrap_err_safe,458 .unwrap_err_safe,
456 .unwrap_err_unsafe,459 .unwrap_err_unsafe,
460 .unwrap_err_code,
457 .ptr_type,461 .ptr_type,
458 .ensure_err_payload_void,462 .ensure_err_payload_void,
459 .enum_literal,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,6 +120,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
120 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),120 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
121 .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),121 .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),
122 .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),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 .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),124 .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),
124 .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),125 .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),
125 .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),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,11 +801,12 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
800 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);801 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
801 assert(operand.ty.zigTypeTag() == .Pointer);802 assert(operand.ty.zigTypeTag() == .Pointer);
802803
803 if (operand.ty.elemType().zigTypeTag() != .Optional) {804 const elem_type = operand.ty.elemType();
804 return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{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 }
806808
807 const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena());809 const child_type = try elem_type.optionalChildAlloc(scope.arena());
808 const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One);810 const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One);
809811
810 if (operand.value()) |val| {812 if (operand.value()) |val| {
...@@ -829,6 +831,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf...@@ -829,6 +831,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf
829 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});831 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});
830}832}
831833
834fn analyzeInstUnwrapErrCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
835 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErrCode", .{});
836}
837
832fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {838fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
833 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{});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,7 +970,8 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
964 const entry = if (val.cast(Value.Payload.ErrorSet)) |payload|970 const entry = if (val.cast(Value.Payload.ErrorSet)) |payload|
965 (payload.fields.getEntry(field_name) orelse971 (payload.fields.getEntry(field_name) orelse
966 return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).*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);
968975
969 const error_payload = try scope.arena().create(Value.Payload.Error);976 const error_payload = try scope.arena().create(Value.Payload.Error);
970 error_payload.* = .{977 error_payload.* = .{
...@@ -1298,17 +1305,7 @@ fn analyzeInstCmp(...@@ -1298,17 +1305,7 @@ fn analyzeInstCmp(
1298 {1305 {
1299 // comparing null with optionals1306 // comparing null with optionals
1300 const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;1307 const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;
1301 if (opt_operand.value()) |opt_val| {1308 return mod.analyzeIsNull(scope, inst.base.src, opt_operand, op == .neq);
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);
1312 } else if (is_equality_cmp and1309 } else if (is_equality_cmp and
1313 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))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,8 +1353,9 @@ fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, inver
1356 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);1353 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);
1357}1354}
13581355
1359fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst {1356fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1360 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstIsErr", .{});1357 const operand = try resolveInst(mod, scope, inst.positionals.operand);
1358 return mod.analyzeIsErr(scope, inst.base.src, operand);
1361}1359}
13621360
1363fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {1361fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {