aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-23 20:09:56 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-23 20:09:56 -0700
commit9a271347fe1e302c132fa63bbe27bfffcf3b132d (patch)
tree6b001cfc452916b8ff32255b01051752302f58fe /src
parentb40a8efb9a72e69cd7e9061fc4c08d5e705b0fbd (diff)
downloadzig-9a271347fe1e302c132fa63bbe27bfffcf3b132d.tar.gz
zig-9a271347fe1e302c132fa63bbe27bfffcf3b132d.zip
AstGen: implement suspend blocks
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig89
-rw-r--r--src/Sema.zig7
-rw-r--r--src/Zir.zig5
3 files changed, 96 insertions, 5 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 7e3eff48ea..65f8d78e95 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -827,10 +827,10 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
.@"comptime" => return comptimeExpr(gz, scope, rl, node_datas[node].lhs),
.@"switch", .switch_comma => return switchExpr(gz, scope, rl, node),
- .@"nosuspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
- .@"suspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
- .@"await" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
- .@"resume" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
+ .@"nosuspend" => return nosuspendExpr(gz, scope, rl, node),
+ .@"suspend" => return suspendExpr(gz, scope, rl, node),
+ .@"await" => return awaitExpr(gz, scope, rl, node),
+ .@"resume" => return resumeExpr(gz, scope, rl, node),
.@"try" => return tryExpr(gz, scope, rl, node, node_datas[node].lhs),
@@ -883,6 +883,82 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
}
}
+pub fn nosuspendExpr(
+ gz: *GenZir,
+ scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+ const astgen = gz.astgen;
+ return astgen.failNode(node, "TODO AstGen nosuspendExpr", .{});
+}
+
+pub fn suspendExpr(
+ gz: *GenZir,
+ scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+ const astgen = gz.astgen;
+ const gpa = astgen.gpa;
+ const tree = &astgen.file.tree;
+ const node_datas = tree.nodes.items(.data);
+ const body_node = node_datas[node].lhs;
+
+ if (gz.nosuspend_node != 0) {
+ return astgen.failNodeNotes(node, "suspend inside nosuspend block", .{}, &[_]u32{
+ try astgen.errNoteNode(gz.nosuspend_node, "nosuspend block here", .{}),
+ });
+ }
+ if (gz.suspend_node != 0) {
+ return astgen.failNodeNotes(node, "cannot suspend inside suspend block", .{}, &[_]u32{
+ try astgen.errNoteNode(gz.suspend_node, "other suspend block here", .{}),
+ });
+ }
+ if (body_node == 0) {
+ // Accepted proposal to remove block-less suspend from the language:
+ // https://github.com/ziglang/zig/issues/8603
+ // TODO: simplify the parser and make this an assert instead of
+ // a compile error.
+ return astgen.failNode(node, "suspend without a block", .{});
+ }
+
+ const suspend_inst = try gz.addBlock(.suspend_block, node);
+ try gz.instructions.append(gpa, suspend_inst);
+
+ var suspend_scope = gz.makeSubBlock(scope);
+ suspend_scope.suspend_node = node;
+ defer suspend_scope.instructions.deinit(gpa);
+
+ const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node);
+ if (!gz.refIsNoReturn(body_result)) {
+ _ = try suspend_scope.addBreak(.break_inline, suspend_inst, .void_value);
+ }
+ try suspend_scope.setBlockBody(suspend_inst);
+
+ return gz.indexToRef(suspend_inst);
+}
+
+pub fn awaitExpr(
+ gz: *GenZir,
+ scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+ const astgen = gz.astgen;
+ return astgen.failNode(node, "TODO AstGen awaitExpr", .{});
+}
+
+pub fn resumeExpr(
+ gz: *GenZir,
+ scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+ const astgen = gz.astgen;
+ return astgen.failNode(node, "TODO AstGen resumeExpr", .{});
+}
+
pub fn fnProtoExpr(
gz: *GenZir,
scope: *Scope,
@@ -1701,6 +1777,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
.block,
.block_inline,
.block_inline_var,
+ .suspend_block,
.loop,
.bool_br_and,
.bool_br_or,
@@ -4090,7 +4167,9 @@ fn boolBinOp(
var rhs_scope = gz.makeSubBlock(scope);
defer rhs_scope.instructions.deinit(gz.astgen.gpa);
const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs);
- _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
+ if (!gz.refIsNoReturn(rhs)) {
+ _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
+ }
try rhs_scope.setBoolBrBody(bool_br);
const block_ref = gz.indexToRef(bool_br);
diff --git a/src/Sema.zig b/src/Sema.zig
index fd9bc39fd9..0648ca1b1c 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -151,6 +151,7 @@ pub fn analyzeBody(
.bitcast => try sema.zirBitcast(block, inst),
.bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
.block => try sema.zirBlock(block, inst),
+ .suspend_block => try sema.zirSuspendBlock(block, inst),
.bool_not => try sema.zirBoolNot(block, inst),
.bool_and => try sema.zirBoolOp(block, inst, false),
.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
return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{});
}
+fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+ const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const src = inst_data.src();
+ return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirSuspendBlock", .{});
+}
+
fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
diff --git a/src/Zir.zig b/src/Zir.zig
index dfa845ce13..9b0a40600c 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -199,6 +199,9 @@ pub const Inst = struct {
block_inline,
/// Same as `block_inline` but it additionally marks a decl as being a variable.
block_inline_var,
+ /// Implements `suspend {...}`.
+ /// Uses the `pl_node` union field. Payload is `Block`.
+ suspend_block,
/// Boolean AND. See also `bit_and`.
/// Uses the `pl_node` union field. Payload is `Bin`.
bool_and,
@@ -975,6 +978,7 @@ pub const Inst = struct {
.block,
.block_inline,
.block_inline_var,
+ .suspend_block,
.loop,
.bool_br_and,
.bool_br_or,
@@ -2541,6 +2545,7 @@ const Writer = struct {
.block,
.block_inline,
.block_inline_var,
+ .suspend_block,
.loop,
.validate_struct_init_ptr,
.validate_array_init_ptr,