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...@@ -827,10 +827,10 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
827 .@"comptime" => return comptimeExpr(gz, scope, rl, node_datas[node].lhs),827 .@"comptime" => return comptimeExpr(gz, scope, rl, node_datas[node].lhs),
828 .@"switch", .switch_comma => return switchExpr(gz, scope, rl, node),828 .@"switch", .switch_comma => return switchExpr(gz, scope, rl, node),
829829
830 .@"nosuspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),830 .@"nosuspend" => return nosuspendExpr(gz, scope, rl, node),
831 .@"suspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),831 .@"suspend" => return suspendExpr(gz, scope, rl, node),
832 .@"await" => return astgen.failNode(node, "async and related features are not yet supported", .{}),832 .@"await" => return awaitExpr(gz, scope, rl, node),
833 .@"resume" => return astgen.failNode(node, "async and related features are not yet supported", .{}),833 .@"resume" => return resumeExpr(gz, scope, rl, node),
834834
835 .@"try" => return tryExpr(gz, scope, rl, node, node_datas[node].lhs),835 .@"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...@@ -883,6 +883,82 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
883 }883 }
884}884}
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
886pub fn fnProtoExpr(962pub fn fnProtoExpr(
887 gz: *GenZir,963 gz: *GenZir,
888 scope: *Scope,964 scope: *Scope,
...@@ -1701,6 +1777,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -1701,6 +1777,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
1701 .block,1777 .block,
1702 .block_inline,1778 .block_inline,
1703 .block_inline_var,1779 .block_inline_var,
1780 .suspend_block,
1704 .loop,1781 .loop,
1705 .bool_br_and,1782 .bool_br_and,
1706 .bool_br_or,1783 .bool_br_or,
...@@ -4090,7 +4167,9 @@ fn boolBinOp(...@@ -4090,7 +4167,9 @@ fn boolBinOp(
4090 var rhs_scope = gz.makeSubBlock(scope);4167 var rhs_scope = gz.makeSubBlock(scope);
4091 defer rhs_scope.instructions.deinit(gz.astgen.gpa);4168 defer rhs_scope.instructions.deinit(gz.astgen.gpa);
4092 const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs);4169 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 }
4094 try rhs_scope.setBoolBrBody(bool_br);4173 try rhs_scope.setBoolBrBody(bool_br);
40954174
4096 const block_ref = gz.indexToRef(bool_br);4175 const block_ref = gz.indexToRef(bool_br);
src/Sema.zig+7
...@@ -151,6 +151,7 @@ pub fn analyzeBody(...@@ -151,6 +151,7 @@ pub fn analyzeBody(
151 .bitcast => try sema.zirBitcast(block, inst),151 .bitcast => try sema.zirBitcast(block, inst),
152 .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),152 .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
153 .block => try sema.zirBlock(block, inst),153 .block => try sema.zirBlock(block, inst),
154 .suspend_block => try sema.zirSuspendBlock(block, inst),
154 .bool_not => try sema.zirBoolNot(block, inst),155 .bool_not => try sema.zirBoolNot(block, inst),
155 .bool_and => try sema.zirBoolOp(block, inst, false),156 .bool_and => try sema.zirBoolOp(block, inst, false),
156 .bool_or => try sema.zirBoolOp(block, inst, true),157 .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...@@ -1647,6 +1648,12 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Inn
1647 return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{});1648 return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{});
1648}1649}
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
1650fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {1657fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1651 const tracy = trace(@src());1658 const tracy = trace(@src());
1652 defer tracy.end();1659 defer tracy.end();
src/Zir.zig+5
...@@ -199,6 +199,9 @@ pub const Inst = struct {...@@ -199,6 +199,9 @@ pub const Inst = struct {
199 block_inline,199 block_inline,
200 /// Same as `block_inline` but it additionally marks a decl as being a variable.200 /// Same as `block_inline` but it additionally marks a decl as being a variable.
201 block_inline_var,201 block_inline_var,
202 /// Implements `suspend {...}`.
203 /// Uses the `pl_node` union field. Payload is `Block`.
204 suspend_block,
202 /// Boolean AND. See also `bit_and`.205 /// Boolean AND. See also `bit_and`.
203 /// Uses the `pl_node` union field. Payload is `Bin`.206 /// Uses the `pl_node` union field. Payload is `Bin`.
204 bool_and,207 bool_and,
...@@ -975,6 +978,7 @@ pub const Inst = struct {...@@ -975,6 +978,7 @@ pub const Inst = struct {
975 .block,978 .block,
976 .block_inline,979 .block_inline,
977 .block_inline_var,980 .block_inline_var,
981 .suspend_block,
978 .loop,982 .loop,
979 .bool_br_and,983 .bool_br_and,
980 .bool_br_or,984 .bool_br_or,
...@@ -2541,6 +2545,7 @@ const Writer = struct {...@@ -2541,6 +2545,7 @@ const Writer = struct {
2541 .block,2545 .block,
2542 .block_inline,2546 .block_inline,
2543 .block_inline_var,2547 .block_inline_var,
2548 .suspend_block,
2544 .loop,2549 .loop,
2545 .validate_struct_init_ptr,2550 .validate_struct_init_ptr,
2546 .validate_array_init_ptr,2551 .validate_array_init_ptr,