Merge pull request #53822 from vnen/gdscript-await-issues

Fix a few issues with await in GDScript
This commit is contained in:
Rémi Verschelde 2021-10-15 07:26:48 +02:00 committed by GitHub
commit 027d1f1551
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 15 deletions

View File

@ -1069,7 +1069,7 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node) {
case GDScriptParser::Node::SUBSCRIPT: case GDScriptParser::Node::SUBSCRIPT:
case GDScriptParser::Node::TERNARY_OPERATOR: case GDScriptParser::Node::TERNARY_OPERATOR:
case GDScriptParser::Node::UNARY_OPERATOR: case GDScriptParser::Node::UNARY_OPERATOR:
reduce_expression(static_cast<GDScriptParser::ExpressionNode *>(p_node)); reduce_expression(static_cast<GDScriptParser::ExpressionNode *>(p_node), true);
break; break;
case GDScriptParser::Node::BREAK: case GDScriptParser::Node::BREAK:
case GDScriptParser::Node::BREAKPOINT: case GDScriptParser::Node::BREAKPOINT:
@ -1658,7 +1658,7 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
p_return->set_datatype(result); p_return->set_datatype(result);
} }
void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expression) { void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expression, bool p_is_root) {
// This one makes some magic happen. // This one makes some magic happen.
if (p_expression == nullptr) { if (p_expression == nullptr) {
@ -1686,7 +1686,7 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre
reduce_binary_op(static_cast<GDScriptParser::BinaryOpNode *>(p_expression)); reduce_binary_op(static_cast<GDScriptParser::BinaryOpNode *>(p_expression));
break; break;
case GDScriptParser::Node::CALL: case GDScriptParser::Node::CALL:
reduce_call(static_cast<GDScriptParser::CallNode *>(p_expression)); reduce_call(static_cast<GDScriptParser::CallNode *>(p_expression), p_is_root);
break; break;
case GDScriptParser::Node::CAST: case GDScriptParser::Node::CAST:
reduce_cast(static_cast<GDScriptParser::CastNode *>(p_expression)); reduce_cast(static_cast<GDScriptParser::CastNode *>(p_expression));
@ -1927,16 +1927,25 @@ void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) {
p_await->set_datatype(await_type); p_await->set_datatype(await_type);
return; return;
} }
GDScriptParser::DataType awaiting_type;
if (p_await->to_await->type == GDScriptParser::Node::CALL) { if (p_await->to_await->type == GDScriptParser::Node::CALL) {
reduce_call(static_cast<GDScriptParser::CallNode *>(p_await->to_await), true); reduce_call(static_cast<GDScriptParser::CallNode *>(p_await->to_await), true);
awaiting_type = p_await->to_await->get_datatype();
} else { } else {
reduce_expression(p_await->to_await); reduce_expression(p_await->to_await);
} }
p_await->is_constant = p_await->to_await->is_constant; if (p_await->to_await->is_constant) {
p_await->reduced_value = p_await->to_await->reduced_value; p_await->is_constant = p_await->to_await->is_constant;
p_await->reduced_value = p_await->to_await->reduced_value;
GDScriptParser::DataType awaiting_type = p_await->to_await->get_datatype(); awaiting_type = p_await->to_await->get_datatype();
} else {
awaiting_type.kind = GDScriptParser::DataType::VARIANT;
awaiting_type.type_source = GDScriptParser::DataType::UNDETECTED;
}
p_await->set_datatype(awaiting_type); p_await->set_datatype(awaiting_type);
@ -2056,7 +2065,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
p_binary_op->set_datatype(result); p_binary_op->set_datatype(result);
} }
void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_await) { void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_await, bool p_is_root) {
bool all_is_constant = true; bool all_is_constant = true;
Map<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing. Map<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing.
for (int i = 0; i < p_call->arguments.size(); i++) { for (int i = 0; i < p_call->arguments.size(); i++) {
@ -2415,7 +2424,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
} }
} }
if (call_type.is_coroutine && !is_await) { if (call_type.is_coroutine && !p_is_await && !p_is_root) {
push_error(vformat(R"*(Function "%s()" is a coroutine, so it must be called with "await".)*", p_call->function_name), p_call->callee); push_error(vformat(R"*(Function "%s()" is a coroutine, so it must be called with "await".)*", p_call->function_name), p_call->callee);
} }

View File

@ -78,12 +78,12 @@ class GDScriptAnalyzer {
void resolve_return(GDScriptParser::ReturnNode *p_return); void resolve_return(GDScriptParser::ReturnNode *p_return);
// Reduction functions. // Reduction functions.
void reduce_expression(GDScriptParser::ExpressionNode *p_expression); void reduce_expression(GDScriptParser::ExpressionNode *p_expression, bool p_is_root = false);
void reduce_array(GDScriptParser::ArrayNode *p_array); void reduce_array(GDScriptParser::ArrayNode *p_array);
void reduce_assignment(GDScriptParser::AssignmentNode *p_assignment); void reduce_assignment(GDScriptParser::AssignmentNode *p_assignment);
void reduce_await(GDScriptParser::AwaitNode *p_await); void reduce_await(GDScriptParser::AwaitNode *p_await);
void reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_op); void reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_op);
void reduce_call(GDScriptParser::CallNode *p_call, bool is_await = false); void reduce_call(GDScriptParser::CallNode *p_call, bool p_is_await = false, bool p_is_root = false);
void reduce_cast(GDScriptParser::CastNode *p_cast); void reduce_cast(GDScriptParser::CastNode *p_cast);
void reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary); void reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary);
void reduce_get_node(GDScriptParser::GetNodeNode *p_get_node); void reduce_get_node(GDScriptParser::GetNodeNode *p_get_node);

View File

@ -488,6 +488,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression); const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression);
GDScriptDataType type = _gdtype_from_datatype(call->get_datatype()); GDScriptDataType type = _gdtype_from_datatype(call->get_datatype());
GDScriptCodeGenerator::Address result = codegen.add_temporary(type); GDScriptCodeGenerator::Address result = codegen.add_temporary(type);
GDScriptCodeGenerator::Address nil = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NIL);
GDScriptCodeGenerator::Address return_addr = p_root ? nil : result;
Vector<GDScriptCodeGenerator::Address> arguments; Vector<GDScriptCodeGenerator::Address> arguments;
for (int i = 0; i < call->arguments.size(); i++) { for (int i = 0; i < call->arguments.size(); i++) {
@ -538,13 +541,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (within_await) { if (within_await) {
gen->write_call_async(result, self, call->function_name, arguments); gen->write_call_async(result, self, call->function_name, arguments);
} else { } else {
gen->write_call(result, self, call->function_name, arguments); gen->write_call(return_addr, self, call->function_name, arguments);
} }
} else { } else {
if (within_await) { if (within_await) {
gen->write_call_self_async(result, call->function_name, arguments); gen->write_call_self_async(result, call->function_name, arguments);
} else { } else {
gen->write_call_self(result, call->function_name, arguments); gen->write_call_self(return_addr, call->function_name, arguments);
} }
} }
} else if (callee->type == GDScriptParser::Node::SUBSCRIPT) { } else if (callee->type == GDScriptParser::Node::SUBSCRIPT) {
@ -579,12 +582,12 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->write_call_method_bind(result, base, method, arguments); gen->write_call_method_bind(result, base, method, arguments);
} }
} else { } else {
gen->write_call(result, base, call->function_name, arguments); gen->write_call(return_addr, base, call->function_name, arguments);
} }
} else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) { } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) {
gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments); gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments);
} else { } else {
gen->write_call(result, base, call->function_name, arguments); gen->write_call(return_addr, base, call->function_name, arguments);
} }
if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) { if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary(); gen->pop_temporary();

View File

@ -2098,8 +2098,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} }
if (result.get_type() != Variant::SIGNAL) { if (result.get_type() != Variant::SIGNAL) {
// Not async, return immediately using the target from OPCODE_AWAIT_RESUME.
GET_VARIANT_PTR(target, 3);
*target = result;
ip += 4; // Skip OPCODE_AWAIT_RESUME and its data. ip += 4; // Skip OPCODE_AWAIT_RESUME and its data.
// The stack pointer should be the same, so we don't need to set a return value.
is_signal = false; is_signal = false;
} else { } else {
sig = result; sig = result;

View File

@ -0,0 +1,8 @@
# https://github.com/godotengine/godot/issues/50894
func test():
print(await not_coroutine())
func not_coroutine():
return "awaited"

View File

@ -0,0 +1,6 @@
GDTEST_OK
>> WARNING
>> Line: 4
>> REDUNDANT_AWAIT
>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
awaited