aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2019-08-29 21:51:31 -0400
committerAndrew Kelley <andrew@ziglang.org>2019-08-29 21:51:37 -0400
commit03910925f06f6127e81de47ff22ce4d24ca565b2 (patch)
tree280f12a0b8e28667b4120d1fbc0e00861d4fdfdd /src/analyze.cpp
parent8e939916347888e755d737c579042b034e215aa8 (diff)
downloadzig-03910925f06f6127e81de47ff22ce4d24ca565b2.tar.gz
zig-03910925f06f6127e81de47ff22ce4d24ca565b2.zip
await does not force async if callee is blocking
closes #3067
Diffstat (limited to 'src/analyze.cpp')
-rw-r--r--src/analyze.cpp108
1 files changed, 75 insertions, 33 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 1ed4e19727..d1c79f9a1a 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -31,6 +31,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status);
static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
+static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame);
// nullptr means not analyzed yet; this one means currently being analyzed
static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1);
@@ -4196,6 +4197,54 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
}
}
+// ErrorNone - not async
+// ErrorIsAsync - yes async
+// ErrorSemanticAnalyzeFail - compile error emitted result is invalid
+static Error analyze_callee_async(CodeGen *g, ZigFn *fn, ZigFn *callee, AstNode *call_node,
+ bool must_not_be_async)
+{
+ if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)
+ return ErrorNone;
+ if (callee->anal_state == FnAnalStateReady) {
+ analyze_fn_body(g, callee);
+ if (callee->anal_state == FnAnalStateInvalid) {
+ return ErrorSemanticAnalyzeFail;
+ }
+ }
+ bool callee_is_async;
+ if (callee->anal_state == FnAnalStateComplete) {
+ analyze_fn_async(g, callee, true);
+ if (callee->anal_state == FnAnalStateInvalid) {
+ return ErrorSemanticAnalyzeFail;
+ }
+ callee_is_async = fn_is_async(callee);
+ } else {
+ // If it's already been determined, use that value. Otherwise
+ // assume non-async, emit an error later if it turned out to be async.
+ if (callee->inferred_async_node == nullptr ||
+ callee->inferred_async_node == inferred_async_checking)
+ {
+ callee->assumed_non_async = call_node;
+ callee_is_async = false;
+ } else {
+ callee_is_async = callee->inferred_async_node != inferred_async_none;
+ }
+ }
+ if (callee_is_async) {
+ fn->inferred_async_node = call_node;
+ fn->inferred_async_fn = callee;
+ if (must_not_be_async) {
+ ErrorMsg *msg = add_node_error(g, fn->proto_node,
+ buf_sprintf("function with calling convention '%s' cannot be async",
+ calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc)));
+ add_async_error_notes(g, msg, fn);
+ return ErrorSemanticAnalyzeFail;
+ }
+ return ErrorIsAsync;
+ }
+ return ErrorNone;
+}
+
// This function resolves functions being inferred async.
static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
if (fn->inferred_async_node == inferred_async_checking) {
@@ -4222,47 +4271,40 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
for (size_t i = 0; i < fn->call_list.length; i += 1) {
IrInstructionCallGen *call = fn->call_list.at(i);
- ZigFn *callee = call->fn_entry;
- if (callee == nullptr) {
+ if (call->fn_entry == nullptr) {
// TODO function pointer call here, could be anything
continue;
}
-
- if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)
- continue;
- if (callee->anal_state == FnAnalStateReady) {
- analyze_fn_body(g, callee);
- if (callee->anal_state == FnAnalStateInvalid) {
+ switch (analyze_callee_async(g, fn, call->fn_entry, call->base.source_node, must_not_be_async)) {
+ case ErrorSemanticAnalyzeFail:
fn->anal_state = FnAnalStateInvalid;
return;
- }
- }
- if (callee->anal_state != FnAnalStateComplete) {
- add_node_error(g, call->base.source_node,
- buf_sprintf("call to function '%s' depends on itself", buf_ptr(&callee->symbol_name)));
- fn->anal_state = FnAnalStateInvalid;
- return;
- }
- analyze_fn_async(g, callee, true);
- if (callee->anal_state == FnAnalStateInvalid) {
- fn->anal_state = FnAnalStateInvalid;
- return;
+ case ErrorNone:
+ continue;
+ case ErrorIsAsync:
+ if (resolve_frame) {
+ resolve_async_fn_frame(g, fn);
+ }
+ return;
+ default:
+ zig_unreachable();
}
- if (fn_is_async(callee)) {
- fn->inferred_async_node = call->base.source_node;
- fn->inferred_async_fn = callee;
- if (must_not_be_async) {
- ErrorMsg *msg = add_node_error(g, fn->proto_node,
- buf_sprintf("function with calling convention '%s' cannot be async",
- calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc)));
- add_async_error_notes(g, msg, fn);
+ }
+ for (size_t i = 0; i < fn->await_list.length; i += 1) {
+ IrInstructionAwaitGen *await = fn->await_list.at(i);
+ switch (analyze_callee_async(g, fn, await->target_fn, await->base.source_node, must_not_be_async)) {
+ case ErrorSemanticAnalyzeFail:
fn->anal_state = FnAnalStateInvalid;
return;
- }
- if (resolve_frame) {
- resolve_async_fn_frame(g, fn);
- }
- return;
+ case ErrorNone:
+ continue;
+ case ErrorIsAsync:
+ if (resolve_frame) {
+ resolve_async_fn_frame(g, fn);
+ }
+ return;
+ default:
+ zig_unreachable();
}
}
fn->inferred_async_node = inferred_async_none;