diff options
Diffstat (limited to 'modules')
11 files changed, 91 insertions, 26 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 08c8763493..045505b720 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -126,6 +126,20 @@ <param index="0" name="value" type="Variant" /> <param index="1" name="type" type="Variant" /> <description> + Returns [code]true[/code] if [param value] is an instance of [param type]. The [param type] value must be one of the following: + - A constant from the [enum Variant.Type] enumeration, for example [constant TYPE_INT]. + - An [Object]-derived class which exists in [ClassDB], for example [Node]. + - A [Script] (you can use any class, including inner one). + Unlike the right operand of the [code]is[/code] operator, [param type] can be a non-constant value. The [code]is[/code] operator supports more features (such as typed arrays) and is more performant. Use the operator instead of this method if you do not need dynamic type checking. + Examples: + [codeblock] + print(is_instance_of(a, TYPE_INT)) + print(is_instance_of(a, Node)) + print(is_instance_of(a, MyClass)) + print(is_instance_of(a, MyClass.InnerClass)) + [/codeblock] + [b]Note:[/b] If [param value] and/or [param type] are freed objects (see [method @GlobalScope.is_instance_valid]), or [param type] is not one of the above options, this method will raise an runtime error. + See also [method @GlobalScope.typeof], [method type_exists], [method Array.is_same_typed] (and other [Array] methods). </description> </method> <method name="len"> diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 38f9163f70..5ce01a08bf 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -657,6 +657,10 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type } else if (ProjectSettings::get_singleton()->has_autoload(first) && ProjectSettings::get_singleton()->get_autoload(first).is_singleton) { const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(first); Ref<GDScriptParserRef> ref = get_parser_for(autoload.path); + if (ref.is_null()) { + push_error(vformat(R"(The referenced autoload "%s" (from "%s") could not be loaded.)", first, autoload.path), p_type); + return bad_type; + } if (ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) { push_error(vformat(R"(Could not parse singleton "%s" from "%s".)", first, autoload.path), p_type); return bad_type; @@ -727,7 +731,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type } } if (!result.is_set()) { - push_error(vformat(R"("%s" was not found in the current scope.)", first), p_type); + push_error(vformat(R"(Could not find type "%s" in the current scope.)", first), p_type); return bad_type; } @@ -1534,6 +1538,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * // Check if the function signature matches the parent. If not it's an error since it breaks polymorphism. // Not for the constructor which can vary in signature. GDScriptParser::DataType base_type = parser->current_class->base_type; + base_type.is_meta_type = false; GDScriptParser::DataType parent_return_type; List<GDScriptParser::DataType> parameters_types; int default_par_count = 0; diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index a13bf8009f..5b092e3691 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -581,7 +581,8 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va } void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) { - if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) { + // Avoid validated evaluator for modulo and division when operands are int, since there's no check for division by zero. + if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand) && ((p_operator != Variant::OP_DIVIDE && p_operator != Variant::OP_MODULE) || p_left_operand.type.builtin_type != Variant::INT || p_right_operand.type.builtin_type != Variant::INT)) { if (p_target.mode == Address::TEMPORARY) { Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); Variant::Type temp_type = temporaries[p_target.address].type; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index efa75528fc..35c9946bc1 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2265,13 +2265,15 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type, p_script); + int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type]; + p_script->native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx]; + ERR_FAIL_COND_V(p_script->native.is_null(), ERR_BUG); + // Inheritance switch (base_type.kind) { - case GDScriptDataType::NATIVE: { - int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type]; - p_script->native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx]; - ERR_FAIL_COND_V(p_script->native.is_null(), ERR_BUG); - } break; + case GDScriptDataType::NATIVE: + // Nothing more to do. + break; case GDScriptDataType::GDSCRIPT: { Ref<GDScript> base = Ref<GDScript>(base_type.script_type); if (base.is_null()) { @@ -2303,7 +2305,6 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri p_script->base = base; p_script->_base = base.ptr(); p_script->member_indices = base->member_indices; - p_script->native = base->native; } break; default: { _set_error("Parser bug: invalid inheritance.", nullptr); diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index ba400b8e15..83d2ed6010 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -1326,28 +1326,30 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; } - ScriptInstance *scr_inst = val_obj->get_script_instance(); - if (!scr_inst) { - err_text = "Trying to assign value of type '" + val_obj->get_class_name() + - "' to a variable of type '" + base_type->get_path().get_file() + "'."; - OPCODE_BREAK; - } + if (val_obj) { // src is not null + ScriptInstance *scr_inst = val_obj->get_script_instance(); + if (!scr_inst) { + err_text = "Trying to assign value of type '" + val_obj->get_class_name() + + "' to a variable of type '" + base_type->get_path().get_file() + "'."; + OPCODE_BREAK; + } - Script *src_type = val_obj->get_script_instance()->get_script().ptr(); - bool valid = false; + Script *src_type = scr_inst->get_script().ptr(); + bool valid = false; - while (src_type) { - if (src_type == base_type) { - valid = true; - break; + while (src_type) { + if (src_type == base_type) { + valid = true; + break; + } + src_type = src_type->get_base_script().ptr(); } - src_type = src_type->get_base_script().ptr(); - } - if (!valid) { - err_text = "Trying to assign value of type '" + val_obj->get_script_instance()->get_script()->get_path().get_file() + - "' to a variable of type '" + base_type->get_path().get_file() + "'."; - OPCODE_BREAK; + if (!valid) { + err_text = "Trying to assign value of type '" + val_obj->get_script_instance()->get_script()->get_path().get_file() + + "' to a variable of type '" + base_type->get_path().get_file() + "'."; + OPCODE_BREAK; + } } } #endif // DEBUG_ENABLED diff --git a/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.gd new file mode 100644 index 0000000000..1644295b38 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.gd @@ -0,0 +1,3 @@ +func test(): + var foo: Foo + print('not ok') diff --git a/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.out b/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.out new file mode 100644 index 0000000000..3f6c2d868d --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Could not find type "Foo" in the current scope. diff --git a/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.gd b/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.gd new file mode 100644 index 0000000000..6c056530f6 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.gd @@ -0,0 +1,10 @@ +func test(): + print("ok") + +# https://github.com/godotengine/godot/issues/71994 +class A: + extends RefCounted +class B: + extends A + func duplicate(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.out b/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.out new file mode 100644 index 0000000000..1b47ed10dc --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.out @@ -0,0 +1,2 @@ +GDTEST_OK +ok diff --git a/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.gd b/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.gd new file mode 100644 index 0000000000..1b47680a7b --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.gd @@ -0,0 +1,18 @@ +extends Node + +class LocalClass extends Node: + pass + +func test(): + var typed: LocalClass = get_node_or_null("does_not_exist") + var untyped = null + var node_1: LocalClass = typed + var node_2: LocalClass = untyped + var node_3 = typed + var node_4 = untyped + print(typed) + print(untyped) + print(node_1) + print(node_2) + print(node_3) + print(node_4) diff --git a/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.out b/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.out new file mode 100644 index 0000000000..d66b72f5c3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.out @@ -0,0 +1,7 @@ +GDTEST_OK +<Object#null> +<null> +<Object#null> +<null> +<Object#null> +<null> |