Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix various issues when function argument's default value is array/dictionary #62994

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 68 additions & 9 deletions modules/gdscript/gdscript_analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,11 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
if (p_function->parameters[i]->default_value) {
default_value_count++;

if (p_function->parameters[i]->default_value->is_constant) {
if (p_function->parameters[i]->default_value->type == GDScriptParser::Node::ARRAY || p_function->parameters[i]->default_value->type == GDScriptParser::Node::DICTIONARY) {
if (p_function->parameters[i]->default_value->reduced_value.get_type() != Variant::NIL) {
p_function->default_arg_values.push_back(p_function->parameters[i]->default_value->reduced_value);
}
} else if (p_function->parameters[i]->default_value->is_constant) {
p_function->default_arg_values.push_back(p_function->parameters[i]->default_value->reduced_value);
}
}
Expand Down Expand Up @@ -1725,6 +1729,13 @@ void GDScriptAnalyzer::resolve_parameter(GDScriptParser::ParameterNode *p_parame
} else {
result.type_source = GDScriptParser::DataType::INFERRED;
}
result.is_constant = false;

if (p_parameter->default_value->type == GDScriptParser::Node::ARRAY) {
parameter_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_parameter->default_value));
} else if (p_parameter->default_value->type == GDScriptParser::Node::DICTIONARY) {
parameter_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_parameter->default_value));
}
}

if (p_parameter->datatype_specifier != nullptr) {
Expand Down Expand Up @@ -3653,8 +3664,6 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
}

void GDScriptAnalyzer::const_fold_array(GDScriptParser::ArrayNode *p_array) {
bool all_is_constant = true;

for (int i = 0; i < p_array->elements.size(); i++) {
GDScriptParser::ExpressionNode *element = p_array->elements[i];

Expand All @@ -3664,8 +3673,7 @@ void GDScriptAnalyzer::const_fold_array(GDScriptParser::ArrayNode *p_array) {
const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element));
}

all_is_constant = all_is_constant && element->is_constant;
if (!all_is_constant) {
if (!element->is_constant) {
return;
}
}
Expand All @@ -3680,8 +3688,6 @@ void GDScriptAnalyzer::const_fold_array(GDScriptParser::ArrayNode *p_array) {
}

void GDScriptAnalyzer::const_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary) {
bool all_is_constant = true;

for (int i = 0; i < p_dictionary->elements.size(); i++) {
const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];

Expand All @@ -3691,8 +3697,7 @@ void GDScriptAnalyzer::const_fold_dictionary(GDScriptParser::DictionaryNode *p_d
const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element.value));
}

all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant;
if (!all_is_constant) {
if (!element.key->is_constant || !element.value->is_constant) {
return;
}
}
Expand All @@ -3706,6 +3711,60 @@ void GDScriptAnalyzer::const_fold_dictionary(GDScriptParser::DictionaryNode *p_d
p_dictionary->reduced_value = dict;
}

void GDScriptAnalyzer::parameter_fold_array(GDScriptParser::ArrayNode *p_array) {
for (int i = 0; i < p_array->elements.size(); i++) {
GDScriptParser::ExpressionNode *element = p_array->elements[i];

if (element->type == GDScriptParser::Node::ARRAY) {
parameter_fold_array(static_cast<GDScriptParser::ArrayNode *>(element));
if (element->reduced_value.get_type() == Variant::NIL) {
return;
}
} else if (element->type == GDScriptParser::Node::DICTIONARY) {
parameter_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element));
if (element->reduced_value.get_type() == Variant::NIL) {
return;
}
} else if (!element->is_constant) {
return;
}
}

Array array;
array.resize(p_array->elements.size());
for (int i = 0; i < p_array->elements.size(); i++) {
array[i] = p_array->elements[i]->reduced_value;
}
p_array->reduced_value = array;
}

void GDScriptAnalyzer::parameter_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary) {
for (int i = 0; i < p_dictionary->elements.size(); i++) {
const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];

if (element.value->type == GDScriptParser::Node::ARRAY) {
parameter_fold_array(static_cast<GDScriptParser::ArrayNode *>(element.value));
if (element.value->reduced_value.get_type() == Variant::NIL) {
return;
}
} else if (element.value->type == GDScriptParser::Node::DICTIONARY) {
parameter_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element.value));
if (element.value->reduced_value.get_type() == Variant::NIL) {
return;
}
} else if (!element.key->is_constant || !element.value->is_constant) {
return;
}
}

Dictionary dict;
for (int i = 0; i < p_dictionary->elements.size(); i++) {
const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
dict[element.key->reduced_value] = element.value->reduced_value;
}
p_dictionary->reduced_value = dict;
}

GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType result;
result.is_constant = true;
Expand Down
3 changes: 3 additions & 0 deletions modules/gdscript/gdscript_analyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ class GDScriptAnalyzer {
void const_fold_array(GDScriptParser::ArrayNode *p_array);
void const_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary);

void parameter_fold_array(GDScriptParser::ArrayNode *p_array);
void parameter_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary);

// Helpers.
GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);
GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const;
Expand Down
4 changes: 2 additions & 2 deletions modules/gdscript/gdscript_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -702,13 +702,13 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
} break;
case GDScriptParser::Node::ARRAY: {
const GDScriptParser::ArrayNode *arr = static_cast<const GDScriptParser::ArrayNode *>(par->default_value);
if (arr->is_constant && arr->reduced) {
if (arr->reduced_value.get_type() != Variant::NIL && arr->reduced) {
def_val = arr->reduced_value.operator String();
}
} break;
case GDScriptParser::Node::DICTIONARY: {
const GDScriptParser::DictionaryNode *dict = static_cast<const GDScriptParser::DictionaryNode *>(par->default_value);
if (dict->is_constant && dict->reduced) {
if (dict->reduced_value.get_type() != Variant::NIL && dict->reduced) {
def_val = dict->reduced_value.operator String();
}
} break;
Expand Down