mirror of
https://github.com/godotengine/godot.git
synced 2025-10-20 00:13:30 +00:00
Merge pull request #79880 from dalexeev/gds-fix-id-shadowing-below
GDScript: Fix bug with identifier shadowed below in current scope
This commit is contained in:
commit
3de7dd902c
19 changed files with 367 additions and 213 deletions
|
@ -225,194 +225,211 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
|||
|
||||
StringName identifier = in->name;
|
||||
|
||||
// Try function parameters.
|
||||
if (codegen.parameters.has(identifier)) {
|
||||
return codegen.parameters[identifier];
|
||||
}
|
||||
|
||||
// Try local variables and constants.
|
||||
if (!p_initializer && codegen.locals.has(identifier)) {
|
||||
return codegen.locals[identifier];
|
||||
}
|
||||
|
||||
// Try class members.
|
||||
if (_is_class_member_property(codegen, identifier)) {
|
||||
// Get property.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(_gdtype_from_datatype(p_expression->get_datatype(), codegen.script));
|
||||
gen->write_get_member(temp, identifier);
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Try members.
|
||||
if (!codegen.function_node || !codegen.function_node->is_static) {
|
||||
// Try member variables.
|
||||
if (codegen.script->member_indices.has(identifier)) {
|
||||
if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) {
|
||||
// Perform getter.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(codegen.script->member_indices[identifier].data_type);
|
||||
Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
|
||||
gen->write_call_self(temp, codegen.script->member_indices[identifier].getter, args);
|
||||
return temp;
|
||||
} else {
|
||||
// No getter or inside getter: direct member access.
|
||||
int idx = codegen.script->member_indices[identifier].index;
|
||||
return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, idx, codegen.script->get_member_type(identifier));
|
||||
switch (in->source) {
|
||||
// LOCALS.
|
||||
case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER:
|
||||
case GDScriptParser::IdentifierNode::LOCAL_VARIABLE:
|
||||
case GDScriptParser::IdentifierNode::LOCAL_CONSTANT:
|
||||
case GDScriptParser::IdentifierNode::LOCAL_ITERATOR:
|
||||
case GDScriptParser::IdentifierNode::LOCAL_BIND: {
|
||||
// Try function parameters.
|
||||
if (codegen.parameters.has(identifier)) {
|
||||
return codegen.parameters[identifier];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try static variables.
|
||||
{
|
||||
GDScript *scr = codegen.script;
|
||||
while (scr) {
|
||||
if (scr->static_variables_indices.has(identifier)) {
|
||||
if (scr->static_variables_indices[identifier].getter != StringName() && scr->static_variables_indices[identifier].getter != codegen.function_name) {
|
||||
// Perform getter.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
|
||||
GDScriptCodeGenerator::Address class_addr(GDScriptCodeGenerator::Address::CLASS);
|
||||
Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
|
||||
gen->write_call(temp, class_addr, scr->static_variables_indices[identifier].getter, args);
|
||||
return temp;
|
||||
} else {
|
||||
// No getter or inside getter: direct variable access.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
|
||||
GDScriptCodeGenerator::Address _class = codegen.add_constant(scr);
|
||||
int index = scr->static_variables_indices[identifier].index;
|
||||
gen->write_get_static_variable(temp, _class, index);
|
||||
return temp;
|
||||
// Try local variables and constants.
|
||||
if (!p_initializer && codegen.locals.has(identifier)) {
|
||||
return codegen.locals[identifier];
|
||||
}
|
||||
} break;
|
||||
|
||||
// MEMBERS.
|
||||
case GDScriptParser::IdentifierNode::MEMBER_VARIABLE:
|
||||
case GDScriptParser::IdentifierNode::INHERITED_VARIABLE: {
|
||||
// Try class members.
|
||||
if (_is_class_member_property(codegen, identifier)) {
|
||||
// Get property.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(_gdtype_from_datatype(p_expression->get_datatype(), codegen.script));
|
||||
gen->write_get_member(temp, identifier);
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Try members.
|
||||
if (!codegen.function_node || !codegen.function_node->is_static) {
|
||||
// Try member variables.
|
||||
if (codegen.script->member_indices.has(identifier)) {
|
||||
if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) {
|
||||
// Perform getter.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(codegen.script->member_indices[identifier].data_type);
|
||||
Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
|
||||
gen->write_call_self(temp, codegen.script->member_indices[identifier].getter, args);
|
||||
return temp;
|
||||
} else {
|
||||
// No getter or inside getter: direct member access.
|
||||
int idx = codegen.script->member_indices[identifier].index;
|
||||
return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, idx, codegen.script->get_member_type(identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
scr = scr->_base;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case GDScriptParser::IdentifierNode::MEMBER_FUNCTION:
|
||||
case GDScriptParser::IdentifierNode::MEMBER_SIGNAL: {
|
||||
// Try methods and signals (can be Callable and Signal).
|
||||
|
||||
// Try class constants.
|
||||
{
|
||||
GDScript *owner = codegen.script;
|
||||
while (owner) {
|
||||
GDScript *scr = owner;
|
||||
// Search upwards through parent classes:
|
||||
const GDScriptParser::ClassNode *base_class = codegen.class_node;
|
||||
while (base_class != nullptr) {
|
||||
if (base_class->has_member(identifier)) {
|
||||
const GDScriptParser::ClassNode::Member &member = base_class->get_member(identifier);
|
||||
if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
|
||||
// Get like it was a property.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
|
||||
GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
|
||||
|
||||
gen->write_get_named(temp, identifier, self);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
base_class = base_class->base_type.class_type;
|
||||
}
|
||||
|
||||
// Try in native base.
|
||||
GDScript *scr = codegen.script;
|
||||
GDScriptNativeClass *nc = nullptr;
|
||||
while (scr) {
|
||||
if (scr->constants.has(identifier)) {
|
||||
return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
|
||||
}
|
||||
if (scr->native.is_valid()) {
|
||||
nc = scr->native.ptr();
|
||||
}
|
||||
scr = scr->_base;
|
||||
}
|
||||
|
||||
// Class C++ integer constant.
|
||||
if (nc) {
|
||||
bool success = false;
|
||||
int64_t constant = ClassDB::get_integer_constant(nc->get_name(), identifier, &success);
|
||||
if (success) {
|
||||
return codegen.add_constant(constant);
|
||||
if (nc && (ClassDB::has_signal(nc->get_name(), identifier) || ClassDB::has_method(nc->get_name(), identifier))) {
|
||||
// Get like it was a property.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
|
||||
GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
|
||||
|
||||
gen->write_get_named(temp, identifier, self);
|
||||
return temp;
|
||||
}
|
||||
} break;
|
||||
case GDScriptParser::IdentifierNode::MEMBER_CONSTANT:
|
||||
case GDScriptParser::IdentifierNode::MEMBER_CLASS: {
|
||||
// Try class constants.
|
||||
GDScript *owner = codegen.script;
|
||||
while (owner) {
|
||||
GDScript *scr = owner;
|
||||
GDScriptNativeClass *nc = nullptr;
|
||||
while (scr) {
|
||||
if (scr->constants.has(identifier)) {
|
||||
return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
|
||||
}
|
||||
if (scr->native.is_valid()) {
|
||||
nc = scr->native.ptr();
|
||||
}
|
||||
scr = scr->_base;
|
||||
}
|
||||
|
||||
// Class C++ integer constant.
|
||||
if (nc) {
|
||||
bool success = false;
|
||||
int64_t constant = ClassDB::get_integer_constant(nc->get_name(), identifier, &success);
|
||||
if (success) {
|
||||
return codegen.add_constant(constant);
|
||||
}
|
||||
}
|
||||
|
||||
owner = owner->_owner;
|
||||
}
|
||||
} break;
|
||||
case GDScriptParser::IdentifierNode::STATIC_VARIABLE: {
|
||||
// Try static variables.
|
||||
GDScript *scr = codegen.script;
|
||||
while (scr) {
|
||||
if (scr->static_variables_indices.has(identifier)) {
|
||||
if (scr->static_variables_indices[identifier].getter != StringName() && scr->static_variables_indices[identifier].getter != codegen.function_name) {
|
||||
// Perform getter.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
|
||||
GDScriptCodeGenerator::Address class_addr(GDScriptCodeGenerator::Address::CLASS);
|
||||
Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
|
||||
gen->write_call(temp, class_addr, scr->static_variables_indices[identifier].getter, args);
|
||||
return temp;
|
||||
} else {
|
||||
// No getter or inside getter: direct variable access.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
|
||||
GDScriptCodeGenerator::Address _class = codegen.add_constant(scr);
|
||||
int index = scr->static_variables_indices[identifier].index;
|
||||
gen->write_get_static_variable(temp, _class, index);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
scr = scr->_base;
|
||||
}
|
||||
} break;
|
||||
|
||||
// GLOBALS.
|
||||
case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE: {
|
||||
// Try globals.
|
||||
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
|
||||
// If it's an autoload singleton, we postpone to load it at runtime.
|
||||
// This is so one autoload doesn't try to load another before it's compiled.
|
||||
HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
|
||||
if (autoloads.has(identifier) && autoloads[identifier].is_singleton) {
|
||||
GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype(), codegen.script));
|
||||
int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
|
||||
gen->write_store_global(global, idx);
|
||||
return global;
|
||||
} else {
|
||||
int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
|
||||
Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
|
||||
return codegen.add_constant(global);
|
||||
}
|
||||
}
|
||||
|
||||
owner = owner->_owner;
|
||||
}
|
||||
}
|
||||
|
||||
// Try signals and methods (can be made callables).
|
||||
{
|
||||
// Search upwards through parent classes:
|
||||
const GDScriptParser::ClassNode *base_class = codegen.class_node;
|
||||
while (base_class != nullptr) {
|
||||
if (base_class->has_member(identifier)) {
|
||||
const GDScriptParser::ClassNode::Member &member = base_class->get_member(identifier);
|
||||
if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
|
||||
// Get like it was a property.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
|
||||
GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
|
||||
|
||||
gen->write_get_named(temp, identifier, self);
|
||||
return temp;
|
||||
// Try global classes.
|
||||
if (ScriptServer::is_global_class(identifier)) {
|
||||
const GDScriptParser::ClassNode *class_node = codegen.class_node;
|
||||
while (class_node->outer) {
|
||||
class_node = class_node->outer;
|
||||
}
|
||||
}
|
||||
base_class = base_class->base_type.class_type;
|
||||
}
|
||||
|
||||
// Try in native base.
|
||||
GDScript *scr = codegen.script;
|
||||
GDScriptNativeClass *nc = nullptr;
|
||||
while (scr) {
|
||||
if (scr->native.is_valid()) {
|
||||
nc = scr->native.ptr();
|
||||
}
|
||||
scr = scr->_base;
|
||||
}
|
||||
Ref<Resource> res;
|
||||
|
||||
if (nc && (ClassDB::has_signal(nc->get_name(), identifier) || ClassDB::has_method(nc->get_name(), identifier))) {
|
||||
// Get like it was a property.
|
||||
GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
|
||||
GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
|
||||
|
||||
gen->write_get_named(temp, identifier, self);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
// Try globals.
|
||||
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
|
||||
// If it's an autoload singleton, we postpone to load it at runtime.
|
||||
// This is so one autoload doesn't try to load another before it's compiled.
|
||||
HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
|
||||
if (autoloads.has(identifier) && autoloads[identifier].is_singleton) {
|
||||
GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype(), codegen.script));
|
||||
int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
|
||||
gen->write_store_global(global, idx);
|
||||
return global;
|
||||
} else {
|
||||
int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
|
||||
Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
|
||||
return codegen.add_constant(global);
|
||||
}
|
||||
}
|
||||
|
||||
// Try global classes.
|
||||
if (ScriptServer::is_global_class(identifier)) {
|
||||
const GDScriptParser::ClassNode *class_node = codegen.class_node;
|
||||
while (class_node->outer) {
|
||||
class_node = class_node->outer;
|
||||
}
|
||||
|
||||
Ref<Resource> res;
|
||||
|
||||
if (class_node->identifier && class_node->identifier->name == identifier) {
|
||||
res = Ref<GDScript>(main_script);
|
||||
} else {
|
||||
String global_class_path = ScriptServer::get_global_class_path(identifier);
|
||||
if (ResourceLoader::get_resource_type(global_class_path) == "GDScript") {
|
||||
Error err = OK;
|
||||
res = GDScriptCache::get_full_script(global_class_path, err);
|
||||
if (err != OK) {
|
||||
_set_error("Can't load global class " + String(identifier), p_expression);
|
||||
r_error = ERR_COMPILATION_FAILED;
|
||||
return GDScriptCodeGenerator::Address();
|
||||
if (class_node->identifier && class_node->identifier->name == identifier) {
|
||||
res = Ref<GDScript>(main_script);
|
||||
} else {
|
||||
String global_class_path = ScriptServer::get_global_class_path(identifier);
|
||||
if (ResourceLoader::get_resource_type(global_class_path) == "GDScript") {
|
||||
Error err = OK;
|
||||
res = GDScriptCache::get_full_script(global_class_path, err);
|
||||
if (err != OK) {
|
||||
_set_error("Can't load global class " + String(identifier), p_expression);
|
||||
r_error = ERR_COMPILATION_FAILED;
|
||||
return GDScriptCodeGenerator::Address();
|
||||
}
|
||||
} else {
|
||||
res = ResourceLoader::load(global_class_path);
|
||||
if (res.is_null()) {
|
||||
_set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression);
|
||||
r_error = ERR_COMPILATION_FAILED;
|
||||
return GDScriptCodeGenerator::Address();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = ResourceLoader::load(global_class_path);
|
||||
if (res.is_null()) {
|
||||
_set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression);
|
||||
r_error = ERR_COMPILATION_FAILED;
|
||||
return GDScriptCodeGenerator::Address();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return codegen.add_constant(res);
|
||||
}
|
||||
return codegen.add_constant(res);
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
|
||||
GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
|
||||
gen->write_store_named_global(global, identifier);
|
||||
return global;
|
||||
}
|
||||
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
|
||||
GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
|
||||
gen->write_store_named_global(global, identifier);
|
||||
return global;
|
||||
}
|
||||
#endif
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
// Not found, error.
|
||||
_set_error("Identifier not found: " + String(identifier), p_expression);
|
||||
r_error = ERR_COMPILATION_FAILED;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue