diff options
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/gdscript/gdscript_function.cpp | 11 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_function.h | 8 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 105 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_parser.h | 2 | 
4 files changed, 110 insertions, 16 deletions
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index b2757f1b0b..cff9ba55b8 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -328,8 +328,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  						continue;  					} -					if (!argument_types[i].is_type(*p_args[i])) { -						if (argument_types[i].is_type(Variant())) { +					if (!argument_types[i].is_type(*p_args[i], true)) { +						if (argument_types[i].is_type(Variant(), true)) {  							memnew_placement(&stack[i], Variant);  							continue;  						} else { @@ -339,7 +339,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  							return Variant();  						}  					} -					memnew_placement(&stack[i], Variant(*p_args[i])); +					if (argument_types[i].kind == GDScriptDataType::BUILTIN) { +						Variant arg = Variant::construct(argument_types[i].builtin_type, &p_args[i], 1, r_err); +						memnew_placement(&stack[i], Variant(arg)); +					} else { +						memnew_placement(&stack[i], Variant(*p_args[i])); +					}  				}  				for (int i = p_argcount; i < _stack_size; i++) {  					memnew_placement(&stack[i], Variant); diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 34fc51e92a..cefc28d77f 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -55,7 +55,7 @@ struct GDScriptDataType {  	StringName native_type;  	Ref<Script> script_type; -	bool is_type(const Variant &p_variant) const { +	bool is_type(const Variant &p_variant, bool p_allow_implicit_conversion = false) const {  		if (!has_type) return true; // Can't type check  		switch (kind) { @@ -63,7 +63,11 @@ struct GDScriptDataType {  				break;  			case BUILTIN: {  				Variant::Type var_type = p_variant.get_type(); -				return builtin_type == var_type; +				bool valid = builtin_type == var_type; +				if (!valid && p_allow_implicit_conversion) { +					valid = Variant::can_convert_strict(var_type, builtin_type); +				} +				return valid;  			} break;  			case NATIVE: {  				if (p_variant.get_type() == Variant::NIL) { 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 diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 167132e390..809bff8f20 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -607,7 +607,7 @@ private:  	Variant::Operator _get_variant_operation(const OperatorNode::Operator &p_op) const;  	bool _get_function_signature(DataType &p_base_type, const StringName &p_function, DataType &r_return_type, List<DataType> &r_arg_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) const;  	bool _get_member_type(const DataType &p_base_type, const StringName &p_member, DataType &r_member_type) const; -	bool _is_type_compatible(const DataType &p_container, const DataType &p_expression) const; +	bool _is_type_compatible(const DataType &p_container, const DataType &p_expression, bool p_allow_implicit_conversion = false) const;  	DataType _reduce_node_type(Node *p_node);  	DataType _reduce_function_call_type(const OperatorNode *p_call);  |