Merge pull request #62462 from vnen/gdscript-setter-chaining
GDScript: Fix setter being called in chains for shared types
This commit is contained in:
commit
c4a426d6ec
9 changed files with 104 additions and 23 deletions
|
@ -3327,13 +3327,20 @@ Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Varia
|
||||||
void Variant::static_assign(const Variant &p_variant) {
|
void Variant::static_assign(const Variant &p_variant) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Variant::is_shared() const {
|
bool Variant::is_type_shared(Variant::Type p_type) {
|
||||||
switch (type) {
|
switch (p_type) {
|
||||||
case OBJECT:
|
case OBJECT:
|
||||||
return true;
|
|
||||||
case ARRAY:
|
case ARRAY:
|
||||||
return true;
|
|
||||||
case DICTIONARY:
|
case DICTIONARY:
|
||||||
|
case PACKED_BYTE_ARRAY:
|
||||||
|
case PACKED_INT32_ARRAY:
|
||||||
|
case PACKED_INT64_ARRAY:
|
||||||
|
case PACKED_FLOAT32_ARRAY:
|
||||||
|
case PACKED_FLOAT64_ARRAY:
|
||||||
|
case PACKED_STRING_ARRAY:
|
||||||
|
case PACKED_VECTOR2_ARRAY:
|
||||||
|
case PACKED_VECTOR3_ARRAY:
|
||||||
|
case PACKED_COLOR_ARRAY:
|
||||||
return true;
|
return true;
|
||||||
default: {
|
default: {
|
||||||
}
|
}
|
||||||
|
@ -3342,6 +3349,10 @@ bool Variant::is_shared() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Variant::is_shared() const {
|
||||||
|
return is_type_shared(type);
|
||||||
|
}
|
||||||
|
|
||||||
void Variant::_variant_call_error(const String &p_method, Callable::CallError &error) {
|
void Variant::_variant_call_error(const String &p_method, Callable::CallError &error) {
|
||||||
switch (error.error) {
|
switch (error.error) {
|
||||||
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
|
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
|
||||||
|
|
|
@ -297,6 +297,7 @@ public:
|
||||||
static String get_type_name(Variant::Type p_type);
|
static String get_type_name(Variant::Type p_type);
|
||||||
static bool can_convert(Type p_type_from, Type p_type_to);
|
static bool can_convert(Type p_type_from, Type p_type_to);
|
||||||
static bool can_convert_strict(Type p_type_from, Type p_type_to);
|
static bool can_convert_strict(Type p_type_from, Type p_type_to);
|
||||||
|
static bool is_type_shared(Variant::Type p_type);
|
||||||
|
|
||||||
bool is_ref_counted() const;
|
bool is_ref_counted() const;
|
||||||
_FORCE_INLINE_ bool is_num() const {
|
_FORCE_INLINE_ bool is_num() const {
|
||||||
|
|
|
@ -1336,6 +1336,18 @@ void GDScriptByteCodeGenerator::write_endif() {
|
||||||
if_jmp_addrs.pop_back();
|
if_jmp_addrs.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GDScriptByteCodeGenerator::write_jump_if_shared(const Address &p_value) {
|
||||||
|
append(GDScriptFunction::OPCODE_JUMP_IF_SHARED, 1);
|
||||||
|
append(p_value);
|
||||||
|
if_jmp_addrs.push_back(opcodes.size());
|
||||||
|
append(0); // Jump destination, will be patched.
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDScriptByteCodeGenerator::write_end_jump_if_shared() {
|
||||||
|
patch_jump(if_jmp_addrs.back()->get());
|
||||||
|
if_jmp_addrs.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
void GDScriptByteCodeGenerator::start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) {
|
void GDScriptByteCodeGenerator::start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) {
|
||||||
Address counter(Address::LOCAL_VARIABLE, add_local("@counter_pos", p_iterator_type), p_iterator_type);
|
Address counter(Address::LOCAL_VARIABLE, add_local("@counter_pos", p_iterator_type), p_iterator_type);
|
||||||
Address container(Address::LOCAL_VARIABLE, add_local("@container_pos", p_list_type), p_list_type);
|
Address container(Address::LOCAL_VARIABLE, add_local("@container_pos", p_list_type), p_list_type);
|
||||||
|
|
|
@ -479,6 +479,8 @@ public:
|
||||||
virtual void write_if(const Address &p_condition) override;
|
virtual void write_if(const Address &p_condition) override;
|
||||||
virtual void write_else() override;
|
virtual void write_else() override;
|
||||||
virtual void write_endif() override;
|
virtual void write_endif() override;
|
||||||
|
virtual void write_jump_if_shared(const Address &p_value) override;
|
||||||
|
virtual void write_end_jump_if_shared() override;
|
||||||
virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) override;
|
virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) override;
|
||||||
virtual void write_for_assignment(const Address &p_variable, const Address &p_list) override;
|
virtual void write_for_assignment(const Address &p_variable, const Address &p_list) override;
|
||||||
virtual void write_for() override;
|
virtual void write_for() override;
|
||||||
|
|
|
@ -140,6 +140,8 @@ public:
|
||||||
virtual void write_if(const Address &p_condition) = 0;
|
virtual void write_if(const Address &p_condition) = 0;
|
||||||
virtual void write_else() = 0;
|
virtual void write_else() = 0;
|
||||||
virtual void write_endif() = 0;
|
virtual void write_endif() = 0;
|
||||||
|
virtual void write_jump_if_shared(const Address &p_value) = 0;
|
||||||
|
virtual void write_end_jump_if_shared() = 0;
|
||||||
virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) = 0;
|
virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) = 0;
|
||||||
virtual void write_for_assignment(const Address &p_variable, const Address &p_list) = 0;
|
virtual void write_for_assignment(const Address &p_variable, const Address &p_list) = 0;
|
||||||
virtual void write_for() = 0;
|
virtual void write_for() = 0;
|
||||||
|
|
|
@ -1056,6 +1056,14 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
||||||
|
|
||||||
// Set back the values into their bases.
|
// Set back the values into their bases.
|
||||||
for (const ChainInfo &info : set_chain) {
|
for (const ChainInfo &info : set_chain) {
|
||||||
|
bool known_type = assigned.type.has_type;
|
||||||
|
bool is_shared = Variant::is_type_shared(assigned.type.builtin_type);
|
||||||
|
|
||||||
|
if (!known_type) {
|
||||||
|
// Jump shared values since they are already updated in-place.
|
||||||
|
gen->write_jump_if_shared(assigned);
|
||||||
|
}
|
||||||
|
if (known_type && !is_shared) {
|
||||||
if (!info.is_named) {
|
if (!info.is_named) {
|
||||||
gen->write_set(info.base, info.key, assigned);
|
gen->write_set(info.base, info.key, assigned);
|
||||||
if (info.key.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
|
if (info.key.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
|
||||||
|
@ -1064,19 +1072,35 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
||||||
} else {
|
} else {
|
||||||
gen->write_set_named(info.base, info.name, assigned);
|
gen->write_set_named(info.base, info.name, assigned);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!known_type) {
|
||||||
|
gen->write_end_jump_if_shared();
|
||||||
|
}
|
||||||
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
|
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
|
||||||
gen->pop_temporary();
|
gen->pop_temporary();
|
||||||
}
|
}
|
||||||
assigned = info.base;
|
assigned = info.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool known_type = assigned.type.has_type;
|
||||||
|
bool is_shared = Variant::is_type_shared(assigned.type.builtin_type);
|
||||||
|
|
||||||
|
if (!known_type || !is_shared) {
|
||||||
// If this is a class member property, also assign to it.
|
// If this is a class member property, also assign to it.
|
||||||
// This allow things like: position.x += 2.0
|
// This allow things like: position.x += 2.0
|
||||||
if (assign_class_member_property != StringName()) {
|
if (assign_class_member_property != StringName()) {
|
||||||
gen->write_set_member(assigned, assign_class_member_property);
|
if (!known_type) {
|
||||||
|
gen->write_jump_if_shared(assigned);
|
||||||
|
}
|
||||||
|
gen->write_set_member(assigned, assign_class_member_property);
|
||||||
|
if (!known_type) {
|
||||||
|
gen->write_end_jump_if_shared();
|
||||||
|
}
|
||||||
|
} else if (is_member_property) {
|
||||||
|
// Same as above but for script members.
|
||||||
|
if (!known_type) {
|
||||||
|
gen->write_jump_if_shared(assigned);
|
||||||
}
|
}
|
||||||
// Same as above but for members
|
|
||||||
if (is_member_property) {
|
|
||||||
if (member_property_has_setter && !member_property_is_in_setter) {
|
if (member_property_has_setter && !member_property_is_in_setter) {
|
||||||
Vector<GDScriptCodeGenerator::Address> args;
|
Vector<GDScriptCodeGenerator::Address> args;
|
||||||
args.push_back(assigned);
|
args.push_back(assigned);
|
||||||
|
@ -1084,6 +1108,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
||||||
} else {
|
} else {
|
||||||
gen->write_assign(target_member_property, assigned);
|
gen->write_assign(target_member_property, assigned);
|
||||||
}
|
}
|
||||||
|
if (!known_type) {
|
||||||
|
gen->write_end_jump_if_shared();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
|
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
|
||||||
|
|
|
@ -838,6 +838,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
|
||||||
|
|
||||||
incr = 1;
|
incr = 1;
|
||||||
} break;
|
} break;
|
||||||
|
case OPCODE_JUMP_IF_SHARED: {
|
||||||
|
text += "jump-if-shared ";
|
||||||
|
text += DADDR(1);
|
||||||
|
text += " to ";
|
||||||
|
text += itos(_code_ptr[ip + 2]);
|
||||||
|
|
||||||
|
incr = 3;
|
||||||
|
} break;
|
||||||
case OPCODE_RETURN: {
|
case OPCODE_RETURN: {
|
||||||
text += "return ";
|
text += "return ";
|
||||||
text += DADDR(1);
|
text += DADDR(1);
|
||||||
|
|
|
@ -304,6 +304,7 @@ public:
|
||||||
OPCODE_JUMP_IF,
|
OPCODE_JUMP_IF,
|
||||||
OPCODE_JUMP_IF_NOT,
|
OPCODE_JUMP_IF_NOT,
|
||||||
OPCODE_JUMP_TO_DEF_ARGUMENT,
|
OPCODE_JUMP_TO_DEF_ARGUMENT,
|
||||||
|
OPCODE_JUMP_IF_SHARED,
|
||||||
OPCODE_RETURN,
|
OPCODE_RETURN,
|
||||||
OPCODE_RETURN_TYPED_BUILTIN,
|
OPCODE_RETURN_TYPED_BUILTIN,
|
||||||
OPCODE_RETURN_TYPED_ARRAY,
|
OPCODE_RETURN_TYPED_ARRAY,
|
||||||
|
|
|
@ -311,6 +311,7 @@ void (*type_init_function_table[])(Variant *) = {
|
||||||
&&OPCODE_JUMP_IF, \
|
&&OPCODE_JUMP_IF, \
|
||||||
&&OPCODE_JUMP_IF_NOT, \
|
&&OPCODE_JUMP_IF_NOT, \
|
||||||
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
|
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
|
||||||
|
&&OPCODE_JUMP_IF_SHARED, \
|
||||||
&&OPCODE_RETURN, \
|
&&OPCODE_RETURN, \
|
||||||
&&OPCODE_RETURN_TYPED_BUILTIN, \
|
&&OPCODE_RETURN_TYPED_BUILTIN, \
|
||||||
&&OPCODE_RETURN_TYPED_ARRAY, \
|
&&OPCODE_RETURN_TYPED_ARRAY, \
|
||||||
|
@ -2361,6 +2362,21 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||||
}
|
}
|
||||||
DISPATCH_OPCODE;
|
DISPATCH_OPCODE;
|
||||||
|
|
||||||
|
OPCODE(OPCODE_JUMP_IF_SHARED) {
|
||||||
|
CHECK_SPACE(3);
|
||||||
|
|
||||||
|
GET_INSTRUCTION_ARG(val, 0);
|
||||||
|
|
||||||
|
if (val->is_shared()) {
|
||||||
|
int to = _code_ptr[ip + 2];
|
||||||
|
GD_ERR_BREAK(to < 0 || to > _code_size);
|
||||||
|
ip = to;
|
||||||
|
} else {
|
||||||
|
ip += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DISPATCH_OPCODE;
|
||||||
|
|
||||||
OPCODE(OPCODE_RETURN) {
|
OPCODE(OPCODE_RETURN) {
|
||||||
CHECK_SPACE(2);
|
CHECK_SPACE(2);
|
||||||
GET_INSTRUCTION_ARG(r, 0);
|
GET_INSTRUCTION_ARG(r, 0);
|
||||||
|
|
Loading…
Reference in a new issue