diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index b0ac4aa8007..13707de12ab 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1064,6 +1064,8 @@ 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); + const bool base_known_type = base.type.has_type; + const bool base_is_shared = Variant::is_type_shared(base.type.builtin_type); if (r_error) { return GDScriptCodeGenerator::Address(); @@ -1074,7 +1076,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // 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) { + if ((!base_known_type || !base_is_shared) && 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; @@ -1229,8 +1231,14 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } } } else if (base_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + if (!base_known_type) { + gen->write_jump_if_shared(base); + } // Save the temp value back to the base by calling its setter. gen->write_call(GDScriptCodeGenerator::Address(), base, member_property_setter_function, { assigned }); + if (!base_known_type) { + gen->write_end_jump_if_shared(); + } } if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { diff --git a/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.gd b/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.gd new file mode 100644 index 00000000000..f70b521e1a4 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.gd @@ -0,0 +1,62 @@ +# GH-94667 + +class Inner: + var subprop: Vector2: + set(value): + prints("subprop setter", value) + subprop = value + get: + print("subprop getter") + return subprop + + func _to_string() -> String: + return "" + +var prop1: + set(value): + prints("prop1 setter", value) + prop1 = value + +var prop2: Inner: + set(value): + prints("prop2 setter", value) + prop2 = value + +var prop3: + set(value): + prints("prop3 setter", value) + prop3 = value + get: + print("prop3 getter") + return prop3 + +var prop4: Inner: + set(value): + prints("prop4 setter", value) + prop4 = value + get: + print("prop4 getter") + return prop4 + +func test(): + print("===") + prop1 = Vector2() + prop1.x = 1.0 + print("---") + prop1 = Inner.new() + prop1.subprop.x = 1.0 + + print("===") + prop2 = Inner.new() + prop2.subprop.x = 1.0 + + print("===") + prop3 = Vector2() + prop3.x = 1.0 + print("---") + prop3 = Inner.new() + prop3.subprop.x = 1.0 + + print("===") + prop4 = Inner.new() + prop4.subprop.x = 1.0 diff --git a/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.out b/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.out new file mode 100644 index 00000000000..c51759f4815 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.out @@ -0,0 +1,26 @@ +GDTEST_OK +=== +prop1 setter (0, 0) +prop1 setter (1, 0) +--- +prop1 setter +subprop getter +subprop setter (1, 0) +=== +prop2 setter +subprop getter +subprop setter (1, 0) +=== +prop3 setter (0, 0) +prop3 getter +prop3 setter (1, 0) +--- +prop3 setter +prop3 getter +subprop getter +subprop setter (1, 0) +=== +prop4 setter +prop4 getter +subprop getter +subprop setter (1, 0)