You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-05 12:10:55 +00:00
Fixes cyclic detection from variables assigning themselves to themselves in autocomplete, and restricts initialization of variables from other variables which have not been declared above it in class body
This commit is contained in:
@@ -646,41 +646,51 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
|
||||
}
|
||||
}
|
||||
|
||||
if (member.variable->datatype_specifier != nullptr) {
|
||||
datatype = specified_type;
|
||||
// Check if initalizer is an unset identifier (ie: a variable within scope, but declared below)
|
||||
if (member.variable->initializer && !member.variable->initializer->get_datatype().is_set()) {
|
||||
if (member.variable->initializer->type == GDScriptParser::Node::IDENTIFIER) {
|
||||
GDScriptParser::IdentifierNode *initializer_identifier = static_cast<GDScriptParser::IdentifierNode *>(member.variable->initializer);
|
||||
push_error(vformat(R"(Identifier "%s" must be declared above current variable.)", initializer_identifier->name), member.variable->initializer);
|
||||
} else {
|
||||
ERR_PRINT("Parser bug (please report): tried to assign unset node without an identifier.");
|
||||
}
|
||||
} else {
|
||||
if (member.variable->datatype_specifier != nullptr) {
|
||||
datatype = specified_type;
|
||||
|
||||
if (member.variable->initializer != nullptr) {
|
||||
if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true, member.variable->initializer)) {
|
||||
// Try reverse test since it can be a masked subtype.
|
||||
if (!is_type_compatible(member.variable->initializer->get_datatype(), datatype, true, member.variable->initializer)) {
|
||||
push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer);
|
||||
} else {
|
||||
// TODO: Add warning.
|
||||
if (member.variable->initializer != nullptr) {
|
||||
if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true, member.variable->initializer)) {
|
||||
// Try reverse test since it can be a masked subtype.
|
||||
if (!is_type_compatible(member.variable->initializer->get_datatype(), datatype, true, member.variable->initializer)) {
|
||||
push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer);
|
||||
} else {
|
||||
// TODO: Add warning.
|
||||
mark_node_unsafe(member.variable->initializer);
|
||||
member.variable->use_conversion_assign = true;
|
||||
}
|
||||
} else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION);
|
||||
#endif
|
||||
}
|
||||
if (member.variable->initializer->get_datatype().is_variant()) {
|
||||
// TODO: Warn unsafe assign.
|
||||
mark_node_unsafe(member.variable->initializer);
|
||||
member.variable->use_conversion_assign = true;
|
||||
}
|
||||
} else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION);
|
||||
#endif
|
||||
}
|
||||
if (member.variable->initializer->get_datatype().is_variant()) {
|
||||
// TODO: Warn unsafe assign.
|
||||
mark_node_unsafe(member.variable->initializer);
|
||||
member.variable->use_conversion_assign = true;
|
||||
} else if (member.variable->infer_datatype) {
|
||||
if (member.variable->initializer == nullptr) {
|
||||
push_error(vformat(R"(Cannot infer the type of "%s" variable because there's no default value.)", member.variable->identifier->name), member.variable->identifier);
|
||||
} else if (!datatype.is_set() || datatype.has_no_type()) {
|
||||
push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value doesn't have a set type.)", member.variable->identifier->name), member.variable->initializer);
|
||||
} else if (datatype.is_variant()) {
|
||||
push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is Variant. Use explicit "Variant" type if this is intended.)", member.variable->identifier->name), member.variable->initializer);
|
||||
} else if (datatype.builtin_type == Variant::NIL) {
|
||||
push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is "null".)", member.variable->identifier->name), member.variable->initializer);
|
||||
}
|
||||
datatype.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
|
||||
}
|
||||
} else if (member.variable->infer_datatype) {
|
||||
if (member.variable->initializer == nullptr) {
|
||||
push_error(vformat(R"(Cannot infer the type of "%s" variable because there's no default value.)", member.variable->identifier->name), member.variable->identifier);
|
||||
} else if (!datatype.is_set() || datatype.has_no_type()) {
|
||||
push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value doesn't have a set type.)", member.variable->identifier->name), member.variable->initializer);
|
||||
} else if (datatype.is_variant()) {
|
||||
push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is Variant. Use explicit "Variant" type if this is intended.)", member.variable->identifier->name), member.variable->initializer);
|
||||
} else if (datatype.builtin_type == Variant::NIL) {
|
||||
push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is "null".)", member.variable->identifier->name), member.variable->initializer);
|
||||
}
|
||||
datatype.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
|
||||
}
|
||||
|
||||
datatype.is_constant = false;
|
||||
|
||||
Reference in New Issue
Block a user