diff options
Diffstat (limited to 'modules/gdscript')
12 files changed, 68 insertions, 41 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 00f8d2817a..b6caefbdb5 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -2027,11 +2027,6 @@ String GDScriptLanguage::get_extension() const { return "gd"; } -Error GDScriptLanguage::execute_file(const String &p_path) { - // ?? - return OK; -} - void GDScriptLanguage::finish() { if (_call_stack) { memdelete_arr(_call_stack); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 82d04f641c..0117ed40ab 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -473,7 +473,6 @@ public: virtual void init() override; virtual String get_type() const override; virtual String get_extension() const override; - virtual Error execute_file(const String &p_path) override; virtual void finish() override; /* EDITOR FUNCTIONS */ diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index e058187860..38d5ae6b77 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2618,7 +2618,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o result = get_operation_type(p_binary_op->variant_op, left_type, right_type, valid, p_binary_op); if (!valid) { push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", left_type.to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); - } else if (result.type_source != GDScriptParser::DataType::ANNOTATED_EXPLICIT) { + } else if (!result.is_hard_type()) { mark_node_unsafe(p_binary_op); } } else { diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 5b092e3691..d6f21d297a 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -1058,7 +1058,7 @@ void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_tar void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) { bool is_validated = true; if (Variant::is_utility_function_vararg(p_function)) { - is_validated = true; // Vararg works fine with any argument, since they can be any type. + is_validated = false; // Vararg needs runtime checks, can't use validated call. } else if (p_arguments.size() == Variant::get_utility_function_argument_count(p_function)) { bool all_types_exact = true; for (int i = 0; i < p_arguments.size(); i++) { @@ -1107,7 +1107,7 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, // Check if all types are correct. if (Variant::is_builtin_method_vararg(p_type, p_method)) { - is_validated = true; // Vararg works fine with any argument, since they can be any type. + is_validated = false; // Vararg needs runtime checks, can't use validated call. } else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) { bool all_types_exact = true; for (int i = 0; i < p_arguments.size(); i++) { diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index fad2bf334b..d0c2cb43a6 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -85,7 +85,7 @@ void GDScriptCompiler::_set_error(const String &p_error, const GDScriptParser::N } GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner) { - if (!p_datatype.is_set() || !p_datatype.is_hard_type()) { + if (!p_datatype.is_set() || !p_datatype.is_hard_type() || p_datatype.is_coroutine) { return GDScriptDataType(); } @@ -211,10 +211,6 @@ static bool _can_use_ptrcall(const MethodBind *p_method, const Vector<GDScriptCo return true; } -inline static bool is_category_or_group(const PropertyInfo &p_info) { - return p_info.usage & PROPERTY_USAGE_CATEGORY || p_info.usage & PROPERTY_USAGE_GROUP || p_info.usage & PROPERTY_USAGE_SUBGROUP; -} - GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) { if (p_expression->is_constant && !(p_expression->get_datatype().is_meta_type && p_expression->get_datatype().kind == GDScriptParser::DataType::CLASS)) { return codegen.add_constant(p_expression->reduced_value); @@ -242,7 +238,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Try class members. if (_is_class_member_property(codegen, identifier)) { // Get property. - GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Could get the type of the class member here. + GDScriptCodeGenerator::Address temp = codegen.add_temporary(_gdtype_from_datatype(p_expression->get_datatype(), codegen.script)); gen->write_get_member(temp, identifier); return temp; } @@ -250,7 +246,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Try members. if (!codegen.function_node || !codegen.function_node->is_static) { // Try member variables. - if (codegen.script->member_indices.has(identifier) && !is_category_or_group(codegen.script->member_info[identifier])) { + if (codegen.script->member_indices.has(identifier)) { if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) { // Perform getter. GDScriptCodeGenerator::Address temp = codegen.add_temporary(codegen.script->member_indices[identifier].data_type); @@ -2022,6 +2018,32 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ bool is_initializer = p_func && !p_for_lambda && p_func->identifier->name == GDScriptLanguage::get_singleton()->strings._init; bool is_implicit_ready = !p_func && p_for_ready; + if (!p_for_lambda && is_implicit_initializer) { + // Initialize the default values for type variables before anything. + // This avoids crashes if they are accessed with validated calls before being properly initialized. + // It may happen with out-of-order access or with `@onready` variables. + for (const GDScriptParser::ClassNode::Member &member : p_class->members) { + if (member.type != GDScriptParser::ClassNode::Member::VARIABLE) { + continue; + } + + const GDScriptParser::VariableNode *field = member.variable; + GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script); + GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type); + + if (field_type.has_type) { + codegen.generator->write_newline(field->start_line); + + if (field_type.has_container_element_type()) { + codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>()); + } else if (field_type.kind == GDScriptDataType::BUILTIN) { + codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>()); + } + // The `else` branch is for objects, in such case we leave it as `null`. + } + } + } + if (!p_for_lambda && (is_implicit_initializer || is_implicit_ready)) { // Initialize class fields. for (int i = 0; i < p_class->members.size(); i++) { @@ -2055,16 +2077,6 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) { codegen.generator->pop_temporary(); } - } else if (field_type.has_type) { - codegen.generator->write_newline(field->start_line); - - // Initialize with default for type. - if (field_type.has_container_element_type()) { - codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>()); - } else if (field_type.kind == GDScriptDataType::BUILTIN) { - codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>()); - } - // The `else` branch is for objects, in such case we leave it as `null`. } } } diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.gd b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.gd index 6fc90ea29c..1e5c10b7d5 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.gd +++ b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.gd @@ -1,4 +1,4 @@ func test(): var lambda := func(unused: Variant) -> void: pass - lambda.call() + lambda.call("something") diff --git a/modules/gdscript/tests/scripts/runtime/features/conversions_from_native_members.gd b/modules/gdscript/tests/scripts/runtime/features/conversions_from_native_members.gd new file mode 100644 index 0000000000..a778fb1a94 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/conversions_from_native_members.gd @@ -0,0 +1,11 @@ +class Foo extends Node: + func _init(): + name = 'f' + var string: String = name + assert(typeof(string) == TYPE_STRING) + assert(string == 'f') + print('ok') + +func test(): + var foo := Foo.new() + foo.free() diff --git a/modules/gdscript/tests/scripts/runtime/features/conversions_from_native_members.out b/modules/gdscript/tests/scripts/runtime/features/conversions_from_native_members.out new file mode 100644 index 0000000000..1b47ed10dc --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/conversions_from_native_members.out @@ -0,0 +1,2 @@ +GDTEST_OK +ok diff --git a/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.gd b/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.gd new file mode 100644 index 0000000000..03278e453f --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.gd @@ -0,0 +1,20 @@ +extends Node + +@onready var later_inferred := [1] +@onready var later_static : Array +@onready var later_static_with_init : Array = [1] +@onready var later_untyped = [1] + +func test(): + assert(typeof(later_inferred) == TYPE_ARRAY) + assert(later_inferred.size() == 0) + + assert(typeof(later_static) == TYPE_ARRAY) + assert(later_static.size() == 0) + + assert(typeof(later_static_with_init) == TYPE_ARRAY) + assert(later_static_with_init.size() == 0) + + assert(typeof(later_untyped) == TYPE_NIL) + + print("ok") diff --git a/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.out b/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.out new file mode 100644 index 0000000000..1b47ed10dc --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.out @@ -0,0 +1,2 @@ +GDTEST_OK +ok diff --git a/modules/gdscript/tests/scripts/runtime/features/groups_are_not_properties.gd b/modules/gdscript/tests/scripts/runtime/features/groups_are_not_properties.gd deleted file mode 100644 index a5ad7c0b85..0000000000 --- a/modules/gdscript/tests/scripts/runtime/features/groups_are_not_properties.gd +++ /dev/null @@ -1,11 +0,0 @@ -# https://github.com/godotengine/godot/issues/73843 -extends RefCounted - -@export_group("Resource") -@export_category("RefCounted") - -func test(): - var res = Resource.new() - var ref = RefCounted.new() - prints("Resource class not shadowed:", res is Resource) - prints("RefCounted class not shadowed:", ref is RefCounted) diff --git a/modules/gdscript/tests/scripts/runtime/features/groups_are_not_properties.out b/modules/gdscript/tests/scripts/runtime/features/groups_are_not_properties.out deleted file mode 100644 index 182c6dcd3a..0000000000 --- a/modules/gdscript/tests/scripts/runtime/features/groups_are_not_properties.out +++ /dev/null @@ -1,3 +0,0 @@ -GDTEST_OK -Resource class not shadowed: true -RefCounted class not shadowed: true |