diff options
Diffstat (limited to 'modules/gdscript')
12 files changed, 80 insertions, 26 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 73b1e44db3..eaf2565e69 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1537,10 +1537,14 @@ void GDScript::clear(ClearData *p_clear_data) { } } - RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies(); - for (GDScript *E : must_clear_dependencies) { - clear_data->scripts.insert(E); - E->clear(clear_data); + // If we're in the process of shutting things down then every single script will be cleared + // anyway, so we can safely skip this very costly operation. + if (!GDScriptLanguage::singleton->finishing) { + RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies(); + for (GDScript *E : must_clear_dependencies) { + clear_data->scripts.insert(E); + E->clear(clear_data); + } } for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) { @@ -2246,6 +2250,11 @@ String GDScriptLanguage::get_extension() const { } void GDScriptLanguage::finish() { + if (finishing) { + return; + } + finishing = true; + _call_stack.free(); // Clear the cache before parsing the script_list @@ -2281,6 +2290,8 @@ void GDScriptLanguage::finish() { } script_list.clear(); function_list.clear(); + + finishing = false; } void GDScriptLanguage::profiling_start() { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index d097cb193b..4e78fbe302 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -411,6 +411,8 @@ class GDScriptLanguage : public ScriptLanguage { static GDScriptLanguage *singleton; + bool finishing = false; + Variant *_global_array = nullptr; Vector<Variant> global_array; HashMap<StringName, int> globals; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 5469dad3f7..b0ac4aa800 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1064,12 +1064,22 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Get at (potential) root stack pos, so it can be returned. GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, chain.back()->get()->base); + if (r_error) { return GDScriptCodeGenerator::Address(); } GDScriptCodeGenerator::Address prev_base = base; + // In case the base has a setter, don't use the address directly, as we want to call that setter. + // So use a temp value instead and call the setter at the end. + GDScriptCodeGenerator::Address base_temp; + if (base.mode == GDScriptCodeGenerator::Address::MEMBER && member_property_has_setter && !member_property_is_in_setter) { + base_temp = codegen.add_temporary(base.type); + gen->write_assign(base_temp, base); + prev_base = base_temp; + } + struct ChainInfo { bool is_named = false; GDScriptCodeGenerator::Address base; @@ -1218,6 +1228,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code gen->write_end_jump_if_shared(); } } + } else if (base_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + // Save the temp value back to the base by calling its setter. + gen->write_call(GDScriptCodeGenerator::Address(), base, member_property_setter_function, { assigned }); } if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index b58b44973e..b1ffc02e4b 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1521,22 +1521,19 @@ static GDScriptCompletionIdentifier _type_from_variant(const Variant &p_value, G } if (scr.is_valid()) { ci.type.script_path = scr->get_path(); + ci.type.script_type = scr; + ci.type.native_type = scr->get_instance_base_type(); + ci.type.kind = GDScriptParser::DataType::SCRIPT; if (scr->get_path().ends_with(".gd")) { - Error err; - Ref<GDScriptParserRef> parser = GDScriptCache::get_parser(scr->get_path(), GDScriptParserRef::INTERFACE_SOLVED, err); - if (err == OK) { + Ref<GDScriptParserRef> parser = p_context.parser->get_depended_parser_for(scr->get_path()); + if (parser.is_valid() && parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED) == OK) { ci.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; ci.type.class_type = parser->get_parser()->get_tree(); ci.type.kind = GDScriptParser::DataType::CLASS; - p_context.dependent_parsers.push_back(parser); return ci; } } - - ci.type.kind = GDScriptParser::DataType::SCRIPT; - ci.type.script_type = scr; - ci.type.native_type = scr->get_instance_base_type(); } else { ci.type.kind = GDScriptParser::DataType::NATIVE; } @@ -1811,8 +1808,6 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, if (mb && mb->is_const()) { bool all_is_const = true; Vector<Variant> args; - GDScriptParser::CompletionContext c2 = p_context; - c2.current_line = call->start_line; for (int i = 0; all_is_const && i < call->arguments.size(); i++) { GDScriptCompletionIdentifier arg; @@ -1849,16 +1844,14 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } if (FileAccess::exists(script)) { - Error err = OK; - Ref<GDScriptParserRef> parser = GDScriptCache::get_parser(script, GDScriptParserRef::INTERFACE_SOLVED, err); - if (err == OK) { + Ref<GDScriptParserRef> parser = p_context.parser->get_depended_parser_for(script); + if (parser.is_valid() && parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED) == OK) { r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.script_path = script; r_type.type.class_type = parser->get_parser()->get_tree(); r_type.type.is_constant = false; r_type.type.kind = GDScriptParser::DataType::CLASS; r_type.value = Variant(); - p_context.dependent_parsers.push_back(parser); found = true; } } @@ -2310,9 +2303,8 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, if (ScriptServer::is_global_class(p_identifier->name)) { String script = ScriptServer::get_global_class_path(p_identifier->name); if (script.to_lower().ends_with(".gd")) { - Error err = OK; - Ref<GDScriptParserRef> parser = GDScriptCache::get_parser(script, GDScriptParserRef::INTERFACE_SOLVED, err); - if (err == OK) { + Ref<GDScriptParserRef> parser = p_context.parser->get_depended_parser_for(script); + if (parser.is_valid() && parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED) == OK) { r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.script_path = script; r_type.type.class_type = parser->get_parser()->get_tree(); @@ -2320,7 +2312,6 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, r_type.type.is_constant = false; r_type.type.kind = GDScriptParser::DataType::CLASS; r_type.value = Variant(); - p_context.dependent_parsers.push_back(parser); return true; } } else { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 433f767f1e..54bb152f7f 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -260,6 +260,7 @@ void GDScriptParser::make_completion_context(CompletionType p_type, Node *p_node context.current_line = tokenizer->get_cursor_line(); context.current_argument = p_argument; context.node = p_node; + context.parser = this; completion_context = context; } @@ -277,6 +278,7 @@ void GDScriptParser::make_completion_context(CompletionType p_type, Variant::Typ context.current_suite = current_suite; context.current_line = tokenizer->get_cursor_line(); context.builtin_type = p_builtin_type; + context.parser = this; completion_context = context; } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 21942222cf..60ee477656 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1314,7 +1314,7 @@ public: Variant::Type builtin_type = Variant::VARIANT_MAX; Node *node = nullptr; Object *base = nullptr; - List<Ref<GDScriptParserRef>> dependent_parsers; + GDScriptParser *parser = nullptr; }; struct CompletionCall { diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 5b1639e250..404b61fb40 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -574,7 +574,9 @@ GDScriptTokenizer::Token GDScriptTokenizerText::potential_identifier() { if (len == 1 && _peek(-1) == '_') { // Lone underscore. - return make_token(Token::UNDERSCORE); + Token token = make_token(Token::UNDERSCORE); + token.literal = "_"; + return token; } String name(_start, len); diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 912367764b..5eab8a6306 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -1807,7 +1807,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } else if (methodstr == "free") { if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { if (base->is_ref_counted()) { - err_text = "Attempted to free a reference."; + err_text = "Attempted to free a RefCounted object."; OPCODE_BREAK; } else if (base->get_type() == Variant::OBJECT) { err_text = "Attempted to free a locked object (calling or emitting)."; @@ -1898,7 +1898,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } else if (methodstr == "free") { if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { if (base->is_ref_counted()) { - err_text = "Attempted to free a reference."; + err_text = "Attempted to free a RefCounted object."; OPCODE_BREAK; } else if (base->get_type() == Variant::OBJECT) { err_text = "Attempted to free a locked object (calling or emitting)."; diff --git a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd new file mode 100644 index 0000000000..9e27a500bf --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd @@ -0,0 +1,13 @@ +# https://github.com/godotengine/godot/issues/85952 + +var vec: Vector2 = Vector2.ZERO: + set(new_vec): + prints("setting vec from", vec, "to", new_vec) + if new_vec == Vector2(1, 1): + vec = new_vec + +func test(): + vec.x = 2 + vec.y = 2 + + prints("vec is", vec) diff --git a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out new file mode 100644 index 0000000000..31b3b3a3a8 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out @@ -0,0 +1,4 @@ +GDTEST_OK +setting vec from (0, 0) to (2, 0) +setting vec from (0, 0) to (0, 2) +vec is (0, 0) diff --git a/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd new file mode 100644 index 0000000000..b07c40b6da --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd @@ -0,0 +1,15 @@ +extends Node + +func test() -> void: + var node1 := Node.new() + node1.name = "_" + var node2 := Node.new() + node2.name = "Child" + var node3 := Node.new() + node3.name = "Child" + + add_child(node1) + node1.add_child(node2) + add_child(node3) + + assert(get_node("_/Child") == $_/Child) diff --git a/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out @@ -0,0 +1 @@ +GDTEST_OK |
