AstGen: implement suspend blocks
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user