feat: updated godot version
This commit is contained in:
parent
0c508b0831
commit
42b028dbb5
4694 changed files with 236470 additions and 401376 deletions
|
|
@ -113,8 +113,6 @@ static GDScriptParser::DataType make_native_meta_type(const StringName &p_class_
|
|||
return type;
|
||||
}
|
||||
|
||||
// WARNING: Use this function **only** to create non-GDScript script metatypes. Otherwise, `check_type_compatibility()`
|
||||
// may return an incorrect result due to the assumption "A script type cannot be a subtype of a GDScript class".
|
||||
static GDScriptParser::DataType make_script_meta_type(const Ref<Script> &p_script) {
|
||||
GDScriptParser::DataType type;
|
||||
type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
|
||||
|
|
@ -1690,13 +1688,13 @@ void GDScriptAnalyzer::resolve_annotation(GDScriptParser::AnnotationNode *p_anno
|
|||
|
||||
reduce_expression(argument);
|
||||
|
||||
bool is_argument_value_reduced = false;
|
||||
Variant value = make_expression_reduced_value(argument, is_argument_value_reduced);
|
||||
if (!is_argument_value_reduced) {
|
||||
if (!argument->is_constant) {
|
||||
push_error(vformat(R"(Argument %d of annotation "%s" isn't a constant expression.)", i + 1, p_annotation->name), argument);
|
||||
return;
|
||||
}
|
||||
|
||||
Variant value = argument->reduced_value;
|
||||
|
||||
if (value.get_type() != argument_info.type) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (argument_info.type == Variant::INT && value.get_type() == Variant::FLOAT) {
|
||||
|
|
@ -1875,9 +1873,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
|
|||
if (!p_is_lambda && get_function_signature(p_function, false, base_type, function_name, parent_return_type, parameters_types, default_par_count, method_flags, &native_base)) {
|
||||
bool valid = p_function->is_static == method_flags.has_flag(METHOD_FLAG_STATIC);
|
||||
|
||||
if (p_function->return_type == nullptr) {
|
||||
p_function->set_datatype(parent_return_type);
|
||||
} else {
|
||||
if (p_function->return_type != nullptr) {
|
||||
// Check return type covariance.
|
||||
GDScriptParser::DataType return_type = p_function->get_datatype();
|
||||
if (return_type.is_variant()) {
|
||||
|
|
@ -2055,7 +2051,7 @@ void GDScriptAnalyzer::decide_suite_type(GDScriptParser::Node *p_suite, GDScript
|
|||
}
|
||||
}
|
||||
|
||||
void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite, bool p_is_root) {
|
||||
void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) {
|
||||
for (int i = 0; i < p_suite->statements.size(); i++) {
|
||||
GDScriptParser::Node *stmt = p_suite->statements[i];
|
||||
// Apply annotations.
|
||||
|
|
@ -2064,7 +2060,7 @@ void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite, bool p_
|
|||
E->apply(parser, stmt, nullptr); // TODO: Provide `p_class`.
|
||||
}
|
||||
|
||||
resolve_node(stmt, p_is_root);
|
||||
resolve_node(stmt);
|
||||
resolve_pending_lambda_bodies();
|
||||
decide_suite_type(p_suite, stmt);
|
||||
}
|
||||
|
|
@ -2260,7 +2256,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
|
|||
GDScriptParser::DataType list_type;
|
||||
|
||||
if (p_for->list) {
|
||||
reduce_expression(p_for->list);
|
||||
resolve_node(p_for->list, false);
|
||||
|
||||
bool is_range = false;
|
||||
if (p_for->list->type == GDScriptParser::Node::CALL) {
|
||||
|
|
@ -2377,7 +2373,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
|
|||
}
|
||||
|
||||
void GDScriptAnalyzer::resolve_while(GDScriptParser::WhileNode *p_while) {
|
||||
reduce_expression(p_while->condition);
|
||||
resolve_node(p_while->condition, false);
|
||||
|
||||
resolve_suite(p_while->loop);
|
||||
p_while->set_datatype(p_while->loop->get_datatype());
|
||||
}
|
||||
|
|
@ -2426,7 +2423,7 @@ void GDScriptAnalyzer::resolve_match_branch(GDScriptParser::MatchBranchNode *p_m
|
|||
}
|
||||
|
||||
if (p_match_branch->guard_body) {
|
||||
resolve_suite(p_match_branch->guard_body, false);
|
||||
resolve_suite(p_match_branch->guard_body);
|
||||
}
|
||||
|
||||
resolve_suite(p_match_branch->block);
|
||||
|
|
@ -2515,22 +2512,19 @@ void GDScriptAnalyzer::resolve_match_pattern(GDScriptParser::PatternNode *p_matc
|
|||
}
|
||||
|
||||
void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
|
||||
const bool has_expected_type = parser->current_function != nullptr;
|
||||
const GDScriptParser::DataType expected_type = has_expected_type ? parser->current_function->get_datatype() : GDScriptParser::DataType();
|
||||
|
||||
GDScriptParser::DataType result;
|
||||
|
||||
if (p_return->return_value == nullptr) {
|
||||
// Return type is `null` by default.
|
||||
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
|
||||
result.kind = GDScriptParser::DataType::BUILTIN;
|
||||
result.builtin_type = Variant::NIL;
|
||||
result.is_constant = true;
|
||||
} else {
|
||||
const bool is_void_function = has_expected_type && expected_type.is_hard_type() && expected_type.kind == GDScriptParser::DataType::BUILTIN && expected_type.builtin_type == Variant::NIL;
|
||||
const bool is_call = p_return->return_value->type == GDScriptParser::Node::CALL;
|
||||
GDScriptParser::DataType expected_type;
|
||||
bool has_expected_type = parser->current_function != nullptr;
|
||||
if (has_expected_type) {
|
||||
expected_type = parser->current_function->get_datatype();
|
||||
}
|
||||
|
||||
if (p_return->return_value != nullptr) {
|
||||
bool is_void_function = has_expected_type && expected_type.is_hard_type() && expected_type.kind == GDScriptParser::DataType::BUILTIN && expected_type.builtin_type == Variant::NIL;
|
||||
bool is_call = p_return->return_value->type == GDScriptParser::Node::CALL;
|
||||
if (is_void_function && is_call) {
|
||||
// Pretend the call is a root expression to allow those that are `void`.
|
||||
// Pretend the call is a root expression to allow those that are "void".
|
||||
reduce_call(static_cast<GDScriptParser::CallNode *>(p_return->return_value), false, true);
|
||||
} else {
|
||||
reduce_expression(p_return->return_value);
|
||||
|
|
@ -2564,30 +2558,28 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
|
|||
}
|
||||
result = p_return->return_value->get_datatype();
|
||||
}
|
||||
} else {
|
||||
// Return type is null by default.
|
||||
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
|
||||
result.kind = GDScriptParser::DataType::BUILTIN;
|
||||
result.builtin_type = Variant::NIL;
|
||||
result.is_constant = true;
|
||||
}
|
||||
|
||||
if (has_expected_type && !expected_type.is_variant() && expected_type.is_hard_type()) {
|
||||
if (has_expected_type && !expected_type.is_variant()) {
|
||||
if (result.is_variant() || !result.is_hard_type()) {
|
||||
p_return->use_conversion = true;
|
||||
mark_node_unsafe(p_return);
|
||||
if (!is_type_compatible(expected_type, result, true, p_return)) {
|
||||
downgrade_node_type_source(p_return);
|
||||
}
|
||||
} else if (!is_type_compatible(expected_type, result, true, p_return)) {
|
||||
if (is_type_compatible(result, expected_type)) {
|
||||
p_return->use_conversion = true;
|
||||
mark_node_unsafe(p_return);
|
||||
} else {
|
||||
mark_node_unsafe(p_return);
|
||||
if (!is_type_compatible(result, expected_type)) {
|
||||
push_error(vformat(R"(Cannot return value of type "%s" because the function return type is "%s".)", result.to_string(), expected_type.to_string()), p_return);
|
||||
}
|
||||
} else {
|
||||
if (!is_type_compatible(expected_type, result)) {
|
||||
p_return->use_conversion = true;
|
||||
}
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
|
||||
parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
|
||||
}
|
||||
} else if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
|
||||
parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
}
|
||||
|
|
@ -2887,7 +2879,8 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
|
|||
if (id_type.is_hard_type()) {
|
||||
switch (id_type.kind) {
|
||||
case GDScriptParser::DataType::BUILTIN:
|
||||
need_warn = !Variant::is_type_shared(id_type.builtin_type);
|
||||
// TODO: Change `Variant::is_type_shared()` to include packed arrays?
|
||||
need_warn = !Variant::is_type_shared(id_type.builtin_type) && id_type.builtin_type < Variant::PACKED_BYTE_ARRAY;
|
||||
break;
|
||||
case GDScriptParser::DataType::ENUM:
|
||||
need_warn = true;
|
||||
|
|
@ -3120,10 +3113,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
|
|||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
if (p_binary_op->left_operand->is_constant &&
|
||||
p_binary_op->right_operand->is_constant &&
|
||||
!p_binary_op->left_operand->reduced_value.is_shared() &&
|
||||
!p_binary_op->right_operand->reduced_value.is_shared()) {
|
||||
if (p_binary_op->left_operand->is_constant && p_binary_op->right_operand->is_constant) {
|
||||
p_binary_op->is_constant = true;
|
||||
if (p_binary_op->variant_op < Variant::OP_MAX) {
|
||||
bool valid = false;
|
||||
|
|
@ -3267,9 +3257,30 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
call_type.kind = GDScriptParser::DataType::BUILTIN;
|
||||
call_type.builtin_type = builtin_type;
|
||||
|
||||
// Reference types are not suited for compile-time construction.
|
||||
// Because in this case they would be the same reference in all constructed values.
|
||||
if (all_is_constant && !Variant::is_type_shared(builtin_type)) {
|
||||
bool safe_to_fold = true;
|
||||
switch (builtin_type) {
|
||||
// Those are stored by reference so not suited for compile-time construction.
|
||||
// Because in this case they would be the same reference in all constructed values.
|
||||
case Variant::OBJECT:
|
||||
case Variant::DICTIONARY:
|
||||
case Variant::ARRAY:
|
||||
case Variant::PACKED_BYTE_ARRAY:
|
||||
case Variant::PACKED_INT32_ARRAY:
|
||||
case Variant::PACKED_INT64_ARRAY:
|
||||
case Variant::PACKED_FLOAT32_ARRAY:
|
||||
case Variant::PACKED_FLOAT64_ARRAY:
|
||||
case Variant::PACKED_STRING_ARRAY:
|
||||
case Variant::PACKED_VECTOR2_ARRAY:
|
||||
case Variant::PACKED_VECTOR3_ARRAY:
|
||||
case Variant::PACKED_COLOR_ARRAY:
|
||||
case Variant::PACKED_VECTOR4_ARRAY:
|
||||
safe_to_fold = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (all_is_constant && safe_to_fold) {
|
||||
// Construct here.
|
||||
Vector<const Variant *> args;
|
||||
for (int i = 0; i < p_call->arguments.size(); i++) {
|
||||
|
|
@ -5201,9 +5212,9 @@ void GDScriptAnalyzer::reduce_type_test(GDScriptParser::TypeTestNode *p_type_tes
|
|||
p_type_test->is_constant = true;
|
||||
p_type_test->reduced_value = false;
|
||||
|
||||
if (!is_type_compatible_strict_collections(test_type, operand_type)) {
|
||||
if (!is_type_compatible(test_type, operand_type)) {
|
||||
push_error(vformat(R"(Expression is of type "%s" so it can't be of type "%s".)", operand_type.to_string(), test_type.to_string()), p_type_test->operand);
|
||||
} else if (is_type_compatible_strict_collections(test_type, type_from_variant(p_type_test->operand->reduced_value, p_type_test->operand))) {
|
||||
} else if (is_type_compatible(test_type, type_from_variant(p_type_test->operand->reduced_value, p_type_test->operand))) {
|
||||
p_type_test->reduced_value = test_type.builtin_type != Variant::OBJECT || !p_type_test->operand->reduced_value.is_null();
|
||||
}
|
||||
|
||||
|
|
@ -5253,33 +5264,25 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
|
|||
p_unary_op->set_datatype(result);
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::ExpressionNode *p_expression, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::ExpressionNode *p_expression, bool &is_reduced) {
|
||||
if (p_expression == nullptr) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
if (p_expression->is_constant) {
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return p_expression->reduced_value;
|
||||
}
|
||||
|
||||
switch (p_expression->type) {
|
||||
case GDScriptParser::Node::ARRAY:
|
||||
return make_array_reduced_value(static_cast<GDScriptParser::ArrayNode *>(p_expression), r_is_reduced);
|
||||
return make_array_reduced_value(static_cast<GDScriptParser::ArrayNode *>(p_expression), is_reduced);
|
||||
case GDScriptParser::Node::DICTIONARY:
|
||||
return make_dictionary_reduced_value(static_cast<GDScriptParser::DictionaryNode *>(p_expression), r_is_reduced);
|
||||
return make_dictionary_reduced_value(static_cast<GDScriptParser::DictionaryNode *>(p_expression), is_reduced);
|
||||
case GDScriptParser::Node::SUBSCRIPT:
|
||||
return make_subscript_reduced_value(static_cast<GDScriptParser::SubscriptNode *>(p_expression), r_is_reduced);
|
||||
return make_subscript_reduced_value(static_cast<GDScriptParser::SubscriptNode *>(p_expression), is_reduced);
|
||||
case GDScriptParser::Node::CALL:
|
||||
return make_call_reduced_value(static_cast<GDScriptParser::CallNode *>(p_expression), r_is_reduced);
|
||||
case GDScriptParser::Node::BINARY_OPERATOR:
|
||||
return make_binary_op_reduced_value(static_cast<GDScriptParser::BinaryOpNode *>(p_expression), r_is_reduced);
|
||||
case GDScriptParser::Node::TERNARY_OPERATOR:
|
||||
return make_ternary_op_reduced_value(static_cast<GDScriptParser::TernaryOpNode *>(p_expression), r_is_reduced);
|
||||
case GDScriptParser::Node::CAST:
|
||||
return make_cast_reduced_value(static_cast<GDScriptParser::CastNode *>(p_expression), r_is_reduced);
|
||||
case GDScriptParser::Node::TYPE_TEST:
|
||||
return make_type_test_reduced_value(static_cast<GDScriptParser::TypeTestNode *>(p_expression), r_is_reduced);
|
||||
return make_call_reduced_value(static_cast<GDScriptParser::CallNode *>(p_expression), is_reduced);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -5287,7 +5290,7 @@ Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::Expressi
|
|||
return Variant();
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_array_reduced_value(GDScriptParser::ArrayNode *p_array, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_array_reduced_value(GDScriptParser::ArrayNode *p_array, bool &is_reduced) {
|
||||
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());
|
||||
|
|
@ -5305,11 +5308,11 @@ Variant GDScriptAnalyzer::make_array_reduced_value(GDScriptParser::ArrayNode *p_
|
|||
|
||||
array.make_read_only();
|
||||
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return array;
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_dictionary_reduced_value(GDScriptParser::DictionaryNode *p_dictionary, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_dictionary_reduced_value(GDScriptParser::DictionaryNode *p_dictionary, bool &is_reduced) {
|
||||
Dictionary dictionary = p_dictionary->get_datatype().has_container_element_types()
|
||||
? make_dictionary_from_element_datatype(p_dictionary->get_datatype().get_container_element_type_or_variant(0), p_dictionary->get_datatype().get_container_element_type_or_variant(1))
|
||||
: Dictionary();
|
||||
|
|
@ -5334,11 +5337,11 @@ Variant GDScriptAnalyzer::make_dictionary_reduced_value(GDScriptParser::Dictiona
|
|||
|
||||
dictionary.make_read_only();
|
||||
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::SubscriptNode *p_subscript, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::SubscriptNode *p_subscript, bool &is_reduced) {
|
||||
if (p_subscript->base == nullptr || p_subscript->index == nullptr) {
|
||||
return Variant();
|
||||
}
|
||||
|
|
@ -5353,7 +5356,7 @@ Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::Subscript
|
|||
bool is_valid = false;
|
||||
Variant value = base_value.get_named(p_subscript->attribute->name, is_valid);
|
||||
if (is_valid) {
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return value;
|
||||
} else {
|
||||
return Variant();
|
||||
|
|
@ -5368,7 +5371,7 @@ Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::Subscript
|
|||
bool is_valid = false;
|
||||
Variant value = base_value.get(index_value, &is_valid);
|
||||
if (is_valid) {
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return value;
|
||||
} else {
|
||||
return Variant();
|
||||
|
|
@ -5376,7 +5379,7 @@ Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::Subscript
|
|||
}
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_call_reduced_value(GDScriptParser::CallNode *p_call, bool &r_is_reduced) {
|
||||
Variant GDScriptAnalyzer::make_call_reduced_value(GDScriptParser::CallNode *p_call, bool &is_reduced) {
|
||||
if (p_call->get_callee_type() == GDScriptParser::Node::IDENTIFIER) {
|
||||
Variant::Type type = Variant::NIL;
|
||||
if (p_call->function_name == SNAME("Array")) {
|
||||
|
|
@ -5404,6 +5407,7 @@ Variant GDScriptAnalyzer::make_call_reduced_value(GDScriptParser::CallNode *p_ca
|
|||
Callable::CallError ce;
|
||||
Variant::construct(type, result, argptrs, args.size(), ce);
|
||||
if (ce.error) {
|
||||
push_error(vformat(R"(Failed to construct "%s".)", Variant::get_type_name(type)), p_call);
|
||||
return Variant();
|
||||
}
|
||||
|
||||
|
|
@ -5415,146 +5419,13 @@ Variant GDScriptAnalyzer::make_call_reduced_value(GDScriptParser::CallNode *p_ca
|
|||
dictionary.make_read_only();
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
is_reduced = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
return Variant();
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_binary_op_reduced_value(GDScriptParser::BinaryOpNode *p_binary_op, bool &r_is_reduced) {
|
||||
if (p_binary_op->variant_op == Variant::OP_MAX) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool is_left_op_value_reduced = false;
|
||||
Variant left_op_value = make_expression_reduced_value(p_binary_op->left_operand, is_left_op_value_reduced);
|
||||
if (!is_left_op_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool is_right_op_value_reduced = false;
|
||||
Variant right_op_value = make_expression_reduced_value(p_binary_op->right_operand, is_right_op_value_reduced);
|
||||
if (!is_right_op_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
Variant result;
|
||||
bool valid = false;
|
||||
Variant::evaluate(p_binary_op->variant_op, left_op_value, right_op_value, result, valid);
|
||||
if (!valid) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
if (result.get_type() == Variant::ARRAY) {
|
||||
Array array = result;
|
||||
array.make_read_only();
|
||||
} else if (result.get_type() == Variant::DICTIONARY) {
|
||||
Dictionary dictionary = result;
|
||||
dictionary.make_read_only();
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_ternary_op_reduced_value(GDScriptParser::TernaryOpNode *p_ternary_op, bool &r_is_reduced) {
|
||||
bool is_condition_value_reduced = false;
|
||||
Variant condition_value = make_expression_reduced_value(p_ternary_op->condition, is_condition_value_reduced);
|
||||
if (!is_condition_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool is_true_expr_value_reduced = false;
|
||||
Variant true_expr_value = make_expression_reduced_value(p_ternary_op->true_expr, is_true_expr_value_reduced);
|
||||
if (!is_true_expr_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool is_false_expr_value_reduced = false;
|
||||
Variant false_expr_value = make_expression_reduced_value(p_ternary_op->false_expr, is_false_expr_value_reduced);
|
||||
if (!is_false_expr_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
return condition_value.booleanize() ? true_expr_value : false_expr_value;
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_cast_reduced_value(GDScriptParser::CastNode *p_cast, bool &r_is_reduced) {
|
||||
bool is_operand_value_reduced = false;
|
||||
Variant operand_value = make_expression_reduced_value(p_cast->operand, is_operand_value_reduced);
|
||||
if (!is_operand_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
GDScriptParser::DataType cast_type = type_from_metatype(resolve_datatype(p_cast->cast_type));
|
||||
|
||||
if (!cast_type.is_set()) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
if (cast_type.is_variant()) {
|
||||
r_is_reduced = true;
|
||||
return operand_value;
|
||||
}
|
||||
|
||||
if (cast_type.kind == GDScriptParser::DataType::BUILTIN || cast_type.kind == GDScriptParser::DataType::ENUM) {
|
||||
Variant result;
|
||||
const Variant *argptr = &operand_value;
|
||||
Callable::CallError ce;
|
||||
Variant::construct(cast_type.builtin_type, result, &argptr, 1, ce);
|
||||
if (ce.error) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
if (result.get_type() == Variant::ARRAY) {
|
||||
Array array = cast_type.has_container_element_type(0) ? make_array_from_element_datatype(cast_type.get_container_element_type(0)) : Array();
|
||||
array.assign(result);
|
||||
array.make_read_only();
|
||||
result = array;
|
||||
} else if (result.get_type() == Variant::DICTIONARY) {
|
||||
Dictionary dictionary = cast_type.has_container_element_types()
|
||||
? make_dictionary_from_element_datatype(cast_type.get_container_element_type_or_variant(0), cast_type.get_container_element_type_or_variant(1))
|
||||
: Dictionary();
|
||||
dictionary.assign(result);
|
||||
dictionary.make_read_only();
|
||||
result = dictionary;
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
return Variant();
|
||||
}
|
||||
|
||||
Variant GDScriptAnalyzer::make_type_test_reduced_value(GDScriptParser::TypeTestNode *p_type_test, bool &r_is_reduced) {
|
||||
bool is_operand_value_reduced = false;
|
||||
Variant operand_value = make_expression_reduced_value(p_type_test->operand, is_operand_value_reduced);
|
||||
if (!is_operand_value_reduced) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
GDScriptParser::DataType test_type = type_from_metatype(p_type_test->test_type->get_datatype());
|
||||
if (!test_type.is_set()) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
GDScriptParser::DataType operand_type = type_from_variant(operand_value, p_type_test->operand);
|
||||
if (!operand_type.is_set()) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
if (is_type_compatible_strict_collections(test_type, operand_type)) {
|
||||
result = test_type.builtin_type != Variant::OBJECT || !operand_value.is_null();
|
||||
}
|
||||
|
||||
r_is_reduced = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
Array GDScriptAnalyzer::make_array_from_element_datatype(const GDScriptParser::DataType &p_element_datatype, const GDScriptParser::Node *p_source_node) {
|
||||
Array array;
|
||||
|
||||
|
|
@ -5652,57 +5523,6 @@ Variant GDScriptAnalyzer::make_variable_default_value(GDScriptParser::VariableNo
|
|||
return result;
|
||||
}
|
||||
|
||||
GDScriptParser::DataType GDScriptAnalyzer::type_from_script(const Ref<Script> &p_script, const GDScriptParser::Node *p_source, bool p_is_meta_type) {
|
||||
ERR_FAIL_COND_V(!p_script.is_valid(), GDScriptParser::DataType());
|
||||
|
||||
GDScriptParser::DataType result;
|
||||
result.is_constant = true;
|
||||
result.kind = GDScriptParser::DataType::NATIVE;
|
||||
result.builtin_type = Variant::OBJECT;
|
||||
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; // Constant has explicit type.
|
||||
result.is_meta_type = p_is_meta_type;
|
||||
|
||||
Ref<GDScript> gds = p_script;
|
||||
if (gds.is_valid()) {
|
||||
// This might be an inner class, so we want to get the parser for the root.
|
||||
// But still get the inner class from that tree.
|
||||
String script_path = gds->get_script_path();
|
||||
Ref<GDScriptParserRef> ref = parser->get_depended_parser_for(script_path);
|
||||
if (ref.is_null()) {
|
||||
push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
|
||||
GDScriptParser::DataType error_type;
|
||||
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||
return error_type;
|
||||
}
|
||||
Error err = ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
|
||||
GDScriptParser::ClassNode *found = nullptr;
|
||||
if (err == OK) {
|
||||
found = ref->get_parser()->find_class(gds->fully_qualified_name);
|
||||
if (found != nullptr) {
|
||||
err = resolve_class_inheritance(found, p_source);
|
||||
}
|
||||
}
|
||||
if (err || found == nullptr) {
|
||||
push_error(vformat(R"(Could not resolve script "%s".)", script_path), p_source);
|
||||
GDScriptParser::DataType error_type;
|
||||
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||
return error_type;
|
||||
}
|
||||
|
||||
result.kind = GDScriptParser::DataType::CLASS;
|
||||
result.native_type = found->get_datatype().native_type;
|
||||
result.class_type = found;
|
||||
result.script_path = ref->get_parser()->script_path;
|
||||
} else {
|
||||
result.kind = GDScriptParser::DataType::SCRIPT;
|
||||
result.native_type = p_script->get_instance_base_type();
|
||||
result.script_path = p_script->get_path();
|
||||
}
|
||||
result.script_type = p_script;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) {
|
||||
GDScriptParser::DataType result;
|
||||
result.is_constant = true;
|
||||
|
|
@ -5713,7 +5533,7 @@ 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(0, type_from_metatype(type_from_script(array.get_typed_script(), p_source, true)));
|
||||
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(0, type_from_metatype(make_native_meta_type(array.get_typed_class_name())));
|
||||
} else if (array.get_typed_builtin() != Variant::NIL) {
|
||||
|
|
@ -5722,14 +5542,14 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
|
|||
} else if (p_value.get_type() == Variant::DICTIONARY) {
|
||||
const Dictionary &dict = p_value;
|
||||
if (dict.get_typed_key_script()) {
|
||||
result.set_container_element_type(0, type_from_metatype(type_from_script(dict.get_typed_key_script(), p_source, true)));
|
||||
result.set_container_element_type(0, type_from_metatype(make_script_meta_type(dict.get_typed_key_script())));
|
||||
} else if (dict.get_typed_key_class_name()) {
|
||||
result.set_container_element_type(0, type_from_metatype(make_native_meta_type(dict.get_typed_key_class_name())));
|
||||
} else if (dict.get_typed_key_builtin() != Variant::NIL) {
|
||||
result.set_container_element_type(0, type_from_metatype(make_builtin_meta_type((Variant::Type)dict.get_typed_key_builtin())));
|
||||
}
|
||||
if (dict.get_typed_value_script()) {
|
||||
result.set_container_element_type(1, type_from_metatype(type_from_script(dict.get_typed_value_script(), p_source, true)));
|
||||
result.set_container_element_type(1, type_from_metatype(make_script_meta_type(dict.get_typed_value_script())));
|
||||
} else if (dict.get_typed_value_class_name()) {
|
||||
result.set_container_element_type(1, type_from_metatype(make_native_meta_type(dict.get_typed_value_class_name())));
|
||||
} else if (dict.get_typed_value_builtin() != Variant::NIL) {
|
||||
|
|
@ -5746,16 +5566,50 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
|
|||
result.native_type = obj->get_class_name();
|
||||
|
||||
Ref<Script> scr = p_value; // Check if value is a script itself.
|
||||
bool is_meta_type;
|
||||
if (scr.is_valid()) {
|
||||
is_meta_type = true;
|
||||
result.is_meta_type = true;
|
||||
} else {
|
||||
is_meta_type = false;
|
||||
result.is_meta_type = false;
|
||||
scr = obj->get_script();
|
||||
}
|
||||
|
||||
if (scr.is_valid()) {
|
||||
result = type_from_script(scr, p_source, is_meta_type);
|
||||
Ref<GDScript> gds = scr;
|
||||
if (gds.is_valid()) {
|
||||
// This might be an inner class, so we want to get the parser for the root.
|
||||
// But still get the inner class from that tree.
|
||||
String script_path = gds->get_script_path();
|
||||
Ref<GDScriptParserRef> ref = parser->get_depended_parser_for(script_path);
|
||||
if (ref.is_null()) {
|
||||
push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
|
||||
GDScriptParser::DataType error_type;
|
||||
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||
return error_type;
|
||||
}
|
||||
Error err = ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
|
||||
GDScriptParser::ClassNode *found = nullptr;
|
||||
if (err == OK) {
|
||||
found = ref->get_parser()->find_class(gds->fully_qualified_name);
|
||||
if (found != nullptr) {
|
||||
err = resolve_class_inheritance(found, p_source);
|
||||
}
|
||||
}
|
||||
if (err || found == nullptr) {
|
||||
push_error(vformat(R"(Could not resolve script "%s".)", script_path), p_source);
|
||||
GDScriptParser::DataType error_type;
|
||||
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||
return error_type;
|
||||
}
|
||||
|
||||
result.kind = GDScriptParser::DataType::CLASS;
|
||||
result.native_type = found->get_datatype().native_type;
|
||||
result.class_type = found;
|
||||
result.script_path = ref->get_parser()->script_path;
|
||||
} else {
|
||||
result.kind = GDScriptParser::DataType::SCRIPT;
|
||||
result.native_type = scr->get_instance_base_type();
|
||||
result.script_path = scr->get_path();
|
||||
}
|
||||
result.script_type = scr;
|
||||
} else {
|
||||
result.kind = GDScriptParser::DataType::NATIVE;
|
||||
if (result.native_type == GDScriptNativeClass::get_class_static()) {
|
||||
|
|
@ -6296,21 +6150,6 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
|
|||
return check_type_compatibility(p_target, p_source, p_allow_implicit_conversion, p_source_node);
|
||||
}
|
||||
|
||||
// NOTE:`is_type_compatible()` considers typed arrays/dictionaries compatible with untyped ones (but the operation is unsafe).
|
||||
// However, in the case of constant expressions, this leads to incorrect results.
|
||||
bool GDScriptAnalyzer::is_type_compatible_strict_collections(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source) {
|
||||
if (p_target.builtin_type == Variant::ARRAY && p_source.builtin_type == Variant::ARRAY) {
|
||||
if (p_target.has_container_element_type(0) && !p_source.has_container_element_type(0)) {
|
||||
return false;
|
||||
}
|
||||
} else if (p_target.builtin_type == Variant::DICTIONARY && p_source.builtin_type == Variant::DICTIONARY) {
|
||||
if (p_target.has_container_element_types() && !p_source.has_container_element_types()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return is_type_compatible(p_target, p_source);
|
||||
}
|
||||
|
||||
// TODO: Add safe/unsafe return variable (for variant cases)
|
||||
bool GDScriptAnalyzer::check_type_compatibility(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion, const GDScriptParser::Node *p_source_node) {
|
||||
// These return "true" so it doesn't affect users negatively.
|
||||
|
|
@ -6538,7 +6377,7 @@ void GDScriptAnalyzer::resolve_pending_lambda_bodies() {
|
|||
GDScriptParser::LambdaNode *previous_lambda = current_lambda;
|
||||
bool previous_static_context = static_context;
|
||||
|
||||
List<GDScriptParser::LambdaNode *> lambdas = std::move(pending_body_resolution_lambdas);
|
||||
List<GDScriptParser::LambdaNode *> lambdas = pending_body_resolution_lambdas;
|
||||
pending_body_resolution_lambdas.clear();
|
||||
|
||||
for (GDScriptParser::LambdaNode *lambda : lambdas) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue