authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-23 20:09:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-23 20:09:56-07:00
log9a271347fe1e302c132fa63bbe27bfffcf3b132d
tree6b001cfc452916b8ff32255b01051752302f58fe
parentb40a8efb9a72e69cd7e9061fc4c08d5e705b0fbd

AstGen: implement suspend blocks


3 files changed, 96 insertions(+), 5 deletions(-)

src/AstGen.zig+84-5
......@@ -827,10 +827,10 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
827827 .@"comptime" => return comptimeExpr(gz, scope, rl, node_datas[node].lhs),
828828 .@"switch", .switch_comma => return switchExpr(gz, scope, rl, node),
829829
830 .@"nosuspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
831 .@"suspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
832 .@"await" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
833 .@"resume" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
830 .@"nosuspend" => return nosuspendExpr(gz, scope, rl, node),
831 .@"suspend" => return suspendExpr(gz, scope, rl, node),
832 .@"await" => return awaitExpr(gz, scope, rl, node),
833 .@"resume" => return resumeExpr(gz, scope, rl, node),
834834
835835 .@"try" => return tryExpr(gz, scope, rl, node, node_datas[node].lhs),
836836
......@@ -883,6 +883,82 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
883883 }
884884}
885885
886pub fn nosuspendExpr(
887 gz: *GenZir,
888 scope: *Scope,
889 rl: ResultLoc,
890 node: ast.Node.Index,
891) InnerError!Zir.Inst.Ref {
892 const astgen = gz.astgen;
893 return astgen.failNode(node, "TODO AstGen nosuspendExpr", .{});
894}
895
896pub fn suspendExpr(
897 gz: *GenZir,
898 scope: *Scope,
899 rl: ResultLoc,
900 node: ast.Node.Index,
901) InnerError!Zir.Inst.Ref {
902 const astgen = gz.astgen;
903 const gpa = astgen.gpa;
904 const tree = &astgen.file.tree;
905 const node_datas = tree.nodes.items(.data);
906 const body_node = node_datas[node].lhs;
907
908 if (gz.nosuspend_node != 0) {
909 return astgen.failNodeNotes(node, "suspend inside nosuspend block", .{}, &[_]u32{
910 try astgen.errNoteNode(gz.nosuspend_node, "nosuspend block here", .{}),
911 });
912 }
913 if (gz.suspend_node != 0) {
914 return astgen.failNodeNotes(node, "cannot suspend inside suspend block", .{}, &[_]u32{
915 try astgen.errNoteNode(gz.suspend_node, "other suspend block here", .{}),
916 });
917 }
918 if (body_node == 0) {
919 // Accepted proposal to remove block-less suspend from the language:
920 // https://github.com/ziglang/zig/issues/8603
921 // TODO: simplify the parser and make this an assert instead of
922 // a compile error.
923 return astgen.failNode(node, "suspend without a block", .{});
924 }
925
926 const suspend_inst = try gz.addBlock(.suspend_block, node);
927 try gz.instructions.append(gpa, suspend_inst);
928
929 var suspend_scope = gz.makeSubBlock(scope);
930 suspend_scope.suspend_node = node;
931 defer suspend_scope.instructions.deinit(gpa);
932
933 const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node);
934 if (!gz.refIsNoReturn(body_result)) {
935 _ = try suspend_scope.addBreak(.break_inline, suspend_inst, .void_value);
936 }
937 try suspend_scope.setBlockBody(suspend_inst);
938
939 return gz.indexToRef(suspend_inst);
940}
941
942pub fn awaitExpr(
943 gz: *GenZir,
944 scope: *Scope,
945 rl: ResultLoc,
946 node: ast.Node.Index,
947) InnerError!Zir.Inst.Ref {
948 const astgen = gz.astgen;
949 return astgen.failNode(node, "TODO AstGen awaitExpr", .{});
950}
951
952pub fn resumeExpr(
953 gz: *GenZir,
954 scope: *Scope,
955 rl: ResultLoc,
956 node: ast.Node.Index,
957) InnerError!Zir.Inst.Ref {
958 const astgen = gz.astgen;
959 return astgen.failNode(node, "TODO AstGen resumeExpr", .{});
960}
961
886962pub fn fnProtoExpr(
887963 gz: *GenZir,
888964 scope: *Scope,
......@@ -1701,6 +1777,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
17011777 .block,
17021778 .block_inline,
17031779 .block_inline_var,
1780 .suspend_block,
17041781 .loop,
17051782 .bool_br_and,
17061783 .bool_br_or,
......@@ -4090,7 +4167,9 @@ fn boolBinOp(
40904167 var rhs_scope = gz.makeSubBlock(scope);
40914168 defer rhs_scope.instructions.deinit(gz.astgen.gpa);
40924169 const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs);
4093 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
4170 if (!gz.refIsNoReturn(rhs)) {
4171 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
4172 }
40944173 try rhs_scope.setBoolBrBody(bool_br);
40954174
40964175 const block_ref = gz.indexToRef(bool_br);
src/Sema.zig+7
......@@ -151,6 +151,7 @@ pub fn analyzeBody(
151151 .bitcast => try sema.zirBitcast(block, inst),
152152 .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
153153 .block => try sema.zirBlock(block, inst),
154 .suspend_block => try sema.zirSuspendBlock(block, inst),
154155 .bool_not => try sema.zirBoolNot(block, inst),
155156 .bool_and => try sema.zirBoolOp(block, inst, false),
156157 .bool_or => try sema.zirBoolOp(block, inst, true),
......@@ -1647,6 +1648,12 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Inn
16471648 return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{});
16481649}
16491650
1651fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1652 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1653 const src = inst_data.src();
1654 return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirSuspendBlock", .{});
1655}
1656
16501657fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
16511658 const tracy = trace(@src());
16521659 defer tracy.end();
src/Zir.zig+5
......@@ -199,6 +199,9 @@ pub const Inst = struct {
199199 block_inline,
200200 /// Same as `block_inline` but it additionally marks a decl as being a variable.
201201 block_inline_var,
202 /// Implements `suspend {...}`.
203 /// Uses the `pl_node` union field. Payload is `Block`.
204 suspend_block,
202205 /// Boolean AND. See also `bit_and`.
203206 /// Uses the `pl_node` union field. Payload is `Bin`.
204207 bool_and,
......@@ -975,6 +978,7 @@ pub const Inst = struct {
975978 .block,
976979 .block_inline,
977980 .block_inline_var,
981 .suspend_block,
978982 .loop,
979983 .bool_br_and,
980984 .bool_br_or,
......@@ -2541,6 +2545,7 @@ const Writer = struct {
25412545 .block,
25422546 .block_inline,
25432547 .block_inline_var,
2548 .suspend_block,
25442549 .loop,
25452550 .validate_struct_init_ptr,
25462551 .validate_array_init_ptr,