GDScript: Make array literal typed if for loop variable type is specified

This commit is contained in:
Danil Alexeev 2023-09-21 11:14:28 +03:00
parent 59139df16e
commit 3c35e7f1d6
No known key found for this signature in database
GPG key ID: 124453E157DA8DC7
5 changed files with 30 additions and 7 deletions

View file

@ -2143,6 +2143,9 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
} else if (!is_type_compatible(specified_type, variable_type)) {
p_for->use_conversion_assign = true;
}
if (p_for->list && p_for->list->type == GDScriptParser::Node::ARRAY) {
update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_for->list), specified_type);
}
}
p_for->variable->set_datatype(specified_type);
} else {
@ -2541,28 +2544,31 @@ void GDScriptAnalyzer::update_const_expression_builtin_type(GDScriptParser::Expr
// When an array literal is stored (or passed as function argument) to a typed context, we then assume the array is typed.
// This function determines which type is that (if any).
void GDScriptAnalyzer::update_array_literal_element_type(GDScriptParser::ArrayNode *p_array, const GDScriptParser::DataType &p_element_type) {
GDScriptParser::DataType expected_type = p_element_type;
expected_type.unset_container_element_type(); // Nested types (like `Array[Array[int]]`) are not currently supported.
for (int i = 0; i < p_array->elements.size(); i++) {
GDScriptParser::ExpressionNode *element_node = p_array->elements[i];
if (element_node->is_constant) {
update_const_expression_builtin_type(element_node, p_element_type, "include");
update_const_expression_builtin_type(element_node, expected_type, "include");
}
const GDScriptParser::DataType &element_type = element_node->get_datatype();
if (element_type.has_no_type() || element_type.is_variant() || !element_type.is_hard_type()) {
const GDScriptParser::DataType &actual_type = element_node->get_datatype();
if (actual_type.has_no_type() || actual_type.is_variant() || !actual_type.is_hard_type()) {
mark_node_unsafe(element_node);
continue;
}
if (!is_type_compatible(p_element_type, element_type, true, p_array)) {
if (is_type_compatible(element_type, p_element_type)) {
if (!is_type_compatible(expected_type, actual_type, true, p_array)) {
if (is_type_compatible(actual_type, expected_type)) {
mark_node_unsafe(element_node);
continue;
}
push_error(vformat(R"(Cannot have an element of type "%s" in an array of type "Array[%s]".)", element_type.to_string(), p_element_type.to_string()), element_node);
push_error(vformat(R"(Cannot have an element of type "%s" in an array of type "Array[%s]".)", actual_type.to_string(), expected_type.to_string()), element_node);
return;
}
}
GDScriptParser::DataType array_type = p_array->get_datatype();
array_type.set_container_element_type(p_element_type);
array_type.set_container_element_type(expected_type);
p_array->set_datatype(array_type);
}

View file

@ -0,0 +1,5 @@
# GH-82021
func test():
for x: String in [1, 2, 3]:
print(x)

View file

@ -0,0 +1,2 @@
GDTEST_ANALYZER_ERROR
Cannot include a value of type "int" as "String".

View file

@ -21,6 +21,12 @@ func test():
var elem := e
prints(var_to_str(e), var_to_str(elem))
# GH-82021
print("Test implicitly typed array literal.")
for e: float in [100, 200, 300]:
var elem := e
prints(var_to_str(e), var_to_str(elem))
print("Test String-keys dictionary.")
var d1 := {a = 1, b = 2, c = 3}
for k: StringName in d1:

View file

@ -15,6 +15,10 @@ Test typed int array.
10.0 10.0
20.0 20.0
30.0 30.0
Test implicitly typed array literal.
100.0 100.0
200.0 200.0
300.0 300.0
Test String-keys dictionary.
&"a" &"a"
&"b" &"b"