From a8c2f8a0e1c4d4e128bd64084f5e5611005a923d Mon Sep 17 00:00:00 2001 From: Dmitrii Maganov Date: Fri, 6 Jan 2023 11:49:06 +0200 Subject: [PATCH] GDScript: Fix missing conversion for default argument values --- modules/gdscript/gdscript_analyzer.cpp | 9 +++------ modules/gdscript/gdscript_byte_codegen.cpp | 8 ++++++-- modules/gdscript/gdscript_byte_codegen.h | 2 +- modules/gdscript/gdscript_codegen.h | 2 +- modules/gdscript/gdscript_compiler.cpp | 2 +- modules/gdscript/gdscript_parser.h | 2 +- .../bad_conversion_for_default_parameter.gd | 8 ++++++++ .../bad_conversion_for_default_parameter.out | 8 ++++++++ .../conversion_for_default_parameter.gd | 19 +++++++++++++++++++ .../conversion_for_default_parameter.out | 8 ++++++++ 10 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.gd create mode 100644 modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.out create mode 100644 modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.gd create mode 100644 modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index eb660ef09f0..9ff5e4f6276 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1485,7 +1485,6 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi GDScriptParser::DataType type; type.kind = GDScriptParser::DataType::VARIANT; - bool is_variable = p_assignable->type == GDScriptParser::Node::VARIABLE; bool is_constant = p_assignable->type == GDScriptParser::Node::CONSTANT; GDScriptParser::DataType specified_type; @@ -1548,13 +1547,11 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi } else if (!specified_type.is_variant()) { if (initializer_type.is_variant() || !initializer_type.is_hard_type()) { mark_node_unsafe(p_assignable->initializer); - if (is_variable) { - static_cast(p_assignable)->use_conversion_assign = true; - } + p_assignable->use_conversion_assign = true; } else if (!is_type_compatible(specified_type, initializer_type, true, p_assignable->initializer)) { - if (is_variable && is_type_compatible(initializer_type, specified_type, true, p_assignable->initializer)) { + if (!is_constant && is_type_compatible(initializer_type, specified_type, true, p_assignable->initializer)) { mark_node_unsafe(p_assignable->initializer); - static_cast(p_assignable)->use_conversion_assign = true; + p_assignable->use_conversion_assign = true; } else { push_error(vformat(R"(Cannot assign a value of type %s to %s "%s" with specified type %s.)", initializer_type.to_string(), p_kind, p_assignable->identifier->name, specified_type.to_string()), p_assignable->initializer); } diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 8b3ae17e5fd..7b533c07e9e 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -872,8 +872,12 @@ void GDScriptByteCodeGenerator::write_assign_false(const Address &p_target) { append(p_target); } -void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_dst, const Address &p_src) { - write_assign(p_dst, p_src); +void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_dst, const Address &p_src, bool p_use_conversion) { + if (p_use_conversion) { + write_assign_with_conversion(p_dst, p_src); + } else { + write_assign(p_dst, p_src); + } function->default_arguments.push_back(opcodes.size()); } diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index ba4847813f5..2fa5b26ce57 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -458,7 +458,7 @@ public: virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) override; virtual void write_assign_true(const Address &p_target) override; virtual void write_assign_false(const Address &p_target) override; - virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override; + virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src, bool p_use_conversion) override; virtual void write_store_global(const Address &p_dst, int p_global_index) override; virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) override; virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override; diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index c7a1bcb9e99..e885938ebac 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -113,7 +113,7 @@ public: virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) = 0; virtual void write_assign_true(const Address &p_target) = 0; virtual void write_assign_false(const Address &p_target) = 0; - virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0; + virtual void write_assign_default_parameter(const Address &dst, const Address &src, bool p_use_conversion) = 0; virtual void write_store_global(const Address &p_dst, int p_global_index) = 0; virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) = 0; virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 2d36692c3cf..b6fcf870cdc 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2114,7 +2114,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ } } - codegen.generator->write_assign_default_parameter(dst_addr, src_addr); + codegen.generator->write_assign_default_parameter(dst_addr, src_addr, parameter->use_conversion_assign); if (src_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) { codegen.generator->pop_temporary(); } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 65eace80888..1c728dfb679 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -360,6 +360,7 @@ public: ExpressionNode *initializer = nullptr; TypeNode *datatype_specifier = nullptr; bool infer_datatype = false; + bool use_conversion_assign = false; int usages = 0; virtual ~AssignableNode() {} @@ -1182,7 +1183,6 @@ public: bool onready = false; PropertyInfo export_info; int assignments = 0; - bool use_conversion_assign = false; #ifdef TOOLS_ENABLED String doc_description; #endif // TOOLS_ENABLED diff --git a/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.gd b/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.gd new file mode 100644 index 00000000000..a72ac9b5ee3 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.gd @@ -0,0 +1,8 @@ +var weakling = 'not float' +func weak(x: float = weakling): + print(x) + print('typeof x is', typeof(x)) + +func test(): + print(typeof(weak())) + print('not ok') diff --git a/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.out b/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.out new file mode 100644 index 00000000000..8543cf976e6 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.out @@ -0,0 +1,8 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: weak() +>> runtime/errors/bad_conversion_for_default_parameter.gd +>> 2 +>> Trying to assign value of type 'String' to a variable of type 'float'. +0 +not ok diff --git a/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.gd b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.gd new file mode 100644 index 00000000000..9d0c6317b3c --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.gd @@ -0,0 +1,19 @@ +func literal(x: float = 1): + print('x is ', x) + print('typeof x is ', typeof(x)) + +var inferring := 2 +func inferred(x: float = inferring): + print('x is ', x) + print('typeof x is ', typeof(x)) + +var weakling = 3 +func weak(x: float = weakling): + print('x is ', x) + print('typeof x is ', typeof(x)) + +func test(): + literal() + inferred() + weak() + print('ok') diff --git a/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out new file mode 100644 index 00000000000..a9ef4919cf1 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out @@ -0,0 +1,8 @@ +GDTEST_OK +x is 1 +typeof x is 3 +x is 2 +typeof x is 3 +x is 3 +typeof x is 3 +ok