summaryrefslogtreecommitdiffstats
path: root/modules/gdscript
diff options
context:
space:
mode:
authorGeorge Marques <george@gmarqu.es>2024-07-09 12:45:07 -0300
committerGeorge Marques <george@gmarqu.es>2024-07-09 13:01:59 -0300
commit87c90a573c26ddcbe1b5d9f523b57a89d76dc6df (patch)
tree083ec843980f4ae85343ad488c33207bebfc83fe /modules/gdscript
parent82cedc83c9069125207c128f9a07ce3d82c317cc (diff)
downloadredot-engine-87c90a573c26ddcbe1b5d9f523b57a89d76dc6df.tar.gz
GDScript: Call setter on simple setter chain without getter
Fixes a bug where a member variable was being set directly before calling the setter.
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/gdscript_compiler.cpp13
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd13
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out4
3 files changed, 30 insertions, 0 deletions
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/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)