Преглед изворни кода

GDScript: Don't coerce default values to the export hint type

This behavior is inconsistent with non tools builds and can create
issues. Instead, a warning is emitted if there's a type mismatch. If the
type can't be converted, an error is shown instead.

For the editor it gives a converted value to avoid issues with the
property editor, which expects the correct type.
George Marques пре 3 година
родитељ
комит
f2166ba92f

+ 3 - 0
doc/classes/ProjectSettings.xml

@@ -321,6 +321,9 @@
 		<member name="debug/gdscript/warnings/exclude_addons" type="bool" setter="" getter="" default="true">
 			If [code]true[/code], scripts in the [code]res://addons[/code] folder will not generate warnings.
 		</member>
+		<member name="debug/gdscript/warnings/export_hint_type_mistmatch" type="bool" setter="" getter="" default="true">
+			If [code]true[/code], enables warnings when the type of the default value set to an exported variable is different than the specified export type.
+		</member>
 		<member name="debug/gdscript/warnings/function_conflicts_constant" type="bool" setter="" getter="" default="true">
 			If [code]true[/code], enables warnings when a function is declared with the same name as a constant.
 		</member>

+ 18 - 1
modules/gdscript/gdscript.cpp

@@ -450,7 +450,19 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
 				}
 
 				members_cache.push_back(c->variables[i]._export);
-				member_default_values_cache[c->variables[i].identifier] = c->variables[i].default_value;
+
+				Variant::Type default_value_type = c->variables[i].default_value.get_type();
+				Variant::Type export_type = c->variables[i]._export.type;
+
+				// Convert the default value to the export type to avoid issues with the property editor and scene serialization.
+				// This is done only in the export side, the script itself will use the default value with no type change.
+				if (default_value_type != Variant::NIL && default_value_type != export_type) {
+					Variant::CallError ce;
+					const Variant *args = &c->variables[i].default_value;
+					member_default_values_cache[c->variables[i].identifier] = Variant::construct(export_type, &args, 1, ce);
+				} else {
+					member_default_values_cache[c->variables[i].identifier] = c->variables[i].default_value;
+				}
 			}
 
 			_signals.clear();
@@ -2014,6 +2026,10 @@ String GDScriptWarning::get_message() const {
 		case STANDALONE_TERNARY: {
 			return "Standalone ternary conditional operator: the return value is being discarded.";
 		}
+		case EXPORT_HINT_TYPE_MISTMATCH: {
+			CHECK_SYMBOLS(2);
+			return vformat("The type of the default value (%s) doesn't match the type of the export hint (%s). The type won't be coerced.", symbols[0], symbols[1]);
+		}
 		case WARNING_MAX:
 			break; // Can't happen, but silences warning
 	}
@@ -2057,6 +2073,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
 		"UNSAFE_CALL_ARGUMENT",
 		"DEPRECATED_KEYWORD",
 		"STANDALONE_TERNARY",
+		"EXPORT_HINT_TYPE_MISTMATCH",
 		nullptr
 	};
 

+ 1 - 0
modules/gdscript/gdscript.h

@@ -304,6 +304,7 @@ struct GDScriptWarning {
 		UNSAFE_CALL_ARGUMENT, // Function call argument is of a supertype of the require argument
 		DEPRECATED_KEYWORD, // The keyword is deprecated and should be replaced
 		STANDALONE_TERNARY, // Return value of ternary expression is discarded
+		EXPORT_HINT_TYPE_MISTMATCH, // The type of the variable's default value doesn't match its export hint
 		WARNING_MAX,
 	} code;
 	Vector<String> symbols;

+ 6 - 6
modules/gdscript/gdscript_parser.cpp

@@ -4995,21 +4995,21 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
 						}
 					}
 #ifdef TOOLS_ENABLED
+					// Warn if the default value set is not the same as the export type, since it won't be coerced and
+					// may create wrong expectations.
 					if (subexpr->type == Node::TYPE_CONSTANT && (member._export.type != Variant::NIL || member.data_type.has_type)) {
 						ConstantNode *cn = static_cast<ConstantNode *>(subexpr);
 						if (cn->value.get_type() != Variant::NIL) {
 							if (member._export.type != Variant::NIL && cn->value.get_type() != member._export.type) {
-								if (Variant::can_convert(cn->value.get_type(), member._export.type)) {
-									Variant::CallError err;
-									const Variant *args = &cn->value;
-									cn->value = Variant::construct(member._export.type, &args, 1, err);
-								} else {
+								if (!Variant::can_convert(cn->value.get_type(), member._export.type)) {
 									_set_error("Can't convert the provided value to the export type.");
 									return;
+								} else if (!member.data_type.has_type) {
+									_add_warning(GDScriptWarning::EXPORT_HINT_TYPE_MISTMATCH, member.line, Variant::get_type_name(cn->value.get_type()), Variant::get_type_name(member._export.type));
 								}
 							}
-							member.default_value = cn->value;
 						}
+						member.default_value = cn->value;
 					}
 #endif