summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/gdscript.cpp4
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp114
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp8
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h2
-rw-r--r--modules/gdscript/gdscript_codegen.h2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp10
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_shadows_outer_enum.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_shadows_outer_enum.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/variant_arg_in_virtual_method.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/variant_arg_in_virtual_method.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/unnamed_enums_outer_conflicts.gd17
-rw-r--r--modules/gdscript/tests/scripts/parser/features/unnamed_enums_outer_conflicts.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/vector_inf.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/features/vector_inf.out3
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.gd8
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.out8
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.gd19
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out8
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/gdscript.gd20
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/gdscript.out3
30 files changed, 202 insertions, 88 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 7b79c9cf7e..28f478e9cd 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1037,7 +1037,7 @@ String GDScript::get_script_path() const {
}
Error GDScript::load_source_code(const String &p_path) {
- if (p_path.is_empty() || ResourceLoader::get_resource_type(p_path.get_slice("::", 0)) == "PackedScene") {
+ if (p_path.is_empty() || p_path.begins_with("gdscript://") || ResourceLoader::get_resource_type(p_path.get_slice("::", 0)) == "PackedScene") {
return OK;
}
@@ -1363,6 +1363,8 @@ GDScript::GDScript() :
GDScriptLanguage::get_singleton()->script_list.add(&script_list);
}
+
+ path = vformat("gdscript://%d.gd", get_instance_id());
}
void GDScript::_save_orphaned_subclasses(GDScript::ClearData *p_clear_data) {
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 7bde4e7c4b..8afcb431ec 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -68,9 +68,6 @@ static MethodInfo info_from_utility_func(const StringName &p_function) {
pi.name = "arg" + itos(i + 1);
#endif
pi.type = Variant::get_utility_function_argument_type(p_function, i);
- if (pi.type == Variant::NIL) {
- pi.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
info.arguments.push_back(pi);
}
}
@@ -103,8 +100,21 @@ static GDScriptParser::DataType make_native_meta_type(const StringName &p_class_
type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
type.kind = GDScriptParser::DataType::NATIVE;
type.builtin_type = Variant::OBJECT;
- type.is_constant = true;
type.native_type = p_class_name;
+ type.is_constant = true;
+ type.is_meta_type = true;
+ return type;
+}
+
+static GDScriptParser::DataType make_script_meta_type(const Ref<Script> &p_script) {
+ GDScriptParser::DataType type;
+ type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+ type.kind = GDScriptParser::DataType::SCRIPT;
+ type.builtin_type = Variant::OBJECT;
+ type.native_type = p_script->get_instance_base_type();
+ type.script_type = p_script;
+ type.script_path = p_script->get_path();
+ type.is_constant = true;
type.is_meta_type = true;
return type;
}
@@ -421,7 +431,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
return err;
}
base = info_parser->get_parser()->head->get_datatype();
- } else if (class_exists(name) && ClassDB::can_instantiate(name)) {
+ } else if (class_exists(name)) {
base.kind = GDScriptParser::DataType::NATIVE;
base.native_type = name;
} else {
@@ -581,11 +591,8 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result.builtin_type = GDScriptParser::get_builtin_type(first);
if (result.builtin_type == Variant::ARRAY) {
- GDScriptParser::DataType container_type = resolve_datatype(p_type->container_type);
-
+ GDScriptParser::DataType container_type = type_from_metatype(resolve_datatype(p_type->container_type));
if (container_type.kind != GDScriptParser::DataType::VARIANT) {
- container_type.is_meta_type = false;
- container_type.is_constant = false;
result.set_container_element_type(container_type);
}
}
@@ -607,12 +614,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
result = ref->get_parser()->head->get_datatype();
} else {
- result.kind = GDScriptParser::DataType::SCRIPT;
- result.script_type = ResourceLoader::load(path, "Script");
- result.native_type = result.script_type->get_instance_base_type();
- result.script_path = path;
- result.is_constant = true;
- result.is_meta_type = false;
+ result = make_script_meta_type(ResourceLoader::load(path, "Script"));
}
}
} else if (ProjectSettings::get_singleton()->has_autoload(first) && ProjectSettings::get_singleton()->get_autoload(first).is_singleton) {
@@ -656,7 +658,6 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
case GDScriptParser::ClassNode::Member::CONSTANT:
if (member.get_datatype().is_meta_type) {
result = member.get_datatype();
- result.is_meta_type = false;
found = true;
break;
} else if (Ref<Script>(member.constant->initializer->reduced_value).is_valid()) {
@@ -668,15 +669,8 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return bad_type;
}
result = ref->get_parser()->head->get_datatype();
- result.is_meta_type = false;
} else {
- Ref<Script> script = member.constant->initializer->reduced_value;
- result.kind = GDScriptParser::DataType::SCRIPT;
- result.builtin_type = Variant::OBJECT;
- result.script_type = script;
- result.script_path = script->get_path();
- result.native_type = script->get_instance_base_type();
- result.is_meta_type = false;
+ result = make_script_meta_type(member.constant->initializer->reduced_value);
}
found = true;
break;
@@ -832,8 +826,7 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
for (int j = 0; j < member.signal->parameters.size(); j++) {
GDScriptParser::ParameterNode *param = member.signal->parameters[j];
- GDScriptParser::DataType param_type = resolve_datatype(param->datatype_specifier);
- param_type.is_meta_type = false;
+ GDScriptParser::DataType param_type = type_from_metatype(resolve_datatype(param->datatype_specifier));
param->set_datatype(param_type);
mi.arguments.push_back(PropertyInfo(param_type.builtin_type, param->identifier->name));
// TODO: add signal parameter default values
@@ -1518,14 +1511,12 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi
GDScriptParser::DataType type;
type.kind = GDScriptParser::DataType::VARIANT;
- bool is_variable = p_assignable->type == GDScriptParser::Node::VARIABLE;
bool is_constant = p_assignable->type == GDScriptParser::Node::CONSTANT;
GDScriptParser::DataType specified_type;
bool has_specified_type = p_assignable->datatype_specifier != nullptr;
if (has_specified_type) {
- specified_type = resolve_datatype(p_assignable->datatype_specifier);
- specified_type.is_meta_type = false;
+ specified_type = type_from_metatype(resolve_datatype(p_assignable->datatype_specifier));
type = specified_type;
}
@@ -1581,13 +1572,11 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi
} else if (!specified_type.is_variant()) {
if (initializer_type.is_variant() || !initializer_type.is_hard_type()) {
mark_node_unsafe(p_assignable->initializer);
- if (is_variable) {
- static_cast<GDScriptParser::VariableNode *>(p_assignable)->use_conversion_assign = true;
- }
+ p_assignable->use_conversion_assign = true;
} else if (!is_type_compatible(specified_type, initializer_type, true, p_assignable->initializer)) {
- if (is_variable && is_type_compatible(initializer_type, specified_type, true, p_assignable->initializer)) {
+ if (!is_constant && is_type_compatible(initializer_type, specified_type, true, p_assignable->initializer)) {
mark_node_unsafe(p_assignable->initializer);
- static_cast<GDScriptParser::VariableNode *>(p_assignable)->use_conversion_assign = true;
+ p_assignable->use_conversion_assign = true;
} else {
push_error(vformat(R"(Cannot assign a value of type %s to %s "%s" with specified type %s.)", initializer_type.to_string(), p_kind, p_assignable->identifier->name, specified_type.to_string()), p_assignable->initializer);
}
@@ -2464,7 +2453,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
bool types_match = true;
for (int i = 0; i < p_call->arguments.size(); i++) {
- GDScriptParser::DataType par_type = type_from_property(info.arguments[i]);
+ GDScriptParser::DataType par_type = type_from_property(info.arguments[i], true);
if (!is_type_compatible(par_type, p_call->arguments[i]->get_datatype(), true)) {
types_match = false;
@@ -2521,7 +2510,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
PropertyInfo wrong_arg = function_info.arguments[err.argument];
push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be "%s" but is "%s".)*", function_name, err.argument + 1,
- type_from_property(wrong_arg).to_string(), p_call->arguments[err.argument]->get_datatype().to_string()),
+ type_from_property(wrong_arg, true).to_string(), p_call->arguments[err.argument]->get_datatype().to_string()),
p_call->arguments[err.argument]);
} break;
case Callable::CallError::CALL_ERROR_INVALID_METHOD:
@@ -2568,7 +2557,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
String expected_type_name;
if (err.argument < function_info.arguments.size()) {
- expected_type_name = type_from_property(function_info.arguments[err.argument]).to_string();
+ expected_type_name = type_from_property(function_info.arguments[err.argument], true).to_string();
} else {
expected_type_name = Variant::get_type_name((Variant::Type)err.expected);
}
@@ -2766,14 +2755,13 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) {
reduce_expression(p_cast->operand);
- GDScriptParser::DataType cast_type = resolve_datatype(p_cast->cast_type);
+ GDScriptParser::DataType cast_type = type_from_metatype(resolve_datatype(p_cast->cast_type));
if (!cast_type.is_set()) {
mark_node_unsafe(p_cast);
return;
}
- cast_type = type_from_metatype(cast_type); // The casted value won't be a type name.
p_cast->set_datatype(cast_type);
if (!cast_type.is_variant()) {
@@ -2907,15 +2895,7 @@ GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const Str
return ref->get_parser()->head->get_datatype();
} else {
- type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
- type.kind = GDScriptParser::DataType::SCRIPT;
- type.builtin_type = Variant::OBJECT;
- type.script_type = ResourceLoader::load(path, "Script");
- type.native_type = type.script_type->get_instance_base_type();
- type.script_path = path;
- type.is_constant = true;
- type.is_meta_type = true;
- return type;
+ return make_script_meta_type(ResourceLoader::load(path, "Script"));
}
}
@@ -3938,10 +3918,10 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_metatype(const GDScriptPars
return result;
}
-GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo &p_property) const {
+GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo &p_property, bool p_is_arg) const {
GDScriptParser::DataType result;
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
- if (p_property.type == Variant::NIL && (p_property.usage & PROPERTY_USAGE_NIL_IS_VARIANT)) {
+ if (p_property.type == Variant::NIL && (p_is_arg || (p_property.usage & PROPERTY_USAGE_NIL_IS_VARIANT))) {
// Variant
result.kind = GDScriptParser::DataType::VARIANT;
return result;
@@ -4030,6 +4010,25 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
return false;
}
+ StringName base_native = p_base_type.native_type;
+ if (base_native != StringName()) {
+ // Empty native class might happen in some Script implementations.
+ // Just ignore it.
+ if (!class_exists(base_native)) {
+ push_error(vformat("Native class %s used in script doesn't exist or isn't exposed.", base_native), p_source);
+ return false;
+ } else if (p_is_constructor && !ClassDB::can_instantiate(base_native)) {
+ if (p_base_type.kind == GDScriptParser::DataType::CLASS) {
+ push_error(vformat(R"(Class "%s" cannot be constructed as it is based on abstract native class "%s".)", p_base_type.class_type->fqcn.get_file(), base_native), p_source);
+ } else if (p_base_type.kind == GDScriptParser::DataType::SCRIPT) {
+ push_error(vformat(R"(Script "%s" cannot be constructed as it is based on abstract native class "%s".)", p_base_type.script_path.get_file(), base_native), p_source);
+ } else {
+ push_error(vformat(R"(Native class "%s" cannot be constructed as it is abstract.)", base_native), p_source);
+ }
+ return false;
+ }
+ }
+
if (p_is_constructor) {
function_name = "_init";
r_static = true;
@@ -4090,17 +4089,6 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
}
}
- StringName base_native = p_base_type.native_type;
-#ifdef DEBUG_ENABLED
- if (base_native != StringName()) {
- // Empty native class might happen in some Script implementations.
- // Just ignore it.
- if (!class_exists(base_native)) {
- ERR_FAIL_V_MSG(false, vformat("Native class %s used in script doesn't exist or isn't exposed.", base_native));
- }
- }
-#endif
-
if (p_is_constructor) {
// Native types always have a default constructor.
r_return_type = p_base_type;
@@ -4128,7 +4116,7 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD
r_static = (p_info.flags & METHOD_FLAG_STATIC) != 0;
for (const PropertyInfo &E : p_info.arguments) {
- r_par_types.push_back(type_from_property(E));
+ r_par_types.push_back(type_from_property(E, true));
}
return true;
}
@@ -4137,7 +4125,7 @@ bool GDScriptAnalyzer::validate_call_arg(const MethodInfo &p_method, const GDScr
List<GDScriptParser::DataType> arg_types;
for (const PropertyInfo &E : p_method.arguments) {
- arg_types.push_back(type_from_property(E));
+ arg_types.push_back(type_from_property(E, true));
}
return validate_call_arg(arg_types, p_method.default_arguments.size(), (p_method.flags & METHOD_FLAG_VARARG) != 0, p_call);
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index ecae0b4629..da7b7ddb75 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -108,7 +108,7 @@ class GDScriptAnalyzer {
// Helpers.
GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);
static GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type);
- GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const;
+ GDScriptParser::DataType type_from_property(const PropertyInfo &p_property, bool p_is_arg = false) const;
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
bool get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 57ee41e34e..6c80fb7665 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -872,8 +872,12 @@ void GDScriptByteCodeGenerator::write_assign_false(const Address &p_target) {
append(p_target);
}
-void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_dst, const Address &p_src) {
- write_assign(p_dst, p_src);
+void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_dst, const Address &p_src, bool p_use_conversion) {
+ if (p_use_conversion) {
+ write_assign_with_conversion(p_dst, p_src);
+ } else {
+ write_assign(p_dst, p_src);
+ }
function->default_arguments.push_back(opcodes.size());
}
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index ac9c4c8fb5..171c505116 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -460,7 +460,7 @@ public:
virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) override;
virtual void write_assign_true(const Address &p_target) override;
virtual void write_assign_false(const Address &p_target) override;
- virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override;
+ virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src, bool p_use_conversion) override;
virtual void write_store_global(const Address &p_dst, int p_global_index) override;
virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) override;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index c7a1bcb9e9..e885938eba 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -113,7 +113,7 @@ public:
virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) = 0;
virtual void write_assign_true(const Address &p_target) = 0;
virtual void write_assign_false(const Address &p_target) = 0;
- virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0;
+ virtual void write_assign_default_parameter(const Address &dst, const Address &src, bool p_use_conversion) = 0;
virtual void write_store_global(const Address &p_dst, int p_global_index) = 0;
virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) = 0;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index beed6e90d2..77c6690d20 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -2116,7 +2116,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
}
}
- codegen.generator->write_assign_default_parameter(dst_addr, src_addr);
+ codegen.generator->write_assign_default_parameter(dst_addr, src_addr, parameter->use_conversion_assign);
if (src_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index a6b8537074..bbea6fe857 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -1321,14 +1321,8 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
if (elements.has(item.identifier->name)) {
push_error(vformat(R"(Name "%s" was already in this enum (at line %d).)", item.identifier->name, elements[item.identifier->name]), item.identifier);
} else if (!named) {
- // TODO: Abstract this recursive member check.
- ClassNode *parent = current_class;
- while (parent != nullptr) {
- if (parent->members_indices.has(item.identifier->name)) {
- push_error(vformat(R"(Name "%s" is already used as a class %s.)", item.identifier->name, parent->get_member(item.identifier->name).get_type_name()));
- break;
- }
- parent = parent->outer;
+ if (current_class->members_indices.has(item.identifier->name)) {
+ push_error(vformat(R"(Name "%s" is already used as a class %s.)", item.identifier->name, current_class->get_member(item.identifier->name).get_type_name()));
}
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 4bb02c4ea3..0903f62061 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -360,6 +360,7 @@ public:
ExpressionNode *initializer = nullptr;
TypeNode *datatype_specifier = nullptr;
bool infer_datatype = false;
+ bool use_conversion_assign = false;
int usages = 0;
virtual ~AssignableNode() {}
@@ -1182,7 +1183,6 @@ public:
bool onready = false;
PropertyInfo export_info;
int assignments = 0;
- bool use_conversion_assign = false;
#ifdef TOOLS_ENABLED
String doc_description;
#endif // TOOLS_ENABLED
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 04612c6793..e17a804003 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -164,6 +164,7 @@ bool GDScriptTokenizer::Token::is_identifier() const {
switch (type) {
case IDENTIFIER:
case MATCH: // Used in String.match().
+ case CONST_INF: // Used in Vector{2,3,4}.INF
return true;
default:
return false;
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd
new file mode 100644
index 0000000000..38c2faa859
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd
@@ -0,0 +1,2 @@
+func test():
+ CanvasItem.new()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out
new file mode 100644
index 0000000000..9eff912b59
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Native class "CanvasItem" cannot be constructed as it is abstract.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd
new file mode 100644
index 0000000000..118e7e8a45
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd
@@ -0,0 +1,9 @@
+class A extends CanvasItem:
+ func _init():
+ print('no')
+
+class B extends A:
+ pass
+
+func test():
+ B.new()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out
new file mode 100644
index 0000000000..8b956f5974
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Class "abstract_script_instantiate.gd::B" cannot be constructed as it is based on abstract native class "CanvasItem".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_shadows_outer_enum.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_shadows_outer_enum.gd
deleted file mode 100644
index f3f3b5ffeb..0000000000
--- a/modules/gdscript/tests/scripts/analyzer/errors/enum_shadows_outer_enum.gd
+++ /dev/null
@@ -1,7 +0,0 @@
-enum { V }
-
-class InnerClass:
- enum { V }
-
-func test():
- pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_shadows_outer_enum.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_shadows_outer_enum.out
deleted file mode 100644
index c9706003e1..0000000000
--- a/modules/gdscript/tests/scripts/analyzer/errors/enum_shadows_outer_enum.out
+++ /dev/null
@@ -1,2 +0,0 @@
-GDTEST_PARSER_ERROR
-Name "V" is already used as a class enum value.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.gd b/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.gd
new file mode 100644
index 0000000000..95c3268130
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.gd
@@ -0,0 +1,12 @@
+class A extends CanvasItem:
+ func _init():
+ pass
+
+class B extends A:
+ pass
+
+class C extends CanvasItem:
+ pass
+
+func test():
+ print('ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.out b/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.out
new file mode 100644
index 0000000000..1b47ed10dc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+ok
diff --git a/modules/gdscript/tests/scripts/analyzer/features/variant_arg_in_virtual_method.gd b/modules/gdscript/tests/scripts/analyzer/features/variant_arg_in_virtual_method.gd
new file mode 100644
index 0000000000..da24c06b2e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/variant_arg_in_virtual_method.gd
@@ -0,0 +1,6 @@
+class Check extends Node:
+ func _set(_property: StringName, _value: Variant) -> bool:
+ return true
+
+func test() -> void:
+ print('OK')
diff --git a/modules/gdscript/tests/scripts/analyzer/features/variant_arg_in_virtual_method.out b/modules/gdscript/tests/scripts/analyzer/features/variant_arg_in_virtual_method.out
new file mode 100644
index 0000000000..1ccb591560
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/variant_arg_in_virtual_method.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+OK
diff --git a/modules/gdscript/tests/scripts/parser/features/unnamed_enums_outer_conflicts.gd b/modules/gdscript/tests/scripts/parser/features/unnamed_enums_outer_conflicts.gd
new file mode 100644
index 0000000000..4cbb464f59
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/unnamed_enums_outer_conflicts.gd
@@ -0,0 +1,17 @@
+class A:
+ enum { X = 1 }
+
+ class B:
+ enum { X = 2 }
+
+class C:
+ const X = 3
+
+ class D:
+ enum { X = 4 }
+
+func test():
+ print(A.X)
+ print(A.B.X)
+ print(C.X)
+ print(C.D.X)
diff --git a/modules/gdscript/tests/scripts/parser/features/unnamed_enums_outer_conflicts.out b/modules/gdscript/tests/scripts/parser/features/unnamed_enums_outer_conflicts.out
new file mode 100644
index 0000000000..7536c38490
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/unnamed_enums_outer_conflicts.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+1
+2
+3
+4
diff --git a/modules/gdscript/tests/scripts/parser/features/vector_inf.gd b/modules/gdscript/tests/scripts/parser/features/vector_inf.gd
new file mode 100644
index 0000000000..039d51d9ed
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/vector_inf.gd
@@ -0,0 +1,6 @@
+func test():
+ var vec2: = Vector2.INF
+ var vec3: = Vector3.INF
+
+ print(vec2.x == INF)
+ print(vec3.z == INF)
diff --git a/modules/gdscript/tests/scripts/parser/features/vector_inf.out b/modules/gdscript/tests/scripts/parser/features/vector_inf.out
new file mode 100644
index 0000000000..9d111a8322
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/vector_inf.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+true
+true
diff --git a/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.gd b/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.gd
new file mode 100644
index 0000000000..a72ac9b5ee
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.gd
@@ -0,0 +1,8 @@
+var weakling = 'not float'
+func weak(x: float = weakling):
+ print(x)
+ print('typeof x is', typeof(x))
+
+func test():
+ print(typeof(weak()))
+ print('not ok')
diff --git a/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.out b/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.out
new file mode 100644
index 0000000000..8543cf976e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/bad_conversion_for_default_parameter.out
@@ -0,0 +1,8 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: weak()
+>> runtime/errors/bad_conversion_for_default_parameter.gd
+>> 2
+>> Trying to assign value of type 'String' to a variable of type 'float'.
+0
+not ok
diff --git a/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.gd b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.gd
new file mode 100644
index 0000000000..9d0c6317b3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.gd
@@ -0,0 +1,19 @@
+func literal(x: float = 1):
+ print('x is ', x)
+ print('typeof x is ', typeof(x))
+
+var inferring := 2
+func inferred(x: float = inferring):
+ print('x is ', x)
+ print('typeof x is ', typeof(x))
+
+var weakling = 3
+func weak(x: float = weakling):
+ print('x is ', x)
+ print('typeof x is ', typeof(x))
+
+func test():
+ literal()
+ inferred()
+ weak()
+ print('ok')
diff --git a/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out
new file mode 100644
index 0000000000..a9ef4919cf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out
@@ -0,0 +1,8 @@
+GDTEST_OK
+x is 1
+typeof x is 3
+x is 2
+typeof x is 3
+x is 3
+typeof x is 3
+ok
diff --git a/modules/gdscript/tests/scripts/runtime/features/gdscript.gd b/modules/gdscript/tests/scripts/runtime/features/gdscript.gd
new file mode 100644
index 0000000000..f2368643de
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/gdscript.gd
@@ -0,0 +1,20 @@
+func test():
+ var gdscr: = GDScript.new()
+ gdscr.source_code = '''
+extends Resource
+
+func test() -> void:
+ prints("Outer")
+ var inner = InnerClass.new()
+
+class InnerClass:
+ func _init() -> void:
+ prints("Inner")
+'''
+ @warning_ignore(return_value_discarded)
+ gdscr.reload()
+
+ var inst = gdscr.new()
+
+ @warning_ignore(unsafe_method_access)
+ inst.test()
diff --git a/modules/gdscript/tests/scripts/runtime/features/gdscript.out b/modules/gdscript/tests/scripts/runtime/features/gdscript.out
new file mode 100644
index 0000000000..16114f57f7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/gdscript.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+Outer
+Inner