GDScript: Fix compiler generates incorrect bytecode for conversion return

This commit is contained in:
Danil Alexeev
2026-02-03 17:32:04 +03:00
parent 734f5473c1
commit d0eb19359e
14 changed files with 164 additions and 129 deletions
+25 -20
View File
@@ -2515,19 +2515,22 @@ void GDScriptAnalyzer::resolve_match_pattern(GDScriptParser::PatternNode *p_matc
}
void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
const bool has_expected_type = parser->current_function != nullptr;
const GDScriptParser::DataType expected_type = has_expected_type ? parser->current_function->get_datatype() : GDScriptParser::DataType();
GDScriptParser::DataType result;
GDScriptParser::DataType expected_type;
bool has_expected_type = parser->current_function != nullptr;
if (has_expected_type) {
expected_type = parser->current_function->get_datatype();
}
if (p_return->return_value != nullptr) {
bool is_void_function = has_expected_type && expected_type.is_hard_type() && expected_type.kind == GDScriptParser::DataType::BUILTIN && expected_type.builtin_type == Variant::NIL;
bool is_call = p_return->return_value->type == GDScriptParser::Node::CALL;
if (p_return->return_value == nullptr) {
// Return type is `null` by default.
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = Variant::NIL;
result.is_constant = true;
} else {
const bool is_void_function = has_expected_type && expected_type.is_hard_type() && expected_type.kind == GDScriptParser::DataType::BUILTIN && expected_type.builtin_type == Variant::NIL;
const bool is_call = p_return->return_value->type == GDScriptParser::Node::CALL;
if (is_void_function && is_call) {
// Pretend the call is a root expression to allow those that are "void".
// Pretend the call is a root expression to allow those that are `void`.
reduce_call(static_cast<GDScriptParser::CallNode *>(p_return->return_value), false, true);
} else {
reduce_expression(p_return->return_value);
@@ -2561,28 +2564,30 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
}
result = p_return->return_value->get_datatype();
}
} else {
// Return type is null by default.
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = Variant::NIL;
result.is_constant = true;
}
if (has_expected_type && !expected_type.is_variant() && expected_type.is_hard_type()) {
if (result.is_variant() || !result.is_hard_type()) {
p_return->use_conversion = true;
mark_node_unsafe(p_return);
if (!is_type_compatible(expected_type, result, true, p_return)) {
downgrade_node_type_source(p_return);
}
} else if (!is_type_compatible(expected_type, result, true, p_return)) {
mark_node_unsafe(p_return);
if (!is_type_compatible(result, expected_type)) {
if (is_type_compatible(result, expected_type)) {
p_return->use_conversion = true;
mark_node_unsafe(p_return);
} else {
push_error(vformat(R"(Cannot return value of type "%s" because the function return type is "%s".)", result.to_string(), expected_type.to_string()), p_return);
}
} else {
if (!is_type_compatible(expected_type, result)) {
p_return->use_conversion = true;
}
#ifdef DEBUG_ENABLED
} else if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
}
#endif // DEBUG_ENABLED
}
}