authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-15 19:39:11+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-17 14:28:04+03:00
logece4a2fc512bffba3845bf611370f5ea436c57b4
tree1d47367746a091edeb84b95077e53862bd8fcadb
parentdb77b6b4e731670188e632657aa0aeadf9c87eb5
signaturelock-open Commit is signed but in an unrecognized format.

stage2: astgen for if and while with error unions


5 files changed, 75 insertions(+), 14 deletions(-)

src-self-hosted/astgen.zig+42-14
......@@ -614,11 +614,16 @@ const CondKind = union(enum) {
614614 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);
615615 return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result);
616616 },
617 .err_union => unreachable,
617 .err_union => {
618 const err_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);
619 self.* = .{ .err_union = err_ptr };
620 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr);
621 return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result);
622 },
618623 }
619624 }
620625
621 fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, payload_node: ?*ast.Node) !*Scope {
626 fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
622627 if (self == .bool) return &then_scope.base;
623628
624629 const payload = payload_node.?.castTag(.PointerPayload).?;
......@@ -633,6 +638,21 @@ const CondKind = union(enum) {
633638
634639 return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement payload symbols", .{});
635640 }
641
642 fn elseSubScope(self: CondKind, mod: *Module, else_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
643 if (self != .err_union) return &else_scope.base;
644
645 const payload_ptr = try addZIRUnOp(mod, &else_scope.base, src, .unwrap_err_unsafe, self.err_union.?);
646
647 const payload = payload_node.?.castTag(.Payload).?;
648 const ident_node = payload.error_symbol.castTag(.Identifier).?;
649 const ident_name = try identifierTokenString(mod, &else_scope.base, ident_node.token);
650 if (mem.eql(u8, ident_name, "_")) {
651 return &else_scope.base;
652 }
653
654 return mod.failNode(&else_scope.base, payload.error_symbol, "TODO implement payload symbols", .{});
655 }
636656};
637657
638658fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst {
......@@ -643,7 +663,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
643663 if (cond_kind != .optional) {
644664 return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{});
645665 }
646 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for error unions", .{});
666 cond_kind = .{ .err_union = null };
647667 }
648668 }
649669 var block_scope: Scope.GenZIR = .{
......@@ -667,6 +687,8 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
667687 const block = try addZIRInstBlock(mod, scope, if_src, .{
668688 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
669689 });
690
691 const then_src = tree.token_locs[if_node.body.lastToken()].start;
670692 var then_scope: Scope.GenZIR = .{
671693 .parent = scope,
672694 .decl = block_scope.decl,
......@@ -676,7 +698,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
676698 defer then_scope.instructions.deinit(mod.gpa);
677699
678700 // declare payload to the then_scope
679 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, if_node.payload);
701 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, if_node.payload);
680702
681703 // Most result location types can be forwarded directly; however
682704 // if we need to write to a pointer which has an inferred type,
......@@ -689,7 +711,6 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
689711
690712 const then_result = try expr(mod, then_sub_scope, branch_rl, if_node.body);
691713 if (!then_result.tag.isNoReturn()) {
692 const then_src = tree.token_locs[if_node.body.lastToken()].start;
693714 _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
694715 .block = block,
695716 .operand = then_result,
......@@ -708,10 +729,13 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
708729 defer else_scope.instructions.deinit(mod.gpa);
709730
710731 if (if_node.@"else") |else_node| {
711 const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body);
732 const else_src = tree.token_locs[else_node.body.lastToken()].start;
733 // declare payload to the then_scope
734 const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload);
735
736 const else_result = try expr(mod, else_sub_scope, branch_rl, else_node.body);
712737 if (!else_result.tag.isNoReturn()) {
713 const else_src = tree.token_locs[else_node.body.lastToken()].start;
714 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{
738 _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{
715739 .block = block,
716740 .operand = else_result,
717741 }, .{});
......@@ -739,7 +763,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
739763 if (cond_kind != .optional) {
740764 return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{});
741765 }
742 return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for error unions", .{});
766 cond_kind = .{ .err_union = null };
743767 }
744768 }
745769
......@@ -796,6 +820,8 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
796820 const while_block = try addZIRInstBlock(mod, scope, while_src, .{
797821 .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items),
798822 });
823
824 const then_src = tree.token_locs[while_node.body.lastToken()].start;
799825 var then_scope: Scope.GenZIR = .{
800826 .parent = &continue_scope.base,
801827 .decl = continue_scope.decl,
......@@ -805,7 +831,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
805831 defer then_scope.instructions.deinit(mod.gpa);
806832
807833 // declare payload to the then_scope
808 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, while_node.payload);
834 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, while_node.payload);
809835
810836 // Most result location types can be forwarded directly; however
811837 // if we need to write to a pointer which has an inferred type,
......@@ -818,7 +844,6 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
818844
819845 const then_result = try expr(mod, then_sub_scope, branch_rl, while_node.body);
820846 if (!then_result.tag.isNoReturn()) {
821 const then_src = tree.token_locs[while_node.body.lastToken()].start;
822847 _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
823848 .block = cond_block,
824849 .operand = then_result,
......@@ -837,10 +862,13 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
837862 defer else_scope.instructions.deinit(mod.gpa);
838863
839864 if (while_node.@"else") |else_node| {
840 const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body);
865 const else_src = tree.token_locs[else_node.body.lastToken()].start;
866 // declare payload to the then_scope
867 const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload);
868
869 const else_result = try expr(mod, else_sub_scope, branch_rl, else_node.body);
841870 if (!else_result.tag.isNoReturn()) {
842 const else_src = tree.token_locs[else_node.body.lastToken()].start;
843 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{
871 _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{
844872 .block = while_block,
845873 .operand = else_result,
846874 }, .{});
src-self-hosted/codegen.zig+7
......@@ -671,6 +671,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
671671 .intcast => return self.genIntCast(inst.castTag(.intcast).?),
672672 .isnonnull => return self.genIsNonNull(inst.castTag(.isnonnull).?),
673673 .isnull => return self.genIsNull(inst.castTag(.isnull).?),
674 .iserr => return self.genIsErr(inst.castTag(.iserr).?),
674675 .load => return self.genLoad(inst.castTag(.load).?),
675676 .loop => return self.genLoop(inst.castTag(.loop).?),
676677 .not => return self.genNot(inst.castTag(.not).?),
......@@ -1391,6 +1392,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13911392 }
13921393 }
13931394
1395 fn genIsErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1396 switch (arch) {
1397 else => return self.fail(inst.base.src, "TODO implement iserr for {}", .{self.target.cpu.arch}),
1398 }
1399 }
1400
13941401 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {
13951402 // A loop is a setup to be able to jump back to the beginning.
13961403 const start_index = self.code.items.len;
src-self-hosted/ir.zig+2
......@@ -68,6 +68,7 @@ pub const Inst = struct {
6868 dbg_stmt,
6969 isnonnull,
7070 isnull,
71 iserr,
7172 /// Read a value from a pointer.
7273 load,
7374 loop,
......@@ -100,6 +101,7 @@ pub const Inst = struct {
100101 .not,
101102 .isnonnull,
102103 .isnull,
104 .iserr,
103105 .ptrtoint,
104106 .floatcast,
105107 .intcast,
src-self-hosted/zir.zig+13
......@@ -151,6 +151,8 @@ pub const Inst = struct {
151151 isnonnull,
152152 /// Return a boolean true if an optional is null. `x == null`
153153 isnull,
154 /// Return a boolean true if value is an error
155 iserr,
154156 /// A labeled block of code that loops forever. At the end of the body it is implied
155157 /// to repeat; no explicit "repeat" instruction terminates loop bodies.
156158 loop,
......@@ -219,6 +221,10 @@ pub const Inst = struct {
219221 unwrap_optional_safe,
220222 /// Same as previous, but without safety checks. Used for orelse, if and while
221223 unwrap_optional_unsafe,
224 /// Gets the payload of an error union
225 unwrap_err_safe,
226 /// Same as previous, but without safety checks. Used for orelse, if and while
227 unwrap_err_unsafe,
222228
223229 pub fn Type(tag: Tag) type {
224230 return switch (tag) {
......@@ -237,6 +243,7 @@ pub const Inst = struct {
237243 .@"return",
238244 .isnull,
239245 .isnonnull,
246 .iserr,
240247 .ptrtoint,
241248 .alloc,
242249 .ensure_result_used,
......@@ -250,6 +257,8 @@ pub const Inst = struct {
250257 .optional_type,
251258 .unwrap_optional_safe,
252259 .unwrap_optional_unsafe,
260 .unwrap_err_safe,
261 .unwrap_err_unsafe,
253262 => UnOp,
254263
255264 .add,
......@@ -363,6 +372,7 @@ pub const Inst = struct {
363372 .inttype,
364373 .isnonnull,
365374 .isnull,
375 .iserr,
366376 .mod_rem,
367377 .mul,
368378 .mulwrap,
......@@ -385,6 +395,8 @@ pub const Inst = struct {
385395 .optional_type,
386396 .unwrap_optional_safe,
387397 .unwrap_optional_unsafe,
398 .unwrap_err_safe,
399 .unwrap_err_unsafe,
388400 .ptr_type,
389401 => false,
390402
......@@ -2014,6 +2026,7 @@ const EmitZIR = struct {
20142026 .ptrtoint => try self.emitUnOp(inst.src, new_body, inst.castTag(.ptrtoint).?, .ptrtoint),
20152027 .isnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnull).?, .isnull),
20162028 .isnonnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnonnull).?, .isnonnull),
2029 .iserr => try self.emitUnOp(inst.src, new_body, inst.castTag(.iserr).?, .iserr),
20172030 .load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref),
20182031 .ref => try self.emitUnOp(inst.src, new_body, inst.castTag(.ref).?, .ref),
20192032 .unwrap_optional => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional).?, .unwrap_optional_unsafe),
src-self-hosted/zir_sema.zig+11
......@@ -104,11 +104,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
104104 .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?),
105105 .isnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnull).?, true),
106106 .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false),
107 .iserr => return analyzeInstIsErr(mod, scope, old_inst.castTag(.iserr).?, true),
107108 .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),
108109 .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),
109110 .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
110111 .unwrap_optional_safe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_safe).?, true),
111112 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
113 .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),
114 .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),
112115 }
113116}
114117
......@@ -729,6 +732,10 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
729732 return mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional, operand);
730733}
731734
735fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {
736 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});
737}
738
732739fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
733740 const return_type = try resolveType(mod, scope, fntype.positionals.return_type);
734741
......@@ -1169,6 +1176,10 @@ fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, inver
11691176 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);
11701177}
11711178
1179fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst {
1180 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstIsErr", .{});
1181}
1182
11721183fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {
11731184 const uncasted_cond = try resolveInst(mod, scope, inst.positionals.condition);
11741185 const cond = try mod.coerce(scope, Type.initTag(.bool), uncasted_cond);