diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-04-23 20:09:56 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-04-23 20:09:56 -0700 |
| commit | 9a271347fe1e302c132fa63bbe27bfffcf3b132d (patch) | |
| tree | 6b001cfc452916b8ff32255b01051752302f58fe /src | |
| parent | b40a8efb9a72e69cd7e9061fc4c08d5e705b0fbd (diff) | |
| download | zig-9a271347fe1e302c132fa63bbe27bfffcf3b132d.tar.gz zig-9a271347fe1e302c132fa63bbe27bfffcf3b132d.zip | |
AstGen: implement suspend blocks
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 89 | ||||
| -rw-r--r-- | src/Sema.zig | 7 | ||||
| -rw-r--r-- | src/Zir.zig | 5 |
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, |
