Merge pull request #34333 from vnen/gdscript-assign-op

Fix some cases where typed assignment gets invalid
This commit is contained in:
Rémi Verschelde 2019-12-13 20:13:12 +01:00 committed by GitHub
commit e65db6a16b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 23 deletions

View file

@ -946,18 +946,29 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
{ {
const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
if (E) { if (E) {
if (E->get().setter) { const GDScript::MemberInfo *member = &E->get();
if (member->setter) {
const Variant *val = &p_value; const Variant *val = &p_value;
Variant::CallError err; Variant::CallError err;
call(E->get().setter, &val, 1, err); call(member->setter, &val, 1, err);
if (err.error == Variant::CallError::CALL_OK) { if (err.error == Variant::CallError::CALL_OK) {
return true; //function exists, call was successful return true; //function exists, call was successful
} }
} else { } else {
if (!E->get().data_type.is_type(p_value)) { if (!member->data_type.is_type(p_value)) {
return false; // Type mismatch // Try conversion
Variant::CallError ce;
const Variant *value = &p_value;
Variant converted = Variant::construct(member->data_type.builtin_type, &value, 1, ce);
if (ce.error == Variant::CallError::CALL_OK) {
members.write[member->index] = converted;
return true;
} else {
return false;
}
} else {
members.write[member->index] = p_value;
} }
members.write[E->get().index] = p_value;
} }
return true; return true;
} }

View file

@ -1144,7 +1144,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
GDScriptDataType assign_type = _gdtype_from_datatype(on->arguments[0]->get_datatype()); GDScriptDataType assign_type = _gdtype_from_datatype(on->arguments[0]->get_datatype());
if (assign_type.has_type && !on->arguments[1]->get_datatype().has_type) { if (assign_type.has_type && !on->datatype.has_type) {
// Typed assignment // Typed assignment
switch (assign_type.kind) { switch (assign_type.kind) {
case GDScriptDataType::BUILTIN: { case GDScriptDataType::BUILTIN: {

View file

@ -764,15 +764,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_VARIANT_PTR(dst, 2); GET_VARIANT_PTR(dst, 2);
GET_VARIANT_PTR(src, 3); GET_VARIANT_PTR(src, 3);
#ifdef DEBUG_ENABLED
Variant::Type var_type = (Variant::Type)_code_ptr[ip + 1]; Variant::Type var_type = (Variant::Type)_code_ptr[ip + 1];
GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX); GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
if (src->get_type() != var_type) { if (src->get_type() != var_type) {
#ifdef DEBUG_ENABLED
if (Variant::can_convert_strict(src->get_type(), var_type)) { if (Variant::can_convert_strict(src->get_type(), var_type)) {
#endif // DEBUG_ENABLED
Variant::CallError ce; Variant::CallError ce;
*dst = Variant::construct(var_type, const_cast<const Variant **>(&src), 1, ce); *dst = Variant::construct(var_type, const_cast<const Variant **>(&src), 1, ce);
} else { } else {
#ifdef DEBUG_ENABLED
err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) + err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
"' to a variable of type '" + Variant::get_type_name(var_type) + "'."; "' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
OPCODE_BREAK; OPCODE_BREAK;
@ -780,9 +782,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} else { } else {
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED
*dst = *src; *dst = *src;
#ifdef DEBUG_ENABLED
} }
#endif // DEBUG_ENABLED
ip += 4; ip += 4;
} }

View file

@ -8185,7 +8185,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
} }
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED
bool type_match = check_types;
if (check_types && !_is_type_compatible(lh_type, rh_type)) { if (check_types && !_is_type_compatible(lh_type, rh_type)) {
type_match = false;
// Try supertype test // Try supertype test
if (_is_type_compatible(rh_type, lh_type)) { if (_is_type_compatible(rh_type, lh_type)) {
_mark_line_as_unsafe(op->line); _mark_line_as_unsafe(op->line);
@ -8197,6 +8199,7 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
op->line); op->line);
return; return;
} }
if (op->op == OperatorNode::OP_ASSIGN) {
// Replace assignment with implicit conversion // Replace assignment with implicit conversion
BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>();
convert->line = op->line; convert->line = op->line;
@ -8214,6 +8217,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
convert_call->arguments.push_back(tgt_type); convert_call->arguments.push_back(tgt_type);
op->arguments.write[1] = convert_call; op->arguments.write[1] = convert_call;
type_match = true; // Since we are converting, the type is matching
}
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (lh_type.builtin_type == Variant::INT && rh_type.builtin_type == Variant::REAL) { if (lh_type.builtin_type == Variant::INT && rh_type.builtin_type == Variant::REAL) {
_add_warning(GDScriptWarning::NARROWING_CONVERSION, op->line); _add_warning(GDScriptWarning::NARROWING_CONVERSION, op->line);
@ -8226,6 +8232,7 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
_mark_line_as_unsafe(op->line); _mark_line_as_unsafe(op->line);
} }
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED
op->datatype.has_type = type_match;
} break; } break;
case OperatorNode::OP_CALL: case OperatorNode::OP_CALL:
case OperatorNode::OP_PARENT_CALL: { case OperatorNode::OP_PARENT_CALL: {