Merge pull request #49105 from vnen/gdscript-inner-preload-type
GDScript: Fix inner classes and preloaded scripts as types
This commit is contained in:
commit
f5422c55fc
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "gdscript_analyzer.h"
|
#include "gdscript_analyzer.h"
|
||||||
|
|
||||||
|
#include "core/config/engine.h"
|
||||||
#include "core/config/project_settings.h"
|
#include "core/config/project_settings.h"
|
||||||
#include "core/io/file_access.h"
|
#include "core/io/file_access.h"
|
||||||
#include "core/io/resource_loader.h"
|
#include "core/io/resource_loader.h"
|
||||||
@ -432,8 +433,28 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
|
|||||||
case GDScriptParser::ClassNode::Member::CONSTANT:
|
case GDScriptParser::ClassNode::Member::CONSTANT:
|
||||||
if (member.constant->get_datatype().is_meta_type) {
|
if (member.constant->get_datatype().is_meta_type) {
|
||||||
result = member.constant->get_datatype();
|
result = member.constant->get_datatype();
|
||||||
|
result.is_meta_type = false;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
} else if (Ref<Script>(member.constant->initializer->reduced_value).is_valid()) {
|
||||||
|
Ref<GDScript> gdscript = member.constant->initializer->reduced_value;
|
||||||
|
if (gdscript.is_valid()) {
|
||||||
|
Ref<GDScriptParserRef> ref = get_parser_for(gdscript->get_path());
|
||||||
|
if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
|
||||||
|
push_error(vformat(R"(Could not parse script from "%s".)", gdscript->get_path()), p_type);
|
||||||
|
return GDScriptParser::DataType();
|
||||||
|
}
|
||||||
|
result = ref->get_parser()->head->get_datatype();
|
||||||
|
result.is_meta_type = false;
|
||||||
|
} else {
|
||||||
|
Ref<GDScript> 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();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
default:
|
default:
|
||||||
@ -2129,6 +2150,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
|
|||||||
|
|
||||||
if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) {
|
if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) {
|
||||||
push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call->callee);
|
push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call->callee);
|
||||||
|
} else if (!is_self && base_type.is_meta_type && !is_static) {
|
||||||
|
base_type.is_meta_type = false; // For `to_string()`.
|
||||||
|
push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call->callee);
|
||||||
} else if (is_self && !is_static && !lambda_stack.is_empty()) {
|
} else if (is_self && !is_static && !lambda_stack.is_empty()) {
|
||||||
push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call->callee);
|
push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call->callee);
|
||||||
}
|
}
|
||||||
@ -2392,6 +2416,11 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
|
|||||||
resolve_function_signature(member.function);
|
resolve_function_signature(member.function);
|
||||||
p_identifier->set_datatype(make_callable_type(member.function->info));
|
p_identifier->set_datatype(make_callable_type(member.function->info));
|
||||||
break;
|
break;
|
||||||
|
case GDScriptParser::ClassNode::Member::CLASS:
|
||||||
|
// For out-of-order resolution:
|
||||||
|
resolve_class_interface(member.m_class);
|
||||||
|
p_identifier->set_datatype(member.m_class->get_datatype());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break; // Type already set.
|
break; // Type already set.
|
||||||
}
|
}
|
||||||
@ -3201,7 +3230,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GDScriptParser::DataType p_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 GDScriptAnalyzer::get_function_signature(GDScriptParser::CallNode *p_source, GDScriptParser::DataType p_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) {
|
||||||
r_static = false;
|
r_static = false;
|
||||||
r_vararg = false;
|
r_vararg = false;
|
||||||
r_default_arg_count = 0;
|
r_default_arg_count = 0;
|
||||||
@ -3220,14 +3249,16 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
|
|||||||
|
|
||||||
for (const MethodInfo &E : methods) {
|
for (const MethodInfo &E : methods) {
|
||||||
if (E.name == p_function) {
|
if (E.name == p_function) {
|
||||||
return function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
|
function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
|
||||||
|
r_static = Variant::is_builtin_method_static(p_base_type.builtin_type, function_name);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_constructor = p_base_type.is_meta_type && p_function == "new";
|
bool is_constructor = (p_base_type.is_meta_type || (p_source->callee && p_source->callee->type == GDScriptParser::Node::IDENTIFIER)) && p_function == StaticCString::create("new");
|
||||||
if (is_constructor) {
|
if (is_constructor) {
|
||||||
function_name = "_init";
|
function_name = "_init";
|
||||||
r_static = true;
|
r_static = true;
|
||||||
@ -3257,6 +3288,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
r_return_type = found_function->get_datatype();
|
r_return_type = found_function->get_datatype();
|
||||||
|
r_return_type.is_meta_type = false;
|
||||||
r_return_type.is_coroutine = found_function->is_coroutine;
|
r_return_type.is_coroutine = found_function->is_coroutine;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -3304,7 +3336,11 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
|
|||||||
|
|
||||||
MethodInfo info;
|
MethodInfo info;
|
||||||
if (ClassDB::get_method_info(base_native, function_name, &info)) {
|
if (ClassDB::get_method_info(base_native, function_name, &info)) {
|
||||||
return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
|
bool valid = function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
|
||||||
|
if (valid && Engine::get_singleton()->has_singleton(base_native)) {
|
||||||
|
r_static = true;
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -99,7 +99,7 @@ class GDScriptAnalyzer {
|
|||||||
GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const;
|
GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const;
|
||||||
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const;
|
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const;
|
||||||
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
|
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, 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 get_function_signature(GDScriptParser::CallNode *p_source, 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);
|
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);
|
||||||
bool validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call);
|
bool validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call);
|
||||||
bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
|
bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
|
||||||
|
@ -126,8 +126,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
|
|||||||
names.pop_back();
|
names.pop_back();
|
||||||
}
|
}
|
||||||
result.kind = GDScriptDataType::GDSCRIPT;
|
result.kind = GDScriptDataType::GDSCRIPT;
|
||||||
result.script_type_ref = script;
|
result.script_type = script.ptr();
|
||||||
result.script_type = result.script_type_ref.ptr();
|
|
||||||
result.native_type = script->get_instance_base_type();
|
result.native_type = script->get_instance_base_type();
|
||||||
} else {
|
} else {
|
||||||
result.kind = GDScriptDataType::GDSCRIPT;
|
result.kind = GDScriptDataType::GDSCRIPT;
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
func test():
|
||||||
|
print(Color.html_is_valid("00ffff"))
|
||||||
|
print("OK")
|
@ -0,0 +1,3 @@
|
|||||||
|
GDTEST_OK
|
||||||
|
True
|
||||||
|
OK
|
@ -0,0 +1,5 @@
|
|||||||
|
func test():
|
||||||
|
pass
|
||||||
|
|
||||||
|
func something():
|
||||||
|
return "OK"
|
@ -0,0 +1 @@
|
|||||||
|
GDTEST_OK
|
@ -0,0 +1,11 @@
|
|||||||
|
class InnerClass:
|
||||||
|
var val := "OK"
|
||||||
|
static func create_instance() -> InnerClass:
|
||||||
|
return new()
|
||||||
|
|
||||||
|
func create_inner_instance() -> InnerClass:
|
||||||
|
return InnerClass.create_instance()
|
||||||
|
|
||||||
|
func test():
|
||||||
|
var instance = create_inner_instance()
|
||||||
|
print(instance.val)
|
@ -0,0 +1,2 @@
|
|||||||
|
GDTEST_OK
|
||||||
|
OK
|
@ -0,0 +1,5 @@
|
|||||||
|
const preloaded : GDScript = preload("gdscript_to_preload.gd")
|
||||||
|
|
||||||
|
func test():
|
||||||
|
var preloaded_instance: preloaded = preloaded.new()
|
||||||
|
print(preloaded_instance.something())
|
@ -0,0 +1,2 @@
|
|||||||
|
GDTEST_OK
|
||||||
|
OK
|
Loading…
Reference in New Issue
Block a user