summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitrii Maganov <vonagam@gmail.com>2023-02-24 00:01:27 +0200
committerDmitrii Maganov <vonagam@gmail.com>2023-02-24 00:35:11 +0200
commit55c5774be948752665059ba205336e1571b2f057 (patch)
tree445c1ac6f51aa8b837e1f5234f8253dd442ded6c
parente930c8d3838280e40baabc4426bd8236f7ac50a3 (diff)
GDScript: Fix range regression
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp35
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/for_range_usage.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/for_range_usage.out2
3 files changed, 32 insertions, 12 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 1161403c0c..e058187860 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -1857,29 +1857,40 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
push_error(vformat(R"*(Invalid call for "range()" function. Expected at most 3 arguments, %d given.)*", call->arguments.size()), call->callee);
} else {
// Now we can optimize it.
- bool all_is_constant = true;
+ bool can_reduce = true;
Vector<Variant> args;
args.resize(call->arguments.size());
for (int i = 0; i < call->arguments.size(); i++) {
GDScriptParser::ExpressionNode *argument = call->arguments[i];
reduce_expression(argument);
- if (!argument->is_constant) {
- all_is_constant = false;
- break;
- }
- if (argument->reduced_value.get_type() != Variant::INT && argument->reduced_value.get_type() != Variant::FLOAT) {
- push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, Variant::get_type_name(argument->reduced_value.get_type())), argument);
- all_is_constant = false;
- break;
+ if (argument->is_constant) {
+ if (argument->reduced_value.get_type() != Variant::INT && argument->reduced_value.get_type() != Variant::FLOAT) {
+ can_reduce = false;
+ push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, Variant::get_type_name(argument->reduced_value.get_type())), argument);
+ }
+ if (can_reduce) {
+ args.write[i] = argument->reduced_value;
+ }
+ } else {
+ can_reduce = false;
+ GDScriptParser::DataType argument_type = argument->get_datatype();
+ if (argument_type.is_variant() || !argument_type.is_hard_type()) {
+ mark_node_unsafe(argument);
+ }
+ if (!argument_type.is_variant() && (argument_type.builtin_type != Variant::INT && argument_type.builtin_type != Variant::FLOAT)) {
+ if (!argument_type.is_hard_type()) {
+ downgrade_node_type_source(argument);
+ } else {
+ push_error(vformat(R"*(Invalid argument for "range()" call. Argument %d should be int or float but "%s" was given.)*", i + 1, argument_type.to_string()), argument);
+ }
+ }
}
-
- args.write[i] = argument->reduced_value;
}
Variant reduced;
- if (all_is_constant) {
+ if (can_reduce) {
switch (args.size()) {
case 1:
reduced = (int32_t)args[0];
diff --git a/modules/gdscript/tests/scripts/analyzer/features/for_range_usage.gd b/modules/gdscript/tests/scripts/analyzer/features/for_range_usage.gd
new file mode 100644
index 0000000000..4a7f10f1ee
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/for_range_usage.gd
@@ -0,0 +1,7 @@
+func test():
+ var array := [3, 6, 9]
+ var result := ''
+ for i in range(array.size(), 0, -1):
+ result += str(array[i - 1])
+ assert(result == '963')
+ print('ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/features/for_range_usage.out b/modules/gdscript/tests/scripts/analyzer/features/for_range_usage.out
new file mode 100644
index 0000000000..1b47ed10dc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/for_range_usage.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+ok