diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index c1bc7afee540830ac9c6951a65b3aae3526b4e29..3937e3dee873625cb6dd9f0db73048a74a920891 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -809,10 +809,22 @@ Signature *ETSChecker::ChooseMostSpecificSignature(ArenaVector &sig // Multiple signatures with zero parameter because of inheritance. // Return the closest one in inheritance chain that is defined at the beginning of the vector. if (paramCount == 0) { - if (signatures.front()->RestVar() == nullptr) { - return signatures.front(); + auto zeroParamSignature = std::find_if(signatures.begin(), signatures.end(), + [](auto *signature) { return signature->RestVar() == nullptr; }); + // If there is a zero parameter signature, return that + if (zeroParamSignature != signatures.end()) { + return *zeroParamSignature; } - ThrowTypeError({"Call to `", signatures.front()->Function()->Id()->Name(), "` is ambiguous "}, pos); + // If there are multiple rest parameter signatures with different argument types, throw error + if (signatures.size() > 1 && std::any_of(signatures.begin(), signatures.end(), [signatures](const auto *param) { + return param->RestVar()->TsType() != signatures.front()->RestVar()->TsType(); + })) { + ThrowTypeError({"Call to `", signatures.front()->Function()->Id()->Name(), "` is ambiguous "}, pos); + } + // Else return the signature with the rest parameter + auto restParamSignature = std::find_if(signatures.begin(), signatures.end(), + [](auto *signature) { return signature->RestVar() != nullptr; }); + return *restParamSignature; } // Collect which signatures are most specific for each parameter. @@ -950,7 +962,8 @@ void ETSChecker::CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK); Relation()->IsIdenticalTo(func, overload); - if (Relation()->IsTrue()) { + if (Relation()->IsTrue() && func->CallSignatures()[0]->GetSignatureInfo()->restVar == + overload->CallSignatures()[0]->GetSignatureInfo()->restVar) { ThrowTypeError("Function " + func->Name().Mutf8() + " is already declared.", currentFunc->Start()); } if (HasSameAssemblySignature(func, overload)) { diff --git a/ets2panda/test/compiler/ets/functions_with_ambiguous_rest_parameter-expected.txt b/ets2panda/test/compiler/ets/functions_with_ambiguous_rest_parameter-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e694e14255b9c088ccb123774f278f72117823e --- /dev/null +++ b/ets2panda/test/compiler/ets/functions_with_ambiguous_rest_parameter-expected.txt @@ -0,0 +1,712 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 13 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 13 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "rest parameter": { + "type": "RestElement", + "argument": { + "type": "Identifier", + "name": "n", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 17 + }, + "end": { + "line": 16, + "column": 18 + } + } + }, + "typeAnnotation": { + "type": "TSArrayType", + "elementType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "number", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 20 + }, + "end": { + "line": 16, + "column": 26 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 20 + }, + "end": { + "line": 16, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 20 + }, + "end": { + "line": 16, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 28 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 29 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 31 + }, + "end": { + "line": 16, + "column": 35 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 16, + "column": 36 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "overloads": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 10 + }, + "end": { + "line": 20, + "column": 13 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 10 + }, + "end": { + "line": 20, + "column": 13 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "rest parameter": { + "type": "RestElement", + "argument": { + "type": "Identifier", + "name": "s", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 17 + }, + "end": { + "line": 20, + "column": 18 + } + } + }, + "typeAnnotation": { + "type": "TSArrayType", + "elementType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 20 + }, + "end": { + "line": 20, + "column": 26 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 20 + }, + "end": { + "line": 20, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 20 + }, + "end": { + "line": 20, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 28 + }, + "end": { + "line": 20, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 20, + "column": 29 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 20, + "column": 29 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 20, + "column": 31 + }, + "end": { + "line": 20, + "column": 35 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 20, + "column": 36 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 13 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 13 + }, + "end": { + "line": 22, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 22, + "column": 2 + } + } + } + ], + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 10 + }, + "end": { + "line": 24, + "column": 14 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 10 + }, + "end": { + "line": 24, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 24, + "column": 18 + }, + "end": { + "line": 24, + "column": 22 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 25, + "column": 5 + }, + "end": { + "line": 25, + "column": 8 + } + } + }, + "arguments": [], + "optional": false, + "loc": { + "start": { + "line": 25, + "column": 5 + }, + "end": { + "line": 25, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 25, + "column": 5 + }, + "end": { + "line": 25, + "column": 11 + } + } + } + ], + "loc": { + "start": { + "line": 24, + "column": 23 + }, + "end": { + "line": 26, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 26, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 26, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 1 + }, + "end": { + "line": 26, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 26, + "column": 2 + } + } +} +TypeError: Call to `foo` is ambiguous [functions_with_ambiguous_rest_parameter.sts:25:5] diff --git a/ets2panda/test/compiler/ets/functions_with_ambiguous_rest_parameter.sts b/ets2panda/test/compiler/ets/functions_with_ambiguous_rest_parameter.sts new file mode 100644 index 0000000000000000000000000000000000000000..25f70152405fdd6422b6e9e51d1c1fa1c82dfbc7 --- /dev/null +++ b/ets2panda/test/compiler/ets/functions_with_ambiguous_rest_parameter.sts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 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 law 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. + */ + +function foo(...n: number[]): void { + +} + +function foo(...s: string[]): void { + +} + +function main(): void { + foo(); +} \ No newline at end of file diff --git a/ets2panda/test/parser/ets/default_parameter7-expected.txt b/ets2panda/test/parser/ets/default_parameter7-expected.txt index a00cec04aa5f3e10f5efff8638c248d82c1d0056..87b2956f03dfdd3fcf1088dec54ed9c5d8b19519 100644 --- a/ets2panda/test/parser/ets/default_parameter7-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter7-expected.txt @@ -1645,4 +1645,3 @@ } } } -TypeError: Function foo is already declared. [default_parameter7.sts:1:1] diff --git a/ets2panda/test/parser/ets/rest_parameter_01-expected.txt b/ets2panda/test/parser/ets/rest_parameter_01-expected.txt index 549cac73c48e6c05646c50f17e201c39b56a1306..4fd30c60ca800621cb87135a576884c77144b7cd 100644 --- a/ets2panda/test/parser/ets/rest_parameter_01-expected.txt +++ b/ets2panda/test/parser/ets/rest_parameter_01-expected.txt @@ -614,4 +614,3 @@ } } } -TypeError: Function foo is already declared. [rest_parameter_01.sts:20:1] diff --git a/ets2panda/test/parser/ets/rest_parameter_02-expected.txt b/ets2panda/test/parser/ets/rest_parameter_02-expected.txt index 5482b39d62619a12d166c8dd816dab2517e0f3c9..fc868a90e8a7441af8387a326c64a501ef5c8881 100644 --- a/ets2panda/test/parser/ets/rest_parameter_02-expected.txt +++ b/ets2panda/test/parser/ets/rest_parameter_02-expected.txt @@ -960,4 +960,3 @@ } } } -TypeError: Function foo is already declared. [rest_parameter_02.sts:20:1] diff --git a/ets2panda/test/runtime/ets/FunctionOverload.sts b/ets2panda/test/runtime/ets/FunctionOverload.sts new file mode 100644 index 0000000000000000000000000000000000000000..24f740cae63ab9c0ad167ab7198b729f07ce0234 --- /dev/null +++ b/ets2panda/test/runtime/ets/FunctionOverload.sts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 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 law 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. + */ + +class Overload { + public static func(): string { + return "zero"; + } + + public static func(a: number): string { + return "one"; + } + + public static func(a: number, b: number): string { + return "two"; + } + + public static func(...args: number[]): string { + return "variadic"; + } +} + +function main(): void { + assert Overload.func() == "zero"; + assert Overload.func(1) == "one"; + assert Overload.func(1, 2) == "two"; + assert Overload.func(1, 2, 3) == "variadic"; + + let arr: number[] = [1, 2]; + assert Overload.func(...arr) == "variadic"; +} diff --git a/ets2panda/test/runtime/ets/most_specific_method_with_rest_param_4.sts b/ets2panda/test/runtime/ets/most_specific_method_with_rest_param_4.sts new file mode 100644 index 0000000000000000000000000000000000000000..11c8f8979d9578f47b763e39be179b0661988331 --- /dev/null +++ b/ets2panda/test/runtime/ets/most_specific_method_with_rest_param_4.sts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 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 law 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. + */ + +class A { + foo(...n: number[]){ + return "A"; + } +} + +class B extends A { + foo(...n: number[]){ + return "B"; + } +} + +class C extends B { + foo(...n: number[]){ + return "C"; + } +} + +function main() { + let a: A = new A(); + let b: B = new B(); + let c: C = new C(); + assert a.foo() == "A"; + assert a.foo(1) == "A"; + assert b.foo() == "B"; + assert b.foo(1,2) == "B"; + assert c.foo() == "C"; + assert c.foo(1,2,3) == "C"; +} \ No newline at end of file