diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index f53305d05d0..2d44b60cbb8 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -321,6 +321,9 @@ If [code]true[/code], scripts in the [code]res://addons[/code] folder will not generate warnings. + + 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. + If [code]true[/code], enables warnings when a function is declared with the same name as a constant. diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 81956f8df3d..30dc90ee00a 100644 --- a/modules/gdscript/gdscript.cpp +++ b/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 }; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 959ec776171..24ac74858b4 100644 --- a/modules/gdscript/gdscript.h +++ b/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 symbols; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 0c5f5d29ccc..dc0d6c82efc 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/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(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