diff options
author | RĂ©mi Verschelde <rverschelde@gmail.com> | 2019-03-04 12:27:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-04 12:27:20 +0100 |
commit | 2bc981948d254f45a0268cfc26eb0010f00b984c (patch) | |
tree | 3b068d33d62b9a0b529ea837056b9f6d215af3f3 /modules/gdscript/gdscript_parser.cpp | |
parent | 49d82f245bf11bd9064c9de24704cbec2181b5ba (diff) | |
parent | 425ec6914c40ed0654db16f417e80daa2a84cdd0 (diff) |
Merge pull request #26573 from godotengine/revert-26562-gdscript-no-implicit-cast
Revert "Forbid implicit type conversion in GDScript"
Diffstat (limited to 'modules/gdscript/gdscript_parser.cpp')
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 105 |
1 files changed, 95 insertions, 10 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 687bf40cdd..5619729c13 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -5801,7 +5801,7 @@ Variant::Operator GDScriptParser::_get_variant_operation(const OperatorNode::Ope } } -bool GDScriptParser::_is_type_compatible(const DataType &p_container, const DataType &p_expression) const { +bool GDScriptParser::_is_type_compatible(const DataType &p_container, const DataType &p_expression, bool p_allow_implicit_conversion) const { // Ignore for completion if (!check_types || for_completion) { return true; @@ -5817,6 +5817,9 @@ bool GDScriptParser::_is_type_compatible(const DataType &p_container, const Data if (p_container.kind == DataType::BUILTIN && p_expression.kind == DataType::BUILTIN) { bool valid = p_container.builtin_type == p_expression.builtin_type; + if (p_allow_implicit_conversion) { + valid = valid || Variant::can_convert_strict(p_expression.builtin_type, p_container.builtin_type); + } return valid; } @@ -6685,7 +6688,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat arg_type.native_type = mi.arguments[i].class_name; } - if (!_is_type_compatible(arg_type, par_types[i])) { + if (!_is_type_compatible(arg_type, par_types[i], true)) { types_match = false; break; } else { @@ -6927,7 +6930,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat if (par_type.may_yield && p_call->arguments[i]->type == Node::TYPE_OPERATOR) { _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, p_call->line, _find_function_name(static_cast<OperatorNode *>(p_call->arguments[i]))); } - } else if (!_is_type_compatible(arg_types[i - arg_diff], par_type)) { + } else if (!_is_type_compatible(arg_types[i - arg_diff], par_type, true)) { // Supertypes are acceptable for dynamic compliance if (!_is_type_compatible(par_type, arg_types[i - arg_diff])) { _set_error("At '" + callee_name + "()' call, argument " + itos(i - arg_diff + 1) + ". Assigned type (" + @@ -7390,6 +7393,33 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { // Try supertype test if (_is_type_compatible(expr_type, v.data_type)) { _mark_line_as_unsafe(v.line); + } else { + // Try with implicit conversion + if (v.data_type.kind != DataType::BUILTIN || !_is_type_compatible(v.data_type, expr_type, true)) { + _set_error("Assigned expression type (" + expr_type.to_string() + ") doesn't match the variable's type (" + + v.data_type.to_string() + ").", + v.line); + return; + } + + // Replace assignment with implict conversion + BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); + convert->line = v.line; + convert->function = GDScriptFunctions::TYPE_CONVERT; + + ConstantNode *tgt_type = alloc_node<ConstantNode>(); + tgt_type->line = v.line; + tgt_type->value = (int)v.data_type.builtin_type; + + OperatorNode *convert_call = alloc_node<OperatorNode>(); + convert_call->line = v.line; + convert_call->op = OperatorNode::OP_CALL; + convert_call->arguments.push_back(convert); + convert_call->arguments.push_back(v.expression); + convert_call->arguments.push_back(tgt_type); + + v.expression = convert_call; + v.initial_assignment->arguments.write[1] = convert_call; } } @@ -7430,7 +7460,7 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { // Check export hint if (v.data_type.has_type && v._export.type != Variant::NIL) { DataType export_type = _type_from_property(v._export); - if (!_is_type_compatible(v.data_type, export_type)) { + if (!_is_type_compatible(v.data_type, export_type, true)) { _set_error("Export hint type (" + export_type.to_string() + ") doesn't match the variable's type (" + v.data_type.to_string() + ").", v.line); @@ -7551,7 +7581,7 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) { } else { p_function->return_type = _resolve_type(p_function->return_type, p_function->line); - if (!_is_type_compatible(p_function->argument_types[i], def_type)) { + if (!_is_type_compatible(p_function->argument_types[i], def_type, true)) { String arg_name = p_function->arguments[i]; _set_error("Value type (" + def_type.to_string() + ") doesn't match the type of argument '" + arg_name + "' (" + p_function->arguments[i] + ")", @@ -7739,13 +7769,41 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { } #endif // DEBUG_ENABLED - if (check_types && !_is_type_compatible(lv->datatype, assign_type)) { + if (!_is_type_compatible(lv->datatype, assign_type)) { // Try supertype test if (_is_type_compatible(assign_type, lv->datatype)) { _mark_line_as_unsafe(lv->line); } else { - _set_error("Assigned value type (" + assign_type.to_string() + ") does not match variable type (" + lv->datatype.to_string() + ")", lv->line); - return; + // Try implict conversion + if (lv->datatype.kind != DataType::BUILTIN || !_is_type_compatible(lv->datatype, assign_type, true)) { + _set_error("Assigned value type (" + assign_type.to_string() + ") doesn't match the variable's type (" + + lv->datatype.to_string() + ").", + lv->line); + return; + } + // Replace assignment with implict conversion + BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); + convert->line = lv->line; + convert->function = GDScriptFunctions::TYPE_CONVERT; + + ConstantNode *tgt_type = alloc_node<ConstantNode>(); + tgt_type->line = lv->line; + tgt_type->value = (int)lv->datatype.builtin_type; + + OperatorNode *convert_call = alloc_node<OperatorNode>(); + convert_call->line = lv->line; + convert_call->op = OperatorNode::OP_CALL; + convert_call->arguments.push_back(convert); + convert_call->arguments.push_back(lv->assign); + convert_call->arguments.push_back(tgt_type); + + lv->assign = convert_call; + lv->assign_op->arguments.write[1] = convert_call; +#ifdef DEBUG_ENABLED + if (lv->datatype.builtin_type == Variant::INT && assign_type.builtin_type == Variant::REAL) { + _add_warning(GDScriptWarning::NARROWING_CONVERSION, lv->line); + } +#endif // DEBUG_ENABLED } } if (lv->datatype.infer_type) { @@ -7847,8 +7905,35 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { if (_is_type_compatible(rh_type, lh_type)) { _mark_line_as_unsafe(op->line); } else { - _set_error("Assigned value type (" + rh_type.to_string() + ") does not match variable type (" + lh_type.to_string() + ")", op->line); - return; + // Try implict conversion + if (lh_type.kind != DataType::BUILTIN || !_is_type_compatible(lh_type, rh_type, true)) { + _set_error("Assigned value type (" + rh_type.to_string() + ") doesn't match the variable's type (" + + lh_type.to_string() + ").", + op->line); + return; + } + // Replace assignment with implict conversion + BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); + convert->line = op->line; + convert->function = GDScriptFunctions::TYPE_CONVERT; + + ConstantNode *tgt_type = alloc_node<ConstantNode>(); + tgt_type->line = op->line; + tgt_type->value = (int)lh_type.builtin_type; + + OperatorNode *convert_call = alloc_node<OperatorNode>(); + convert_call->line = op->line; + convert_call->op = OperatorNode::OP_CALL; + convert_call->arguments.push_back(convert); + convert_call->arguments.push_back(op->arguments[1]); + convert_call->arguments.push_back(tgt_type); + + op->arguments.write[1] = convert_call; +#ifdef DEBUG_ENABLED + if (lh_type.builtin_type == Variant::INT && rh_type.builtin_type == Variant::REAL) { + _add_warning(GDScriptWarning::NARROWING_CONVERSION, op->line); + } +#endif // DEBUG_ENABLED } } #ifdef DEBUG_ENABLED |