authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-17 19:47:49-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-17 19:47:49-04:00
logea1734773ba9913e32318aba963cdcb9f51128d4
treef828d07b7c5b9e4cc550ddf7aab21c9ac166b466
parent57b90d2d98154e382c58f1b385de2bcef132f7d9
signaturelock-open Commit is signed but in an unrecognized format.

add compile error for async frames depending on themselves


3 files changed, 85 insertions(+), 2 deletions(-)

src/all_types.hpp+6
...@@ -1279,6 +1279,12 @@ struct ZigTypeOpaque {...@@ -1279,6 +1279,12 @@ struct ZigTypeOpaque {
1279struct ZigTypeFnFrame {1279struct ZigTypeFnFrame {
1280 ZigFn *fn;1280 ZigFn *fn;
1281 ZigType *locals_struct;1281 ZigType *locals_struct;
1282
1283 // This is set to the type that resolving the frame currently depends on, null if none.
1284 // It's for generating a helpful error message.
1285 ZigType *resolve_loop_type;
1286 AstNode *resolve_loop_src_node;
1287 bool reported_loop_err;
1282};1288};
12831289
1284struct ZigTypeAnyFrame {1290struct ZigTypeAnyFrame {
src/analyze.cpp+43-2
...@@ -5197,6 +5197,27 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {...@@ -5197,6 +5197,27 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {
5197 return fn_type;5197 return fn_type;
5198}5198}
51995199
5200static void emit_error_notes_for_type_loop(CodeGen *g, ErrorMsg *msg, ZigType *stop_type,
5201 ZigType *ty, AstNode *src_node)
5202{
5203 ErrorMsg *note = add_error_note(g, msg, src_node,
5204 buf_sprintf("when analyzing type '%s' here", buf_ptr(&ty->name)));
5205 if (ty == stop_type)
5206 return;
5207 switch (ty->id) {
5208 case ZigTypeIdFnFrame: {
5209 ty->data.frame.reported_loop_err = true;
5210 ZigType *depending_type = ty->data.frame.resolve_loop_type;
5211 if (depending_type == nullptr)
5212 return;
5213 emit_error_notes_for_type_loop(g, note, stop_type,
5214 depending_type, ty->data.frame.resolve_loop_src_node);
5215 }
5216 default:
5217 return;
5218 }
5219}
5220
5200static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {5221static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5201 Error err;5222 Error err;
52025223
...@@ -5206,6 +5227,20 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {...@@ -5206,6 +5227,20 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5206 ZigFn *fn = frame_type->data.frame.fn;5227 ZigFn *fn = frame_type->data.frame.fn;
5207 assert(!fn->type_entry->data.fn.is_generic);5228 assert(!fn->type_entry->data.fn.is_generic);
52085229
5230 if (frame_type->data.frame.resolve_loop_type != nullptr) {
5231 if (!frame_type->data.frame.reported_loop_err) {
5232 frame_type->data.frame.reported_loop_err = true;
5233 ErrorMsg *msg = add_node_error(g, fn->proto_node,
5234 buf_sprintf("'%s' depends on itself", buf_ptr(&frame_type->name)));
5235 emit_error_notes_for_type_loop(g, msg,
5236 frame_type,
5237 frame_type->data.frame.resolve_loop_type,
5238 frame_type->data.frame.resolve_loop_src_node);
5239 emit_error_notes_for_ref_stack(g, msg);
5240 }
5241 return ErrorSemanticAnalyzeFail;
5242 }
5243
5209 switch (fn->anal_state) {5244 switch (fn->anal_state) {
5210 case FnAnalStateInvalid:5245 case FnAnalStateInvalid:
5211 return ErrorSemanticAnalyzeFail;5246 return ErrorSemanticAnalyzeFail;
...@@ -5299,6 +5334,10 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {...@@ -5299,6 +5334,10 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5299 return ErrorSemanticAnalyzeFail;5334 return ErrorSemanticAnalyzeFail;
5300 }5335 }
53015336
5337 ZigType *callee_frame_type = get_fn_frame_type(g, callee);
5338 frame_type->data.frame.resolve_loop_type = callee_frame_type;
5339 frame_type->data.frame.resolve_loop_src_node = call->base.source_node;
5340
5302 analyze_fn_body(g, callee);5341 analyze_fn_body(g, callee);
5303 if (callee->anal_state == FnAnalStateInvalid) {5342 if (callee->anal_state == FnAnalStateInvalid) {
5304 frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid;5343 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) {...@@ -5308,8 +5347,6 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5308 if (!fn_is_async(callee))5347 if (!fn_is_async(callee))
5309 continue;5348 continue;
53105349
5311 ZigType *callee_frame_type = get_fn_frame_type(g, callee);
5312
5313 IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);5350 IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
5314 alloca_gen->base.id = IrInstructionIdAllocaGen;5351 alloca_gen->base.id = IrInstructionIdAllocaGen;
5315 alloca_gen->base.source_node = call->base.source_node;5352 alloca_gen->base.source_node = call->base.source_node;
...@@ -5378,9 +5415,13 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {...@@ -5378,9 +5415,13 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5378 continue;5415 continue;
5379 }5416 }
5380 }5417 }
5418
5419 frame_type->data.frame.resolve_loop_type = child_type;
5420 frame_type->data.frame.resolve_loop_src_node = instruction->base.source_node;
5381 if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) {5421 if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) {
5382 return err;5422 return err;
5383 }5423 }
5424
5384 const char *name;5425 const char *name;
5385 if (*instruction->name_hint == 0) {5426 if (*instruction->name_hint == 0) {
5386 name = buf_ptr(buf_sprintf("@local%" ZIG_PRI_usize, alloca_i));5427 name = buf_ptr(buf_sprintf("@local%" ZIG_PRI_usize, alloca_i));
test/compile_errors.zig+36
...@@ -2,6 +2,42 @@ const tests = @import("tests.zig");...@@ -2,6 +2,42 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "indirect recursion of async functions detected",
7 \\var frame: ?anyframe = null;
8 \\
9 \\export fn a() void {
10 \\ _ = async rangeSum(10);
11 \\ while (frame) |f| resume f;
12 \\}
13 \\
14 \\fn rangeSum(x: i32) i32 {
15 \\ suspend {
16 \\ frame = @frame();
17 \\ }
18 \\ frame = null;
19 \\
20 \\ if (x == 0) return 0;
21 \\ var child = rangeSumIndirect(x - 1);
22 \\ return child + 1;
23 \\}
24 \\
25 \\fn rangeSumIndirect(x: i32) i32 {
26 \\ suspend {
27 \\ frame = @frame();
28 \\ }
29 \\ frame = null;
30 \\
31 \\ if (x == 0) return 0;
32 \\ var child = rangeSum(x - 1);
33 \\ return child + 1;
34 \\}
35 ,
36 "tmp.zig:8:1: error: '@Frame(rangeSum)' depends on itself",
37 "tmp.zig:15:33: note: when analyzing type '@Frame(rangeSumIndirect)' here",
38 "tmp.zig:26:25: note: when analyzing type '@Frame(rangeSum)' here",
39 );
40
5 cases.add(41 cases.add(
6 "non-async function pointer eventually is inferred to become async",42 "non-async function pointer eventually is inferred to become async",
7 \\export fn a() void {43 \\export fn a() void {