Merge pull request #115829 from dalexeev/gds-fix-return-codegen
GDScript: Fix compiler generates incorrect bytecode for conversion return
This commit is contained in:
@@ -439,10 +439,9 @@ void GDScriptDocGen::_generate_docs(GDScript *p_script, const GDP::ClassNode *p_
|
||||
method_doc.qualifiers += "static";
|
||||
}
|
||||
|
||||
if (func_name == "_init") {
|
||||
if (func_name == "_init" || func_name == "_static_init") {
|
||||
method_doc.return_type = "void";
|
||||
} else if (m_func->return_type) {
|
||||
// `m_func->return_type->get_datatype()` is a metatype.
|
||||
} else if (!m_func->get_datatype().is_variant()) {
|
||||
_doctype_from_gdtype(m_func->get_datatype(), method_doc.return_type, method_doc.return_enum, true);
|
||||
} else if (!m_func->body->has_return) {
|
||||
// If no `return` statement, then return type is `void`, not `Variant`.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1834,23 +1834,30 @@ void GDScriptByteCodeGenerator::write_newline(int p_line) {
|
||||
}
|
||||
}
|
||||
|
||||
void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
|
||||
if (!function->return_type.has_type() || p_return_value.type.has_type()) {
|
||||
// Either the function is untyped or the return value is also typed.
|
||||
void GDScriptByteCodeGenerator::write_return(const Address &p_return_value, bool p_use_conversion) {
|
||||
if (!p_use_conversion) {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
append(p_return_value);
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a typed function, then we need to check for potential conversions.
|
||||
if (function->return_type.has_type()) {
|
||||
if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {
|
||||
// Typed array.
|
||||
switch (function->return_type.kind) {
|
||||
case GDScriptDataType::VARIANT: {
|
||||
ERR_PRINT("Compiler bug: Unresolved return.");
|
||||
|
||||
// Shouldn't get here, but fail-safe to a regular return.
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
append(p_return_value);
|
||||
} break;
|
||||
case GDScriptDataType::BUILTIN: {
|
||||
if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {
|
||||
const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);
|
||||
append(p_return_value);
|
||||
append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
|
||||
append(element_type.builtin_type);
|
||||
append(element_type.native_type);
|
||||
} else if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::DICTIONARY &&
|
||||
function->return_type.has_container_element_types()) {
|
||||
// Typed dictionary.
|
||||
} else if (function->return_type.builtin_type == Variant::DICTIONARY && function->return_type.has_container_element_types()) {
|
||||
const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);
|
||||
const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);
|
||||
@@ -1861,72 +1868,29 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
|
||||
append(key_type.native_type);
|
||||
append(value_type.builtin_type);
|
||||
append(value_type.native_type);
|
||||
} else if (function->return_type.kind == GDScriptDataType::BUILTIN && p_return_value.type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type != p_return_value.type.builtin_type) {
|
||||
// Add conversion.
|
||||
} else {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);
|
||||
append(p_return_value);
|
||||
append(function->return_type.builtin_type);
|
||||
} else {
|
||||
// Just assign.
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
append(p_return_value);
|
||||
}
|
||||
} else {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
} break;
|
||||
case GDScriptDataType::NATIVE: {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE);
|
||||
append(p_return_value);
|
||||
}
|
||||
} else {
|
||||
switch (function->return_type.kind) {
|
||||
case GDScriptDataType::BUILTIN: {
|
||||
if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {
|
||||
const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);
|
||||
append(p_return_value);
|
||||
append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
|
||||
append(element_type.builtin_type);
|
||||
append(element_type.native_type);
|
||||
} else if (function->return_type.builtin_type == Variant::DICTIONARY && function->return_type.has_container_element_types()) {
|
||||
const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);
|
||||
const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);
|
||||
append(p_return_value);
|
||||
append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
|
||||
append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
|
||||
append(key_type.builtin_type);
|
||||
append(key_type.native_type);
|
||||
append(value_type.builtin_type);
|
||||
append(value_type.native_type);
|
||||
} else {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);
|
||||
append(p_return_value);
|
||||
append(function->return_type.builtin_type);
|
||||
}
|
||||
} break;
|
||||
case GDScriptDataType::NATIVE: {
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE);
|
||||
append(p_return_value);
|
||||
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
|
||||
Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
|
||||
class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
append(class_idx);
|
||||
} break;
|
||||
case GDScriptDataType::GDSCRIPT:
|
||||
case GDScriptDataType::SCRIPT: {
|
||||
Variant script = function->return_type.script_type;
|
||||
int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
|
||||
Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
|
||||
class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
append(class_idx);
|
||||
} break;
|
||||
case GDScriptDataType::SCRIPT:
|
||||
case GDScriptDataType::GDSCRIPT: {
|
||||
Variant script = function->return_type.script_type;
|
||||
int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT);
|
||||
append(p_return_value);
|
||||
append(script_idx);
|
||||
} break;
|
||||
default: {
|
||||
ERR_PRINT("Compiler bug: unresolved return.");
|
||||
|
||||
// Shouldn't get here, but fail-safe to a regular return;
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN);
|
||||
append(p_return_value);
|
||||
} break;
|
||||
}
|
||||
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT);
|
||||
append(p_return_value);
|
||||
append(script_idx);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -552,7 +552,7 @@ public:
|
||||
virtual void write_continue() override;
|
||||
virtual void write_breakpoint() override;
|
||||
virtual void write_newline(int p_line) override;
|
||||
virtual void write_return(const Address &p_return_value) override;
|
||||
virtual void write_return(const Address &p_return_value, bool p_use_conversion) override;
|
||||
virtual void write_assert(const Address &p_test, const Address &p_message) override;
|
||||
|
||||
virtual ~GDScriptByteCodeGenerator();
|
||||
|
||||
@@ -159,7 +159,7 @@ public:
|
||||
virtual void write_continue() = 0;
|
||||
virtual void write_breakpoint() = 0;
|
||||
virtual void write_newline(int p_line) = 0;
|
||||
virtual void write_return(const Address &p_return_value) = 0;
|
||||
virtual void write_return(const Address &p_return_value, bool p_use_conversion) = 0;
|
||||
virtual void write_assert(const Address &p_test, const Address &p_message) = 0;
|
||||
|
||||
virtual ~GDScriptCodeGenerator() {}
|
||||
|
||||
@@ -2168,10 +2168,10 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
|
||||
}
|
||||
|
||||
if (return_n->void_return) {
|
||||
// Always return "null", even if the expression is a call to a void function.
|
||||
gen->write_return(codegen.add_constant(Variant()));
|
||||
// Always return `null`, even if the expression is a call to a `void` function.
|
||||
gen->write_return(codegen.add_constant(Variant()), false);
|
||||
} else {
|
||||
gen->write_return(return_value);
|
||||
gen->write_return(return_value, return_n->use_conversion);
|
||||
}
|
||||
if (return_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
|
||||
codegen.generator->pop_temporary();
|
||||
|
||||
@@ -1047,6 +1047,7 @@ public:
|
||||
struct ReturnNode : public Node {
|
||||
ExpressionNode *return_value = nullptr;
|
||||
bool void_return = false;
|
||||
bool use_conversion = false;
|
||||
|
||||
ReturnNode() {
|
||||
type = RETURN;
|
||||
|
||||
@@ -2818,8 +2818,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
Variant::construct(ret_type, retvalue, const_cast<const Variant **>(&r), 1, ce);
|
||||
} else {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
Variant::get_type_name(r->get_type()), Variant::get_type_name(ret_type));
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), Variant::get_type_name(ret_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
// Construct a base type anyway so type constraints are met.
|
||||
@@ -2848,9 +2848,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
|
||||
if (r->get_type() != Variant::ARRAY) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "Array[%s]".)",
|
||||
Variant::get_type_name(r->get_type()), Variant::get_type_name(builtin_type));
|
||||
#endif
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "Array[%s]".)",
|
||||
_get_var_type(r), Variant::get_type_name(builtin_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
||||
@@ -2858,7 +2858,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
|
||||
if (array->get_typed_builtin() != ((uint32_t)builtin_type) || array->get_typed_class_name() != native_type || array->get_typed_script() != *script_type) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return an array of type "%s" where expected return type is "Array[%s]".)",
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "Array[%s]".)",
|
||||
_get_var_type(r), _get_element_type(builtin_type, native_type, *script_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
@@ -2890,7 +2890,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
|
||||
if (r->get_type() != Variant::DICTIONARY) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" where expected return type is "Dictionary[%s, %s]".)",
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "Dictionary[%s, %s]".)",
|
||||
_get_var_type(r), _get_element_type(key_builtin_type, key_native_type, *key_script_type),
|
||||
_get_element_type(value_builtin_type, value_native_type, *value_script_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
@@ -2902,7 +2902,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
if (dictionary->get_typed_key_builtin() != ((uint32_t)key_builtin_type) || dictionary->get_typed_key_class_name() != key_native_type || dictionary->get_typed_key_script() != *key_script_type ||
|
||||
dictionary->get_typed_value_builtin() != ((uint32_t)value_builtin_type) || dictionary->get_typed_value_class_name() != value_native_type || dictionary->get_typed_value_script() != *value_script_type) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a dictionary of type "%s" where expected return type is "Dictionary[%s, %s]".)",
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "Dictionary[%s, %s]".)",
|
||||
_get_var_type(r), _get_element_type(key_builtin_type, key_native_type, *key_script_type),
|
||||
_get_element_type(value_builtin_type, value_native_type, *value_script_type));
|
||||
#endif // DEBUG_ENABLED
|
||||
@@ -2926,8 +2926,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
GD_ERR_BREAK(!nc);
|
||||
|
||||
if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) {
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
Variant::get_type_name(r->get_type()), nc->get_name());
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), nc->get_name());
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
||||
@@ -2944,8 +2946,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
#endif // DEBUG_ENABLED
|
||||
if (ret_obj && !ClassDB::is_parent_class(ret_obj->get_class_name(), nc->get_name())) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
ret_obj->get_class_name(), nc->get_name());
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), nc->get_name());
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
@@ -2967,8 +2969,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
|
||||
if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
Variant::get_type_name(r->get_type()), GDScript::debug_get_script_name(Ref<Script>(base_type)));
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), GDScript::debug_get_script_name(Ref<Script>(base_type)));
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
@@ -2989,8 +2991,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
ScriptInstance *ret_inst = ret_obj->get_script_instance();
|
||||
if (!ret_inst) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
ret_obj->get_class_name(), GDScript::debug_get_script_name(Ref<GDScript>(base_type)));
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), GDScript::debug_get_script_name(Ref<GDScript>(base_type)));
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
@@ -3008,8 +3010,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||
|
||||
if (!valid) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
err_text = vformat(R"(Trying to return value of type "%s" from a function whose return type is "%s".)",
|
||||
GDScript::debug_get_script_name(ret_obj->get_script_instance()->get_script()), GDScript::debug_get_script_name(Ref<GDScript>(base_type)));
|
||||
err_text = vformat(R"(Trying to return a value of type "%s" from a function whose return type is "%s".)",
|
||||
_get_var_type(r), GDScript::debug_get_script_name(Ref<GDScript>(base_type)));
|
||||
#endif // DEBUG_ENABLED
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,14 +1,18 @@
|
||||
class A:
|
||||
func return_variant() -> Variant: return null
|
||||
func return_void() -> void: pass
|
||||
func return_int() -> int: return 123
|
||||
func return_int_array(_string_array: Array[String]) -> Array[int]: return []
|
||||
func return_int_dict(_string_dict: Dictionary[String, String]) -> Dictionary[int, int]: return {}
|
||||
func return_node(_resource: Resource) -> Node: return null
|
||||
func return_variant() -> Variant: return null
|
||||
|
||||
class B extends A:
|
||||
func return_variant(): pass
|
||||
func return_void(): return 1
|
||||
func return_int(): return "abc"
|
||||
func return_int_array(string_array: Array[String]): return string_array
|
||||
func return_int_dict(string_dict: Dictionary[String, String]): return string_dict
|
||||
func return_node(resource: Resource): return resource
|
||||
func return_variant(): pass
|
||||
|
||||
func test():
|
||||
pass
|
||||
|
||||
+7
-5
@@ -1,6 +1,8 @@
|
||||
GDTEST_ANALYZER_ERROR
|
||||
>> ERROR at line 8: A void function cannot return a value.
|
||||
>> ERROR at line 9: Cannot return a value of type "String" as "int".
|
||||
>> ERROR at line 9: Cannot return value of type "String" because the function return type is "int".
|
||||
>> ERROR at line 10: Cannot return value of type "Resource" because the function return type is "Node".
|
||||
>> ERROR at line 11: Not all code paths return a value.
|
||||
>> ERROR at line 10: Not all code paths return a value.
|
||||
>> ERROR at line 11: A void function cannot return a value.
|
||||
>> ERROR at line 12: Cannot return a value of type "String" as "int".
|
||||
>> ERROR at line 12: Cannot return value of type "String" because the function return type is "int".
|
||||
>> ERROR at line 13: Cannot return value of type "Array[String]" because the function return type is "Array[int]".
|
||||
>> ERROR at line 14: Cannot return value of type "Dictionary[String, String]" because the function return type is "Dictionary[int, int]".
|
||||
>> ERROR at line 15: Cannot return value of type "Resource" because the function return type is "Node".
|
||||
|
||||
+19
-1
@@ -3,23 +3,41 @@ class A:
|
||||
func return_int_as_float(_x: int) -> float: return 1.0
|
||||
func return_variant_as_float(_x: Variant) -> float: return 1.0
|
||||
func return_float_array() -> Array[float]: return [1.0]
|
||||
func return_untyped_array_as_float_array(_array: Array) -> Array[float]: return [1.0]
|
||||
func return_float_dict() -> Dictionary[float, float]: return {1.0: 1.0}
|
||||
func return_untyped_dict_as_float_dict(_dict: Dictionary) -> Dictionary[float, float]: return {1.0: 1.0}
|
||||
func return_object_as_node(_object: Object) -> Node: return null
|
||||
|
||||
class B extends A:
|
||||
func return_float(): return 2
|
||||
func return_int_as_float(x: int): return x
|
||||
func return_variant_as_float(x: Variant): return x
|
||||
func return_float_array(): return [2]
|
||||
func return_untyped_array_as_float_array(array: Array): return array
|
||||
func return_float_dict(): return {2: 2}
|
||||
func return_untyped_dict_as_float_dict(dict: Dictionary): return dict
|
||||
func return_object_as_node(object: Object): return object
|
||||
|
||||
func output(value: Variant) -> void:
|
||||
print(var_to_str(value).replace("\n", ""))
|
||||
if value is Object:
|
||||
var object: Object = value
|
||||
print("<%s>" % object.get_class())
|
||||
else:
|
||||
print(var_to_str(value).replace("\n", ""))
|
||||
|
||||
func test():
|
||||
var b := B.new()
|
||||
var float_array: Array[float] = [2]
|
||||
var float_dict: Dictionary[float, float] = {2: 2}
|
||||
var node := Node.new()
|
||||
|
||||
output(b.return_float())
|
||||
output(b.return_int_as_float(2))
|
||||
output(b.return_variant_as_float(2))
|
||||
output(b.return_float_array())
|
||||
output(b.return_untyped_array_as_float_array(float_array))
|
||||
output(b.return_float_dict())
|
||||
output(b.return_untyped_dict_as_float_dict(float_dict))
|
||||
output(b.return_object_as_node(node))
|
||||
|
||||
node.free()
|
||||
|
||||
+3
@@ -3,4 +3,7 @@ GDTEST_OK
|
||||
2.0
|
||||
2.0
|
||||
Array[float]([2.0])
|
||||
Array[float]([2.0])
|
||||
Dictionary[float, float]({2.0: 2.0})
|
||||
Dictionary[float, float]({2.0: 2.0})
|
||||
<Node>
|
||||
|
||||
+22
-1
@@ -11,7 +11,11 @@ class B extends A:
|
||||
func return_node(variant: Variant): return variant
|
||||
|
||||
func output(value: Variant) -> void:
|
||||
print(var_to_str(value).replace("\n", ""))
|
||||
if value is Object:
|
||||
var object: Object = value
|
||||
print("<%s>" % object.get_class())
|
||||
else:
|
||||
print(var_to_str(value).replace("\n", ""))
|
||||
|
||||
func test():
|
||||
var b := B.new()
|
||||
@@ -20,3 +24,20 @@ func test():
|
||||
output(b.return_int_array("abc"))
|
||||
output(b.return_int_dict("abc"))
|
||||
output(b.return_node("abc"))
|
||||
|
||||
var resource := Resource.new()
|
||||
|
||||
output(b.return_int(resource))
|
||||
output(b.return_int_array(resource))
|
||||
output(b.return_int_dict(resource))
|
||||
output(b.return_node(resource))
|
||||
|
||||
var untyped_array: Array
|
||||
var string_array: Array[String]
|
||||
var untyped_dict: Dictionary
|
||||
var string_dict: Dictionary[String, String]
|
||||
|
||||
output(b.return_int_array(untyped_array))
|
||||
output(b.return_int_array(string_array))
|
||||
output(b.return_int_dict(untyped_dict))
|
||||
output(b.return_int_dict(string_dict))
|
||||
|
||||
+20
-4
@@ -1,9 +1,25 @@
|
||||
GDTEST_RUNTIME_ERROR
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:8 on B.return_int(): Trying to return value of type "String" from a function whose return type is "int".
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:8 on B.return_int(): Trying to return a value of type "String" from a function whose return type is "int".
|
||||
0
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:9 on B.return_int_array(): Trying to return value of type "String" from a function whose return type is "Array[int]".
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:9 on B.return_int_array(): Trying to return a value of type "String" from a function whose return type is "Array[int]".
|
||||
Array[int]([])
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:10 on B.return_int_dict(): Trying to return a value of type "String" where expected return type is "Dictionary[int, int]".
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:10 on B.return_int_dict(): Trying to return a value of type "String" from a function whose return type is "Dictionary[int, int]".
|
||||
Dictionary[int, int]({})
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:11 on B.return_node(): Trying to return value of type "String" from a function whose return type is "Node".
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:11 on B.return_node(): Trying to return a value of type "String" from a function whose return type is "Node".
|
||||
null
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:8 on B.return_int(): Trying to return a value of type "Resource" from a function whose return type is "int".
|
||||
0
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:9 on B.return_int_array(): Trying to return a value of type "Resource" from a function whose return type is "Array[int]".
|
||||
Array[int]([])
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:10 on B.return_int_dict(): Trying to return a value of type "Resource" from a function whose return type is "Dictionary[int, int]".
|
||||
Dictionary[int, int]({})
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:11 on B.return_node(): Trying to return a value of type "Resource" from a function whose return type is "Node".
|
||||
null
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:9 on B.return_int_array(): Trying to return a value of type "Array" from a function whose return type is "Array[int]".
|
||||
Array[int]([])
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:9 on B.return_int_array(): Trying to return a value of type "Array[String]" from a function whose return type is "Array[int]".
|
||||
Array[int]([])
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:10 on B.return_int_dict(): Trying to return a value of type "Dictionary" from a function whose return type is "Dictionary[int, int]".
|
||||
Dictionary[int, int]({})
|
||||
>> SCRIPT ERROR at runtime/errors/untyped_override_return_incompatible_value.gd:10 on B.return_int_dict(): Trying to return a value of type "Dictionary[String, String]" from a function whose return type is "Dictionary[int, int]".
|
||||
Dictionary[int, int]({})
|
||||
|
||||
Reference in New Issue
Block a user