diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp index c3979dd29048..00179109a33c 100644 --- a/modules/gdscript/editor/gdscript_docgen.cpp +++ b/modules/gdscript/editor/gdscript_docgen.cpp @@ -64,8 +64,8 @@ void GDScriptDocGen::_doctype_from_gdtype(const GDType &p_gdtype, String &r_type r_type = p_is_return ? "void" : "null"; return; } - if (p_gdtype.builtin_type == Variant::ARRAY && p_gdtype.has_container_element_type()) { - _doctype_from_gdtype(p_gdtype.get_container_element_type(), r_type, r_enum); + if (p_gdtype.builtin_type == Variant::ARRAY && p_gdtype.has_container_element_type(0)) { + _doctype_from_gdtype(p_gdtype.get_container_element_type(0), r_type, r_enum); if (!r_enum.is_empty()) { r_type = "int[]"; r_enum += "[]"; diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 8dbd262b22bf..3df07f979449 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -494,7 +494,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_function_arg_dicts = 0; } - if (expect_type && (prev_is_char || str[j] == '=') && str[j] != '[' && str[j] != '.') { + if (expect_type && (prev_is_char || str[j] == '=') && str[j] != '[' && str[j] != ',' && str[j] != '.') { expect_type = false; } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 983a19470ad0..55bd0f97d5bd 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -685,10 +685,10 @@ 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 = type_from_metatype(resolve_datatype(p_type->container_type)); + GDScriptParser::DataType container_type = type_from_metatype(resolve_datatype(p_type->get_container_type_or_null(0))); if (container_type.kind != GDScriptParser::DataType::VARIANT) { container_type.is_constant = false; - result.set_container_element_type(container_type); + result.set_container_element_type(0, container_type); } } } else if (class_exists(first)) { @@ -829,8 +829,16 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type } } - if (result.builtin_type != Variant::ARRAY && p_type->container_type != nullptr) { - push_error("Only arrays can specify the collection element type.", p_type); + if (!p_type->container_types.is_empty()) { + if (result.builtin_type == Variant::ARRAY) { + if (p_type->container_types.size() != 1) { + push_error("Arrays require exactly one collection element type.", p_type); + return bad_type; + } + } else { + push_error("Only arrays can specify collection element types.", p_type); + return bad_type; + } } p_type->set_datatype(result); @@ -1891,8 +1899,8 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi if (p_assignable->initializer->type == GDScriptParser::Node::ARRAY) { GDScriptParser::ArrayNode *array = static_cast(p_assignable->initializer); - if (has_specified_type && specified_type.has_container_element_type()) { - update_array_literal_element_type(array, specified_type.get_container_element_type()); + if (has_specified_type && specified_type.has_container_element_type(0)) { + update_array_literal_element_type(array, specified_type.get_container_element_type(0)); } } @@ -1955,7 +1963,7 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi } 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); } - } else if (specified_type.has_container_element_type() && !initializer_type.has_container_element_type()) { + } else if (specified_type.has_container_element_type(0) && !initializer_type.has_container_element_type(0)) { mark_node_unsafe(p_assignable->initializer); #ifdef DEBUG_ENABLED } else if (specified_type.builtin_type == Variant::INT && initializer_type.builtin_type == Variant::FLOAT) { @@ -2127,8 +2135,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { if (list_type.is_variant()) { variable_type.kind = GDScriptParser::DataType::VARIANT; mark_node_unsafe(p_for->list); - } else if (list_type.has_container_element_type()) { - variable_type = list_type.get_container_element_type(); + } else if (list_type.has_container_element_type(0)) { + variable_type = list_type.get_container_element_type(0); variable_type.type_source = list_type.type_source; } else if (list_type.is_typed_container_type()) { variable_type = list_type.get_typed_container_type(); @@ -2377,8 +2385,8 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) { result.builtin_type = Variant::NIL; result.is_constant = true; } else { - if (p_return->return_value->type == GDScriptParser::Node::ARRAY && has_expected_type && expected_type.has_container_element_type()) { - update_array_literal_element_type(static_cast(p_return->return_value), expected_type.get_container_element_type()); + if (p_return->return_value->type == GDScriptParser::Node::ARRAY && has_expected_type && expected_type.has_container_element_type(0)) { + update_array_literal_element_type(static_cast(p_return->return_value), expected_type.get_container_element_type(0)); } if (has_expected_type && expected_type.is_hard_type() && p_return->return_value->is_constant) { update_const_expression_builtin_type(p_return->return_value, expected_type, "return"); @@ -2598,7 +2606,7 @@ void GDScriptAnalyzer::update_const_expression_builtin_type(GDScriptParser::Expr // 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. + expected_type.container_element_types.clear(); // 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]; @@ -2621,7 +2629,7 @@ void GDScriptAnalyzer::update_array_literal_element_type(GDScriptParser::ArrayNo } GDScriptParser::DataType array_type = p_array->get_datatype(); - array_type.set_container_element_type(expected_type); + array_type.set_container_element_type(0, expected_type); p_array->set_datatype(array_type); } @@ -2668,8 +2676,8 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig } // Check if assigned value is an array literal, so we can make it a typed array too if appropriate. - if (p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY && assignee_type.is_hard_type() && assignee_type.has_container_element_type()) { - update_array_literal_element_type(static_cast(p_assignment->assigned_value), assignee_type.get_container_element_type()); + if (p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY && assignee_type.is_hard_type() && assignee_type.has_container_element_type(0)) { + update_array_literal_element_type(static_cast(p_assignment->assigned_value), assignee_type.get_container_element_type(0)); } if (p_assignment->operation == GDScriptParser::AssignmentNode::OP_NONE && assignee_type.is_hard_type() && p_assignment->assigned_value->is_constant) { @@ -2747,7 +2755,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig // weak non-variant assignee and incompatible result downgrades_assignee = true; } - } else if (assignee_type.has_container_element_type() && !op_type.has_container_element_type()) { + } else if (assignee_type.has_container_element_type(0) && !op_type.has_container_element_type(0)) { // typed array assignee and untyped array result mark_node_unsafe(p_assignment); } @@ -3311,8 +3319,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a // If the function requires typed arrays we must make literals be typed. for (const KeyValue &E : arrays) { int index = E.key; - if (index < par_types.size() && par_types[index].is_hard_type() && par_types[index].has_container_element_type()) { - update_array_literal_element_type(E.value, par_types[index].get_container_element_type()); + if (index < par_types.size() && par_types[index].is_hard_type() && par_types[index].has_container_element_type(0)) { + update_array_literal_element_type(E.value, par_types[index].get_container_element_type(0)); } } validate_call_arg(par_types, default_arg_count, method_flags.has_flag(METHOD_FLAG_VARARG), p_call); @@ -3444,8 +3452,8 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) { } } - if (p_cast->operand->type == GDScriptParser::Node::ARRAY && cast_type.has_container_element_type()) { - update_array_literal_element_type(static_cast(p_cast->operand), cast_type.get_container_element_type()); + if (p_cast->operand->type == GDScriptParser::Node::ARRAY && cast_type.has_container_element_type(0)) { + update_array_literal_element_type(static_cast(p_cast->operand), cast_type.get_container_element_type(0)); } if (!cast_type.is_variant()) { @@ -4432,8 +4440,8 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri break; // Can have an element type. case Variant::ARRAY: - if (base_type.has_container_element_type()) { - result_type = base_type.get_container_element_type(); + if (base_type.has_container_element_type(0)) { + result_type = base_type.get_container_element_type(0); result_type.type_source = base_type.type_source; } else { result_type.kind = GDScriptParser::DataType::VARIANT; @@ -4597,7 +4605,7 @@ Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::Expressi } Variant GDScriptAnalyzer::make_array_reduced_value(GDScriptParser::ArrayNode *p_array, bool &is_reduced) { - Array array = p_array->get_datatype().has_container_element_type() ? make_array_from_element_datatype(p_array->get_datatype().get_container_element_type()) : Array(); + Array array = p_array->get_datatype().has_container_element_type(0) ? make_array_from_element_datatype(p_array->get_datatype().get_container_element_type(0)) : Array(); array.resize(p_array->elements.size()); for (int i = 0; i < p_array->elements.size(); i++) { @@ -4719,8 +4727,8 @@ Variant GDScriptAnalyzer::make_variable_default_value(GDScriptParser::VariableNo GDScriptParser::DataType datatype = p_variable->get_datatype(); if (datatype.is_hard_type()) { if (datatype.kind == GDScriptParser::DataType::BUILTIN && datatype.builtin_type != Variant::OBJECT) { - if (datatype.builtin_type == Variant::ARRAY && datatype.has_container_element_type()) { - result = make_array_from_element_datatype(datatype.get_container_element_type()); + if (datatype.builtin_type == Variant::ARRAY && datatype.has_container_element_type(0)) { + result = make_array_from_element_datatype(datatype.get_container_element_type(0)); } else { VariantInternal::initialize(&result, datatype.builtin_type); } @@ -4747,11 +4755,11 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va if (p_value.get_type() == Variant::ARRAY) { const Array &array = p_value; if (array.get_typed_script()) { - result.set_container_element_type(type_from_metatype(make_script_meta_type(array.get_typed_script()))); + result.set_container_element_type(0, type_from_metatype(make_script_meta_type(array.get_typed_script()))); } else if (array.get_typed_class_name()) { - result.set_container_element_type(type_from_metatype(make_native_meta_type(array.get_typed_class_name()))); + result.set_container_element_type(0, type_from_metatype(make_native_meta_type(array.get_typed_class_name()))); } else if (array.get_typed_builtin() != Variant::NIL) { - result.set_container_element_type(type_from_metatype(make_builtin_meta_type((Variant::Type)array.get_typed_builtin()))); + result.set_container_element_type(0, type_from_metatype(make_builtin_meta_type((Variant::Type)array.get_typed_builtin()))); } } else if (p_value.get_type() == Variant::OBJECT) { // Object is treated as a native type, not a builtin type. @@ -4873,7 +4881,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed array."); } elem_type.is_constant = false; - result.set_container_element_type(elem_type); + result.set_container_element_type(0, elem_type); } else if (p_property.type == Variant::INT) { // Check if it's enum. if ((p_property.usage & PROPERTY_USAGE_CLASS_IS_ENUM) && p_property.class_name != StringName()) { @@ -5225,7 +5233,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator bool hard_operation = p_a.is_hard_type() && p_b.is_hard_type(); if (p_operation == Variant::OP_ADD && a_type == Variant::ARRAY && b_type == Variant::ARRAY) { - if (p_a.has_container_element_type() && p_b.has_container_element_type() && p_a.get_container_element_type() == p_b.get_container_element_type()) { + if (p_a.has_container_element_type(0) && p_b.has_container_element_type(0) && p_a.get_container_element_type(0) == p_b.get_container_element_type(0)) { r_valid = true; result = p_a; result.type_source = hard_operation ? GDScriptParser::DataType::ANNOTATED_INFERRED : GDScriptParser::DataType::INFERRED; @@ -5276,8 +5284,8 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ } if (valid && p_target.builtin_type == Variant::ARRAY && p_source.builtin_type == Variant::ARRAY) { // Check the element type. - if (p_target.has_container_element_type() && p_source.has_container_element_type()) { - valid = p_target.get_container_element_type() == p_source.get_container_element_type(); + if (p_target.has_container_element_type(0) && p_source.has_container_element_type(0)) { + valid = p_target.get_container_element_type(0) == p_source.get_container_element_type(0); } } return valid; diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 25e20c0e76e1..27766115d5a0 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -623,8 +623,8 @@ void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, V void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) { switch (p_type.kind) { case GDScriptDataType::BUILTIN: { - if (p_type.builtin_type == Variant::ARRAY && p_type.has_container_element_type()) { - const GDScriptDataType &element_type = p_type.get_container_element_type(); + if (p_type.builtin_type == Variant::ARRAY && p_type.has_container_element_type(0)) { + const GDScriptDataType &element_type = p_type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_ARRAY); append(p_target); append(p_source); @@ -878,8 +878,8 @@ void GDScriptByteCodeGenerator::write_get_static_variable(const Address &p_targe void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_target, const Address &p_source) { switch (p_target.type.kind) { case GDScriptDataType::BUILTIN: { - if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) { - const GDScriptDataType &element_type = p_target.type.get_container_element_type(); + if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) { + const GDScriptDataType &element_type = p_target.type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY); append(p_target); append(p_source); @@ -924,8 +924,8 @@ void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_ta } void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) { - if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) { - const GDScriptDataType &element_type = p_target.type.get_container_element_type(); + if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) { + const GDScriptDataType &element_type = p_target.type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY); append(p_target); append(p_source); @@ -1666,9 +1666,9 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) { // If this is a typed function, then we need to check for potential conversions. if (function->return_type.has_type) { - if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) { + if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) { // Typed array. - const GDScriptDataType &element_type = function->return_type.get_container_element_type(); + const GDScriptDataType &element_type = function->return_type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY); append(p_return_value); append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); @@ -1691,8 +1691,8 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) { } else { switch (function->return_type.kind) { case GDScriptDataType::BUILTIN: { - if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) { - const GDScriptDataType &element_type = function->return_type.get_container_element_type(); + if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) { + const GDScriptDataType &element_type = function->return_type.get_container_element_type(0); append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY); append(p_return_value); append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 7980f020b839..9560f670e665 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -196,8 +196,8 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D } } - if (p_datatype.has_container_element_type()) { - result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type(), p_owner, false)); + for (int i = 0; i < p_datatype.container_element_types.size(); i++) { + result.set_container_element_type(i, _gdtype_from_datatype(p_datatype.get_container_element_type_or_variant(i), p_owner, false)); } return result; @@ -507,8 +507,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code values.push_back(val); } - if (array_type.has_container_element_type()) { - gen->write_construct_typed_array(result, array_type.get_container_element_type(), values); + if (array_type.has_container_element_type(0)) { + gen->write_construct_typed_array(result, array_type.get_container_element_type(0), values); } else { gen->write_construct_array(result, values); } @@ -2133,8 +2133,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui initialized = true; } else if (local_type.has_type) { // Initialize with default for type. - if (local_type.has_container_element_type()) { - codegen.generator->write_construct_typed_array(local, local_type.get_container_element_type(), Vector()); + if (local_type.has_container_element_type(0)) { + codegen.generator->write_construct_typed_array(local, local_type.get_container_element_type(0), Vector()); initialized = true; } else if (local_type.kind == GDScriptDataType::BUILTIN) { codegen.generator->write_construct(local, local_type.builtin_type, Vector()); @@ -2276,8 +2276,8 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type); - if (field_type.has_container_element_type()) { - codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector()); + if (field_type.has_container_element_type(0)) { + codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(0), Vector()); } else if (field_type.kind == GDScriptDataType::BUILTIN) { codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector()); } @@ -2466,9 +2466,9 @@ GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDS if (field_type.has_type) { codegen.generator->write_newline(field->start_line); - if (field_type.has_container_element_type()) { + if (field_type.has_container_element_type(0)) { GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type); - codegen.generator->write_construct_typed_array(temp, field_type.get_container_element_type(), Vector()); + codegen.generator->write_construct_typed_array(temp, field_type.get_container_element_type(0), Vector()); codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index); codegen.generator->pop_temporary(); } else if (field_type.kind == GDScriptDataType::BUILTIN) { diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index c9b543fbb934..e63fa17cfe8e 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -45,10 +45,9 @@ class GDScriptInstance; class GDScript; class GDScriptDataType { -private: - GDScriptDataType *container_element_type = nullptr; - public: + Vector container_element_types; + enum Kind { UNINITIALIZED, BUILTIN, @@ -76,19 +75,20 @@ class GDScriptDataType { case BUILTIN: { Variant::Type var_type = p_variant.get_type(); bool valid = builtin_type == var_type; - if (valid && builtin_type == Variant::ARRAY && has_container_element_type()) { + if (valid && builtin_type == Variant::ARRAY && has_container_element_type(0)) { Array array = p_variant; if (array.is_typed()) { + GDScriptDataType array_container_type = get_container_element_type(0); Variant::Type array_builtin_type = (Variant::Type)array.get_typed_builtin(); StringName array_native_type = array.get_typed_class_name(); Ref