add compile error for async frames depending on themselves
This commit is contained in:
parent
57b90d2d98
commit
ea1734773b
|
@ -1279,6 +1279,12 @@ struct ZigTypeOpaque {
|
|||
struct ZigTypeFnFrame {
|
||||
ZigFn *fn;
|
||||
ZigType *locals_struct;
|
||||
|
||||
// This is set to the type that resolving the frame currently depends on, null if none.
|
||||
// It's for generating a helpful error message.
|
||||
ZigType *resolve_loop_type;
|
||||
AstNode *resolve_loop_src_node;
|
||||
bool reported_loop_err;
|
||||
};
|
||||
|
||||
struct ZigTypeAnyFrame {
|
||||
|
|
|
@ -5197,6 +5197,27 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {
|
|||
return fn_type;
|
||||
}
|
||||
|
||||
static void emit_error_notes_for_type_loop(CodeGen *g, ErrorMsg *msg, ZigType *stop_type,
|
||||
ZigType *ty, AstNode *src_node)
|
||||
{
|
||||
ErrorMsg *note = add_error_note(g, msg, src_node,
|
||||
buf_sprintf("when analyzing type '%s' here", buf_ptr(&ty->name)));
|
||||
if (ty == stop_type)
|
||||
return;
|
||||
switch (ty->id) {
|
||||
case ZigTypeIdFnFrame: {
|
||||
ty->data.frame.reported_loop_err = true;
|
||||
ZigType *depending_type = ty->data.frame.resolve_loop_type;
|
||||
if (depending_type == nullptr)
|
||||
return;
|
||||
emit_error_notes_for_type_loop(g, note, stop_type,
|
||||
depending_type, ty->data.frame.resolve_loop_src_node);
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
||||
Error err;
|
||||
|
||||
|
@ -5206,6 +5227,20 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
|||
ZigFn *fn = frame_type->data.frame.fn;
|
||||
assert(!fn->type_entry->data.fn.is_generic);
|
||||
|
||||
if (frame_type->data.frame.resolve_loop_type != nullptr) {
|
||||
if (!frame_type->data.frame.reported_loop_err) {
|
||||
frame_type->data.frame.reported_loop_err = true;
|
||||
ErrorMsg *msg = add_node_error(g, fn->proto_node,
|
||||
buf_sprintf("'%s' depends on itself", buf_ptr(&frame_type->name)));
|
||||
emit_error_notes_for_type_loop(g, msg,
|
||||
frame_type,
|
||||
frame_type->data.frame.resolve_loop_type,
|
||||
frame_type->data.frame.resolve_loop_src_node);
|
||||
emit_error_notes_for_ref_stack(g, msg);
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
switch (fn->anal_state) {
|
||||
case FnAnalStateInvalid:
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
|
@ -5299,6 +5334,10 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
|||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
ZigType *callee_frame_type = get_fn_frame_type(g, callee);
|
||||
frame_type->data.frame.resolve_loop_type = callee_frame_type;
|
||||
frame_type->data.frame.resolve_loop_src_node = call->base.source_node;
|
||||
|
||||
analyze_fn_body(g, callee);
|
||||
if (callee->anal_state == FnAnalStateInvalid) {
|
||||
frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid;
|
||||
|
@ -5308,8 +5347,6 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
|||
if (!fn_is_async(callee))
|
||||
continue;
|
||||
|
||||
ZigType *callee_frame_type = get_fn_frame_type(g, callee);
|
||||
|
||||
IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
|
||||
alloca_gen->base.id = IrInstructionIdAllocaGen;
|
||||
alloca_gen->base.source_node = call->base.source_node;
|
||||
|
@ -5378,9 +5415,13 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
frame_type->data.frame.resolve_loop_type = child_type;
|
||||
frame_type->data.frame.resolve_loop_src_node = instruction->base.source_node;
|
||||
if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const char *name;
|
||||
if (*instruction->name_hint == 0) {
|
||||
name = buf_ptr(buf_sprintf("@local%" ZIG_PRI_usize, alloca_i));
|
||||
|
|
|
@ -2,6 +2,42 @@ const tests = @import("tests.zig");
|
|||
const builtin = @import("builtin");
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.add(
|
||||
"indirect recursion of async functions detected",
|
||||
\\var frame: ?anyframe = null;
|
||||
\\
|
||||
\\export fn a() void {
|
||||
\\ _ = async rangeSum(10);
|
||||
\\ while (frame) |f| resume f;
|
||||
\\}
|
||||
\\
|
||||
\\fn rangeSum(x: i32) i32 {
|
||||
\\ suspend {
|
||||
\\ frame = @frame();
|
||||
\\ }
|
||||
\\ frame = null;
|
||||
\\
|
||||
\\ if (x == 0) return 0;
|
||||
\\ var child = rangeSumIndirect(x - 1);
|
||||
\\ return child + 1;
|
||||
\\}
|
||||
\\
|
||||
\\fn rangeSumIndirect(x: i32) i32 {
|
||||
\\ suspend {
|
||||
\\ frame = @frame();
|
||||
\\ }
|
||||
\\ frame = null;
|
||||
\\
|
||||
\\ if (x == 0) return 0;
|
||||
\\ var child = rangeSum(x - 1);
|
||||
\\ return child + 1;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:8:1: error: '@Frame(rangeSum)' depends on itself",
|
||||
"tmp.zig:15:33: note: when analyzing type '@Frame(rangeSumIndirect)' here",
|
||||
"tmp.zig:26:25: note: when analyzing type '@Frame(rangeSum)' here",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"non-async function pointer eventually is inferred to become async",
|
||||
\\export fn a() void {
|
||||
|
|
Loading…
Reference in New Issue
Block a user