From 2929d784c2ed8d4864a4a2c52bcb0ee374ccefac Mon Sep 17 00:00:00 2001 From: erenbostanci Date: Thu, 4 Sep 2025 15:11:50 +0300 Subject: [PATCH] Rest parameter compatible types recognition Issue: ICUTNN Testing: Build Signed-off-by: erenbostanci --- ets2panda/checker/ETSAnalyzer.cpp | 2 +- ets2panda/checker/ets/function.cpp | 5 +- ets2panda/checker/types/type.cpp | 16 +++ ets2panda/checker/types/type.h | 6 + .../ast/compiler/ets/invalid_param_pack.ets | 4 +- .../ast/compiler/ets/null_pointer_error.ets | 2 +- .../ets/rest_compatible_type_check.ets | 121 ++++++++++++++++++ .../ast/compiler/ets/restvar_type_infer.ets | 4 +- .../ast/compiler/ets/type_error_test2.ets | 2 +- .../ets/FixedArray/MultipleParserErrors.ets | 10 +- .../ets/FixedArray/unexpected_token_31.ets | 2 +- .../ast/parser/ets/MultipleParserErrors.ets | 10 +- .../annotationUsage_bad_param07.ets | 2 +- .../test/ast/parser/ets/rest_parameter_14.ets | 4 +- .../ast/parser/ets/unexpected_token_31.ets | 2 +- ets2panda/util/diagnostic/syntax.yaml | 8 +- 16 files changed, 172 insertions(+), 28 deletions(-) create mode 100644 ets2panda/test/ast/compiler/ets/rest_compatible_type_check.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 0ce40af3ff..9fa83ca1b3 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -423,7 +423,7 @@ checker::Type *ETSAnalyzer::Check(ir::SpreadElement *expr) const return expr->SetTsType(exprType->AsETSObjectType()->TypeArguments().front()); } - if (!exprType->IsETSArrayType() && !exprType->IsETSTupleType() && !exprType->IsETSReadonlyArrayType()) { + if (!exprType->IsAnyETSArrayOrTupleType()) { if (!exprType->IsTypeError()) { // Don't duplicate error messages for the same error checker->LogError(diagnostic::SPREAD_OF_INVALID_TYPE, {exprType}, expr->Start()); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 1fd04a4a9e..0ff022f42d 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -1799,8 +1799,9 @@ SignatureInfo *ETSChecker::ComposeSignatureInfo(ir::TSTypeParameterDeclaration * return nullptr; } ES2PANDA_ASSERT(restParamType != nullptr); - if (!restParamType->IsAnyETSArrayOrTupleType()) { - LogError(diagnostic::ONLY_ARRAY_OR_TUPLE_FOR_REST, {}, param->Start()); + if (!restParamType->IsAnySpreadOrRestCompatibleType()) { + LogError(diagnostic::REST_PARAMETER_OF_INVALID_TYPE, {restParamType->MaybeBaseTypeOfGradualType()}, + param->Start()); restParamType = GlobalTypeError(); } signatureInfo->restVar = SetupSignatureParameter(param, restParamType); diff --git a/ets2panda/checker/types/type.cpp b/ets2panda/checker/types/type.cpp index 6944992590..c8d3095e47 100644 --- a/ets2panda/checker/types/type.cpp +++ b/ets2panda/checker/types/type.cpp @@ -60,6 +60,22 @@ bool Type::IsBuiltinNumeric() const noexcept return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_NUMERIC); } +bool Type::IsETSIterableType() const +{ + bool retVal = false; + if (IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) { + auto *iter = AsETSObjectType()->GetProperty(compiler::Signatures::ITERATOR_METHOD, + checker::PropertySearchFlags::SEARCH_INSTANCE_METHOD | + checker::PropertySearchFlags::SEARCH_IN_INTERFACES | + checker::PropertySearchFlags::SEARCH_IN_BASE); + + if (iter != nullptr) { + retVal = true; + } + } + return retVal; +} + bool Type::IsLambdaObject() const { if (IsETSObjectType() && (AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE) || diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index b0a50a0b51..0b7197c403 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -113,6 +113,7 @@ public: bool IsETSAsyncFuncReturnType() const; bool IsETSUnboxableObject() const; bool IsETSPrimitiveOrEnumType() const; + bool IsETSIterableType() const; bool IsETSDoubleEnumType() const; bool PossiblyETSNull() const; @@ -176,6 +177,11 @@ public: return HasTypeFlag(checker::TypeFlag::CONSTANT); } + bool IsAnySpreadOrRestCompatibleType() const + { + return IsAnyETSArrayOrTupleType() || IsETSIterableType(); + } + bool IsAnyETSArrayOrTupleType() const { return IsETSArrayType() || IsETSResizableArrayType() || IsETSReadonlyArrayType() || IsETSTupleType(); diff --git a/ets2panda/test/ast/compiler/ets/invalid_param_pack.ets b/ets2panda/test/ast/compiler/ets/invalid_param_pack.ets index 0ef867033b..0eb75d4c88 100644 --- a/ets2panda/test/ast/compiler/ets/invalid_param_pack.ets +++ b/ets2panda/test/ast/compiler/ets/invalid_param_pack.ets @@ -37,8 +37,8 @@ class Derived2 extends Base2{ } } -/* @@? 17:17 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 17:17 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 17:24 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ -/* @@? 29:13 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 29:13 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 29:20 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 36:3 Error TypeError: Property 'my_func' must be accessed through 'this' */ diff --git a/ets2panda/test/ast/compiler/ets/null_pointer_error.ets b/ets2panda/test/ast/compiler/ets/null_pointer_error.ets index 4297f3c7fe..b57521a84f 100644 --- a/ets2panda/test/ast/compiler/ets/null_pointer_error.ets +++ b/ets2panda/test/ast/compiler/ets/null_pointer_error.ets @@ -23,6 +23,6 @@ export class AbstractDaoSession{ /* @@? 1:3 Error TypeError: Cannot find type 'dataRdb'. */ /* @@? 1:3 Error TypeError: 'ValueType' type does not exist. */ -/* @@? 17:62 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 17:62 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 19:17 Error TypeError: Cannot find type 'AbstractDao'. */ /* @@? 20:16 Error TypeError: Type '*ERROR_TYPE*' can not be awaited, it is not a Promise. */ diff --git a/ets2panda/test/ast/compiler/ets/rest_compatible_type_check.ets b/ets2panda/test/ast/compiler/ets/rest_compatible_type_check.ets new file mode 100644 index 0000000000..d52c59a349 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/rest_compatible_type_check.ets @@ -0,0 +1,121 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable low or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +/* + Test Description: Following codes are to check if + argument type is compatible with rest parameter in + function, method decleration. +*/ + +// type alias +type TEntity = Record + +// aliased itarable type check +function foo(... args: TEntity){ + let it = args.$_iterator() + let count = 0 + for(let i of it){ + count++ + } + return count +} + +// Record type check +function foo1(... args: Record): number { + let it = args.$_iterator() + let count = 0 + for(let i of it){ + count++ + } + return count +} + +// Set type check +function foo2(... args: Set): number { + let it = args.$_iterator() + let count = 0 + for(let i of it){ + count++ + } + return count +} + +// Aliased array type check +function foo3(... args: TEntity[]): number { + let it = args.$_iterator() + let count = 0 + for(let i of it){ + count++ + } + return count +} + +// fixed array type check +function foo4(... args: FixedArray){ + return args.length +} + +// array type check +function foo5(... args: double[]){ + return args.length +} + +// tuple type check +function foo6(... args: [string, number]){ + return args[0] +} + +// derived iterable class +class A implements Iterable { + public data: string[] = ['1','2','3'] + public $_iterator(): AIterator { + return new AIterator(this) + } + + // array type check for a class method + public foo7(... args: string[]){ + this.data[0] = args[0] + } + + // Record type check for a class method + public foo8(key: number, ... args: Record){ + return args[key] + } +} + +class AIterator implements Iterator { + index = 0 + base: A + constructor(base: A){ + this.base = base + } + + next() : IteratorResult { + return { + done: this.index >= this.base.data.length, + value: this.index >= this.base.data.length ? undefined: this.base.data[this.index++] + } + } +} + +// derived iterable class type check +function foo9(... args: A): boolean { + return true +} + +function main() { + let entity: TEntity = {"a":"b", "c":"d"} +} \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/restvar_type_infer.ets b/ets2panda/test/ast/compiler/ets/restvar_type_infer.ets index b24788ce95..b0fdeab69b 100644 --- a/ets2panda/test/ast/compiler/ets/restvar_type_infer.ets +++ b/ets2panda/test/ast/compiler/ets/restvar_type_infer.ets @@ -19,8 +19,8 @@ function main() { } /* @@? 17:14 Error TypeError: Cannot use type 'void' as value. */ -/* @@? 17:16 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 17:16 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 17:16 Error TypeError: The type of parameter 'args' cannot be inferred */ /* @@? 18:14 Error TypeError: Cannot use type 'void' as value. */ -/* @@? 18:26 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 18:26 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 18:26 Error TypeError: The type of parameter 'args' cannot be inferred */ diff --git a/ets2panda/test/ast/compiler/ets/type_error_test2.ets b/ets2panda/test/ast/compiler/ets/type_error_test2.ets index 08c72c921a..9577786104 100644 --- a/ets2panda/test/ast/compiler/ets/type_error_test2.ets +++ b/ets2panda/test/ast/compiler/ets/type_error_test2.ets @@ -15,7 +15,7 @@ let f:(c:string, ...abe])=>void = (c:be ...abe])=>{} -/* @@? 16:18 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 16:18 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 16:24 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 16:24 Error SyntaxError: Rest parameter must be the last formal parameter. */ /* @@? 16:35 Error TypeError: Type '(c: *ERROR_TYPE*) => void' cannot be assigned to type '(c: String, ...abe: *ERROR_TYPE*) => void' */ diff --git a/ets2panda/test/ast/parser/ets/FixedArray/MultipleParserErrors.ets b/ets2panda/test/ast/parser/ets/FixedArray/MultipleParserErrors.ets index 4b647af6a8..38a4bddf8c 100644 --- a/ets2panda/test/ast/parser/ets/FixedArray/MultipleParserErrors.ets +++ b/ets2panda/test/ast/parser/ets/FixedArray/MultipleParserErrors.ets @@ -210,9 +210,9 @@ function main(): void { /* @@? 52:12 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 52:12 Error TypeError: Unresolved reference q */ /* @@? 52:23 Error TypeError: Unresolved reference p */ -/* @@? 55:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ -/* @@? 59:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ -/* @@? 63:22 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 55:14 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'Object' is provided. */ +/* @@? 59:14 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'Int' is provided. */ +/* @@? 63:22 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 63:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 67:7 Error TypeError: Merging declarations is not supported, please keep all definitions of classes, interfaces and enums compact in the codebase! */ /* @@? 67:7 Error TypeError: Variable 'A' has already been declared. */ @@ -229,8 +229,8 @@ function main(): void { /* @@? 92:7 Error TypeError: Merging declarations is not supported, please keep all definitions of classes, interfaces and enums compact in the codebase! */ /* @@? 92:7 Error TypeError: Variable 'A' has already been declared. */ /* @@? 93:3 Error SyntaxError: Unexpected token. A constructor, method, accessor, or property was expected. */ -/* @@? 103:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ -/* @@? 104:21 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 103:14 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'Byte' is provided. */ +/* @@? 104:21 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'Byte' is provided. */ /* @@? 115:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 115:26 Error SyntaxError: Unexpected token, expected ',' or ')'. */ /* @@? 115:26 Error SyntaxError: Unexpected token 'case'. */ diff --git a/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets b/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets index 37de6fe998..834b2feb5a 100644 --- a/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets +++ b/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets @@ -18,7 +18,7 @@ function foo(...^number: FixedArray): int { } /* @@? 16:10 Error TypeError: Only abstract or native methods can't have body. */ -/* @@? 16:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 16:14 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 16:17 Error SyntaxError: Unexpected token, expected an identifier. */ /* @@? 16:18 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 16:18 Error SyntaxError: Rest parameter must be the last formal parameter. */ diff --git a/ets2panda/test/ast/parser/ets/MultipleParserErrors.ets b/ets2panda/test/ast/parser/ets/MultipleParserErrors.ets index 257ff2bd18..7dcf7df61e 100644 --- a/ets2panda/test/ast/parser/ets/MultipleParserErrors.ets +++ b/ets2panda/test/ast/parser/ets/MultipleParserErrors.ets @@ -207,9 +207,9 @@ function main(): void { /* @@? 52:12 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 52:12 Error TypeError: Unresolved reference q */ /* @@? 52:23 Error TypeError: Unresolved reference p */ -/* @@? 55:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ -/* @@? 59:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ -/* @@? 63:22 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 55:14 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'Object' is provided. */ +/* @@? 59:14 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'Int' is provided. */ +/* @@? 63:22 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 63:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 67:7 Error TypeError: Merging declarations is not supported, please keep all definitions of classes, interfaces and enums compact in the codebase! */ /* @@? 67:7 Error TypeError: Variable 'A' has already been declared. */ @@ -226,8 +226,8 @@ function main(): void { /* @@? 92:7 Error TypeError: Variable 'A' has already been declared. */ /* @@? 92:7 Error TypeError: Merging declarations is not supported, please keep all definitions of classes, interfaces and enums compact in the codebase! */ /* @@? 93:3 Error SyntaxError: Unexpected token. A constructor, method, accessor, or property was expected. */ -/* @@? 103:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ -/* @@? 104:21 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 103:14 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'Byte' is provided. */ +/* @@? 104:21 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'Byte' is provided. */ /* @@? 115:26 Error SyntaxError: Unexpected token, expected an identifier. */ /* @@? 115:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 115:26 Error SyntaxError: Unexpected token, expected ',' or ')'. */ diff --git a/ets2panda/test/ast/parser/ets/annotations_tests/annotationUsage_bad_param07.ets b/ets2panda/test/ast/parser/ets/annotations_tests/annotationUsage_bad_param07.ets index d507754484..81a06a690b 100644 --- a/ets2panda/test/ast/parser/ets/annotations_tests/annotationUsage_bad_param07.ets +++ b/ets2panda/test/ast/parser/ets/annotations_tests/annotationUsage_bad_param07.ets @@ -21,5 +21,5 @@ function foo(@MyAnno ...a){} /* @@? 22:15 Error TypeError: The required field 'testProperty1' must be specified. Fields without default values cannot be omitted. */ -/* @@? 22:22 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 22:22 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 22:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ diff --git a/ets2panda/test/ast/parser/ets/rest_parameter_14.ets b/ets2panda/test/ast/parser/ets/rest_parameter_14.ets index 73bbbb9eb0..d548498baa 100644 --- a/ets2panda/test/ast/parser/ets/rest_parameter_14.ets +++ b/ets2panda/test/ast/parser/ets/rest_parameter_14.ets @@ -21,5 +21,5 @@ class B { moo(/* @@ label2 */...i: A) {} } -/* @@@ label1 Error SyntaxError: Rest parameter should be either array or tuple type. */ -/* @@@ label2 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@@ label1 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'A' is provided. */ +/* @@@ label2 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but 'A' is provided. */ diff --git a/ets2panda/test/ast/parser/ets/unexpected_token_31.ets b/ets2panda/test/ast/parser/ets/unexpected_token_31.ets index 01374410c3..38ef344262 100644 --- a/ets2panda/test/ast/parser/ets/unexpected_token_31.ets +++ b/ets2panda/test/ast/parser/ets/unexpected_token_31.ets @@ -18,7 +18,7 @@ function foo(...^number: int[]): int { } /* @@? 16:10 Error TypeError: Only abstract or native methods can't have body. */ -/* @@? 16:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ +/* @@? 16:14 Error SyntaxError: Rest parameter can be applied only to array, tuple or any iterable type, but '*ERROR_TYPE*' is provided. */ /* @@? 16:17 Error SyntaxError: Unexpected token, expected an identifier. */ /* @@? 16:18 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 16:18 Error SyntaxError: Rest parameter must be the last formal parameter. */ diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index 178787feee..50d7153745 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -927,10 +927,6 @@ syntax: id: 181 message: "Only ambient modules can use quoted names." -- name: ONLY_ARRAY_OR_TUPLE_FOR_REST - id: 193 - message: "Rest parameter should be either array or tuple type." - - name: ONLY_SPREAD_AT_LAST_INDEX id: 143 message: "Only one spread type declaration allowed, at the last index." @@ -1051,6 +1047,10 @@ syntax: id: 15 message: "Both optional and rest parameters are not allowed in function's parameter list." +- name: REST_PARAMETER_OF_INVALID_TYPE + id: 193 + message: "Rest parameter can be applied only to array, tuple or any iterable type, but '{}' is provided." + - name: REST_PARAM_NOT_LAST id: 67 message: "Rest parameter must be the last formal parameter." -- Gitee