diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 978b0b2beed1b92403a6815b076183561f709bea..9a322ad65557ad990a4c4bb2d342a7ed574497b4 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -411,9 +411,8 @@ public: bool CheckLambdaTypeAnnotation(ir::ETSParameterExpression *param, ir::ArrowFunctionExpression *arrowFuncExpr, Type *parameterType, TypeRelationFlag flags); bool CheckLambdaInfer(ir::AstNode *typeAnnotation, ir::ArrowFunctionExpression *arrowFuncExpr, - Type *const subParameterType); - bool CheckLambdaAssignable(ir::Expression *param, ir::ScriptFunction *lambda); - bool CheckLambdaAssignableUnion(ir::AstNode *typeAnn, ir::ScriptFunction *lambda); + Type *subParameterType); + bool DoesLambdaMatchRequiredArity(const Type *targetType, const ir::ScriptFunction *callingLambda); bool IsCompatibleTypeArgument(ETSTypeParameter *typeParam, Type *typeArgument, const Substitution *substitution); ArenaSubstitution *NewArenaSubstitution() @@ -460,7 +459,6 @@ public: bool reportError); bool ValidateSignatureInvocationContext(Signature *substitutedSig, ir::Expression *argument, std::size_t index, TypeRelationFlag flags); - bool CheckOptionalLambdaFunction(ir::Expression *argument, Signature *substitutedSig, std::size_t index); bool ValidateArgumentAsIdentifier(const ir::Identifier *identifier); bool IsValidRestArgument(ir::Expression *argument, Signature *substitutedSig, TypeRelationFlag flags, std::size_t index); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 22f1c94672ee59da68944b5fef8c27d3f81db994..50bad30fcaead3b3cfc6e7d04394f36d831cbf38 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -364,21 +364,6 @@ Signature *ETSChecker::ValidateParameterlessConstructor(Signature *signature, co return signature; } -// #22952: remove optional arrow leftovers -bool ETSChecker::CheckOptionalLambdaFunction(ir::Expression *argument, Signature *substitutedSig, std::size_t index) -{ - if (argument->IsArrowFunctionExpression()) { - auto *const arrowFuncExpr = argument->AsArrowFunctionExpression(); - - if (ir::ScriptFunction *const lambda = arrowFuncExpr->Function(); - CheckLambdaAssignable(substitutedSig->Function()->Params()[index], lambda)) { - return true; - } - } - - return false; -} - bool ETSChecker::ValidateArgumentAsIdentifier(const ir::Identifier *identifier) { auto result = Scope()->Find(identifier->Name()); @@ -412,8 +397,8 @@ static bool CheckArrowFunctionParamIfNeeded(ETSChecker *checker, Signature *subs { if ((flags & TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA) != 0 && arguments.back()->IsArrowFunctionExpression()) { ir::ScriptFunction *const lambda = arguments.back()->AsArrowFunctionExpression()->Function(); - auto targetParm = substitutedSig->GetSignatureInfo()->params.back()->Declaration()->Node(); - if (!checker->CheckLambdaAssignable(targetParm->AsETSParameterExpression(), lambda)) { + auto paramType = substitutedSig->Params().back()->TsType(); + if (!checker->DoesLambdaMatchRequiredArity(paramType, lambda)) { return false; } } @@ -430,17 +415,15 @@ bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig, commonArity = commonArity - 1; } for (size_t index = 0; index < commonArity; ++index) { - auto &argument = arguments[index]; + auto *const argument = arguments[index]; // #22952: infer optional parameter heuristics - auto const paramType = GetNonNullishType(substitutedSig->Params()[index]->TsType()); + auto *const paramType = GetNonNullishType(substitutedSig->Params()[index]->TsType()); if (argument->IsObjectExpression()) { - if (!paramType->IsETSObjectType()) { - return false; - } - if (paramType->AsETSObjectType()->IsBoxedPrimitive()) { + if (!paramType->IsETSObjectType() || paramType->AsETSObjectType()->IsBoxedPrimitive()) { return false; } + argument->SetPreferredType(paramType); } @@ -458,10 +441,18 @@ bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig, if (argTypeInferenceRequired[index]) { ES2PANDA_ASSERT(argument->IsArrowFunctionExpression()); + auto *const arrowFunExpr = argument->AsArrowFunctionExpression(); + // There are cases, where we could infer the correct overload based on parameter number. We still + // need to check the body of the lambda, but it could be moved to a more appropriate place + if (paramType->IsETSUnionType() || + (paramType->IsETSObjectType() && Relation()->IsSupertypeOf(paramType, GlobalBuiltinFunctionType()))) { + // NOTE (smartin): this check with the if condition is completely wrong here, and need to be put into + // the appropriate place, but we need to rework the whole most specific signature selection for that. + // Until then it stays here, because some code already depend on this + arrowFunExpr->Check(this); + } // Note: If the signatures are from lambdas, then they have no `Function`. - ir::ScriptFunction *const lambda = argument->AsArrowFunctionExpression()->Function(); - auto targetParm = substitutedSig->GetSignatureInfo()->params[index]->Declaration()->Node(); - if (CheckLambdaAssignable(targetParm->AsETSParameterExpression(), lambda)) { + if (DoesLambdaMatchRequiredArity(paramType, arrowFunExpr->Function())) { continue; } return false; @@ -496,7 +487,7 @@ bool ETSChecker::ValidateSignatureInvocationContext(Signature *substitutedSig, i checker::InvocationContext(Relation(), argument, argumentType, targetType, argument->Start(), {{diagnostic::TYPE_MISMATCH_AT_IDX, {argumentType, targetType, index + 1}}}, flags); - return invocationCtx.IsInvocable() || CheckOptionalLambdaFunction(argument, substitutedSig, index); + return invocationCtx.IsInvocable(); } bool ETSChecker::IsValidRestArgument(ir::Expression *const argument, Signature *const substitutedSig, diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 2d284a52d0cdb8acb5c41c3d66f89c35fa3dd538..102eedaeb0dc98bb52e70e94d693d284e5b1425c 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2462,18 +2462,6 @@ std::vector ETSChecker::FindTypeInferenceArguments(const ArenaVectorAsETSUnionType()->Types()) { - if (type->IsETSFunctionType()) { - return lambda->Params().size() == type->AsETSFunctionType()->Params().size(); - } - } - - return false; -} - void ETSChecker::InferTypesForLambda(ir::ScriptFunction *lambda, ir::ETSFunctionType *calleeType, Signature *maybeSubstitutedFunctionSig) { diff --git a/ets2panda/checker/ets/typeCheckingHelpers.cpp b/ets2panda/checker/ets/typeCheckingHelpers.cpp index 515b663e3878f586e60cc62e7affae3d28cbe31c..99287cd5e67aadcc763c4e6d8881b1552f07f46c 100644 --- a/ets2panda/checker/ets/typeCheckingHelpers.cpp +++ b/ets2panda/checker/ets/typeCheckingHelpers.cpp @@ -1323,6 +1323,27 @@ void ETSChecker::CheckUnboxedSourceTypeWithWideningAssignable(TypeRelation *rela } } +// #22952: optional arrow leftovers +bool ETSChecker::DoesLambdaMatchRequiredArity(const Type *const targetType, + const ir::ScriptFunction *const callingLambda) +{ + // NOTE (smartin): still need a full solution for the inference, but it needs to be completely reworked with the + // most specific signature selection + if (targetType->IsETSFunctionType()) { + const auto *const targetFunctionType = targetType->AsETSFunctionType(); + return callingLambda->Params().size() <= targetFunctionType->ArrowSignature()->Params().size(); + } + + if (targetType->IsETSUnionType()) { + const auto &typesInUnion = targetType->AsETSUnionType()->ConstituentTypes(); + return std::any_of(typesInUnion.begin(), typesInUnion.end(), [this, &callingLambda](const Type *const type) { + return DoesLambdaMatchRequiredArity(type, callingLambda); + }); + } + + return targetType->IsETSObjectType() && Relation()->IsSupertypeOf(targetType, GlobalBuiltinFunctionType()); +} + static ir::AstNode *DerefETSTypeReference(ir::AstNode *node) { ES2PANDA_ASSERT(node->IsETSTypeReference()); @@ -1341,38 +1362,6 @@ static ir::AstNode *DerefETSTypeReference(ir::AstNode *node) return node; } -// #22952: optional arrow leftovers -bool ETSChecker::CheckLambdaAssignable(ir::Expression *param, ir::ScriptFunction *lambda) -{ - ES2PANDA_ASSERT(param->IsETSParameterExpression()); - ir::AstNode *typeAnn = param->AsETSParameterExpression()->Ident()->TypeAnnotation(); - if (typeAnn == nullptr) { - return false; - } - if (typeAnn->IsETSTypeReference() && !typeAnn->AsETSTypeReference()->TsType()->IsETSArrayType()) { - typeAnn = DerefETSTypeReference(typeAnn); - } - - if (!typeAnn->IsETSFunctionType()) { - // the surrounding function is made so we can *bypass* the typecheck in the "inference" context, - // however the body of the function has to be checked in any case - if (typeAnn->IsETSUnionType()) { - lambda->Parent()->Check(this); - return CheckLambdaAssignableUnion(typeAnn, lambda); - } - - Type *paramType = param->AsETSParameterExpression()->Ident()->TsType(); - if (Relation()->IsSupertypeOf(paramType, GlobalBuiltinFunctionType())) { - lambda->Parent()->Check(this); - return true; - } - return false; - } - - ir::ETSFunctionType *calleeType = typeAnn->AsETSFunctionType(); - return lambda->Params().size() <= calleeType->Params().size(); -} - bool ETSChecker::CheckLambdaInfer(ir::AstNode *typeAnnotation, ir::ArrowFunctionExpression *const arrowFuncExpr, Type *const subParameterType) { diff --git a/ets2panda/checker/types/ets/etsFunctionType.cpp b/ets2panda/checker/types/ets/etsFunctionType.cpp index 0ec3b4ecaca3259907143dc8f1e7358d05407ff4..e7832fce8333dd31cb994c1dc83b14a8c0ceeb2d 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -219,15 +219,18 @@ static bool SignatureIsSupertypeOf(TypeRelation *relation, Signature *super, Sig return false; } } - for (size_t idx = 0; idx != sub->MinArgCount(); idx++) { + + const size_t commonArgCount = std::min(super->ArgCount(), sub->ArgCount()); + for (size_t idx = 0; idx < commonArgCount; idx++) { if (!relation->IsSupertypeOf(sub->Params()[idx]->TsType(), super->Params()[idx]->TsType())) { return false; } } + if (super->RestVar() != nullptr && !relation->IsSupertypeOf(sub->RestVar()->TsType(), super->RestVar()->TsType())) { return false; } - if (!relation->IsSupertypeOf(super->ReturnType(), sub->ReturnType())) { + if (!super->ReturnType()->IsETSVoidType() && !relation->IsSupertypeOf(super->ReturnType(), sub->ReturnType())) { return false; } return SignatureThrowKindToOrder(super) <= SignatureThrowKindToOrder(sub); diff --git a/ets2panda/checker/types/signature.cpp b/ets2panda/checker/types/signature.cpp index 5ced79c41120e511b5f411031ffe5a045c8275b0..f4b8c109bd9d2590211a7876253c30b4aed6700d 100644 --- a/ets2panda/checker/types/signature.cpp +++ b/ets2panda/checker/types/signature.cpp @@ -216,12 +216,17 @@ static bool MethodSignaturesAreCompatible(TypeRelation *relation, bool checkIden return false; } - auto const areCompatible = [relation, checkIdentical](Type *superT, Type *subT) { + auto const areCompatible = [&relation, checkIdentical](const Type *superT, const Type *subT) { + if (!checkIdentical && superT->IsETSVoidType()) { + return true; + } + return checkIdentical ? relation->IsIdenticalTo(superT, subT) : relation->IsSupertypeOf(superT, subT); }; if (!relation->NoReturnTypeCheck() && !areCompatible(super->ReturnType(), sub->ReturnType())) { return false; } + for (size_t idx = 0; idx < sub->ArgCount(); ++idx) { if (!areCompatible(sub->Params()[idx]->TsType(), super->Params()[idx]->TsType())) { return false; diff --git a/ets2panda/test/ast/compiler/ets/assertInTopLevelStatement.ets b/ets2panda/test/ast/compiler/ets/assertInTopLevelStatement.ets index 6d8a31721c9bc96d2874ed926040d1f725bd20f3..90aa863f94e78a99c7ca2c85c5bcb623b9fbf488 100644 --- a/ets2panda/test/ast/compiler/ets/assertInTopLevelStatement.ets +++ b/ets2panda/test/ast/compiler/ets/assertInTopLevelStatement.ets @@ -28,3 +28,5 @@ let promise2 = promise1.catch((value: string): string => { return "bye"; }) +/* @@? 25:16 Error TypeError: No matching call signature for catch((value: String) => String) */ +/* @@? 25:16 Error TypeError: No matching call signature for catch((value: String) => String) */ diff --git a/ets2panda/test/ast/compiler/ets/function_subtyping_4_neg.ets b/ets2panda/test/ast/compiler/ets/function_subtyping_4_neg.ets new file mode 100644 index 0000000000000000000000000000000000000000..74b71f1758c920b9926b497ad2aa7db420854fbf --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/function_subtyping_4_neg.ets @@ -0,0 +1,42 @@ +/* + * 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 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 main(): void { + let c1: (p0?: number) => void = /* @@ label1 */(p0: string): void => { } + let c2: (p0: string, p1?: number) => void = /* @@ label2 */(p0: string, p1: string): void => { } + let c3: (p0?: number) => void = /* @@ label3 */(p0?: string): void => { } + let c4: (p0?: number, p1?: number) => void = /* @@ label4 */(p0?: string, p1?: string): void => { } + let c5: (p0?: number) => void = /* @@ label5 */(p0?: string, p1?: number): void => { } + let c6: (p0: number) => void = /* @@ label6 */(p0: string, p1?: number): void => { } + let c7: (p0?: number) => void = /* @@ label7 */(p0?: number, /* @@ label13 */p1: string): void => { } + let c8: (p0: number) => void = /* @@ label8 */(p0?: string): void => { } + let c9: (p0: number) => void = /* @@ label9 */(p0?: string, p1?: number): void => { } + let c10: (...p0: number[]) => void = /* @@ label10 */(p0?: string): void => { } + let c11: (...p0/* @@ label11 */?: number[]) => void = /* @@ label12 */(p0?: string): void => { } +} + +/* @@@ label1 Error TypeError: Type '(p0: String) => void' cannot be assigned to type '(p0: Double|undefined) => void' */ +/* @@@ label2 Error TypeError: Type '(p0: String, p1: String) => void' cannot be assigned to type '(p0: String, p1: Double|undefined) => void' */ +/* @@@ label3 Error TypeError: Type '(p0: String|undefined) => void' cannot be assigned to type '(p0: Double|undefined) => void' */ +/* @@@ label4 Error TypeError: Type '(p0: String|undefined, p1: String|undefined) => void' cannot be assigned to type '(p0: Double|undefined, p1: Double|undefined) => void' */ +/* @@@ label5 Error TypeError: Type '(p0: String|undefined, p1: Double|undefined) => void' cannot be assigned to type '(p0: Double|undefined) => void' */ +/* @@@ label6 Error TypeError: Type '(p0: String, p1: Double|undefined) => void' cannot be assigned to type '(p0: Double) => void' */ +/* @@@ label7 Error TypeError: Type '(p0: Double|undefined, p1: String) => void' cannot be assigned to type '(p0: Double|undefined) => void' */ +/* @@@ label8 Error TypeError: Type '(p0: String|undefined) => void' cannot be assigned to type '(p0: Double) => void' */ +/* @@@ label9 Error TypeError: Type '(p0: String|undefined, p1: Double|undefined) => void' cannot be assigned to type '(p0: Double) => void' */ +/* @@@ label10 Error TypeError: Type '(p0: String|undefined) => void' cannot be assigned to type '(...p0: Array) => void' */ +/* @@@ label11 Error SyntaxError: Rest parameter cannot have the default value. */ +/* @@@ label12 Error TypeError: Type '(p0: String|undefined) => void' cannot be assigned to type '(...p0: Array) => void' */ +/* @@@ label13 Error SyntaxError: A required parameter cannot follow an optional parameter. */ diff --git a/ets2panda/test/ast/compiler/ets/function_subtyping_5.ets b/ets2panda/test/ast/compiler/ets/function_subtyping_5.ets new file mode 100644 index 0000000000000000000000000000000000000000..68237cc58767b7566c6d0aa82ba4d21078832be7 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/function_subtyping_5.ets @@ -0,0 +1,19 @@ +/* + * 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 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 main(): void { + let c1: (p0?: number) => void = (p0?: number, p1?: string): void => { } + let c2: (p0: number) => void = (p0: number, p1?: string): void => { } +} diff --git a/ets2panda/test/ast/compiler/ets/function_subtyping_6.ets b/ets2panda/test/ast/compiler/ets/function_subtyping_6.ets new file mode 100644 index 0000000000000000000000000000000000000000..7db6ed5af72cc4242d0b99fb9f724bd2551f352a --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/function_subtyping_6.ets @@ -0,0 +1,29 @@ +/* + * 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 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(f1: (f2: (p?: number) => void) => void) { + let fn = (p?: number) => { + console.log((p ?? 0) + 123) + } + f1(fn) +} + +function test() { + foo(/* @@ label1 */(f2: (p: string) => void) => { + f2("a") + }) +} + +/* @@@ label1 Error TypeError: Type '(f2: (p: String) => void) => void' is not compatible with type '(f2: (p: Double|undefined) => void) => void' at index 1 */ diff --git a/ets2panda/test/ast/compiler/ets/generics_implicit_lambda2.ets b/ets2panda/test/ast/compiler/ets/generics_implicit_lambda2.ets index 5b39271b37ec918f80b393f759ea5f4070630ea2..acb2fdc1fc786a57375a541ac7176a88e49eb298 100644 --- a/ets2panda/test/ast/compiler/ets/generics_implicit_lambda2.ets +++ b/ets2panda/test/ast/compiler/ets/generics_implicit_lambda2.ets @@ -16,7 +16,8 @@ function foo(first: (a: U, b: T, c: U) => T): T {} function main() { - foo(/* @@ label */(a: int, b: String, c: String): String => { return "XXX" }); + /* @@ label */foo(/* @@ label1 */(a: int, b: String, c: String): String => { return "XXX" }); } -/* @@@ label Error TypeError: Type '(a: Int, b: String, c: String) => String' is not compatible with type '(a: Int, b: String, c: Int) => String' at index 1 */ +/* @@@ label Error TypeError: No matching call signature for foo((a: Int, b: String, c: String) => String) */ +/* @@@ label1 Error TypeError: Type '(a: Int, b: String, c: String) => String' is not compatible with type '(a: Int, b: String, c: Int) => String' at index 1 */ diff --git a/ets2panda/test/ast/compiler/ets/resolve_func_name_union_type.ets b/ets2panda/test/ast/compiler/ets/resolve_func_name_union_type.ets index 5cfc8c78642328650aac7d6c878559420bd02e27..09bf7f72a3814342adcd0f391dc9e2af845204be 100644 --- a/ets2panda/test/ast/compiler/ets/resolve_func_name_union_type.ets +++ b/ets2panda/test/ast/compiler/ets/resolve_func_name_union_type.ets @@ -25,5 +25,4 @@ function main() { arktest.assertTrue((v as NumFunc)() == 3.14); // Is used 'arktest.assertTrue' due to #22840 } -/* @@? 24:17 Error TypeError: Type '() => Double' cannot be assigned to type '() => void|Double' */ /* @@? 25:24 Error TypeError: Cannot use type 'void' as value. */ diff --git a/ets2panda/test/ast/parser/ets/lambda-type-inference-overloaded-1.ets b/ets2panda/test/ast/parser/ets/lambda-type-inference-overloaded-1.ets index be682f7d2f1445a16670690f5652e3df7f3f69f3..8ab267434de4b279a18a4ac45f610e718e935e25 100644 --- a/ets2panda/test/ast/parser/ets/lambda-type-inference-overloaded-1.ets +++ b/ets2panda/test/ast/parser/ets/lambda-type-inference-overloaded-1.ets @@ -36,4 +36,3 @@ function main(): void { /* @@@ label Error TypeError: Function foo with this assembly signature already declared. */ /* @@@ label1 Error TypeError: Type 'void' is not compatible with the enclosing method's return type 'Boolean' */ -/* @@? 28:9 Error TypeError: Type '(x: Double, y: String) => Boolean' is not compatible with type '(x: Int, y: String) => Boolean' at index 1 */ diff --git a/ets2panda/test/ast/parser/ets/lambda_optional_param_2.ets b/ets2panda/test/ast/parser/ets/lambda_optional_param_2.ets index 5e7f4e4636a07667cf57d81a8b26207e4a9e3061..e09d211f9c99e0cfa3e0cdeb2efbfe9d743ad5ed 100644 --- a/ets2panda/test/ast/parser/ets/lambda_optional_param_2.ets +++ b/ets2panda/test/ast/parser/ets/lambda_optional_param_2.ets @@ -18,7 +18,8 @@ function gf(x: String, fn: (x?: String) => Int): Int { } function main(): void { - gf("abc" as String, /* @@ label */(x: String): Int => { return x=="TEST"?0:1}) + /* @@ label */gf("abc" as String, /* @@ label1 */(x: String): Int => { return x=="TEST"?0:1}) } -/* @@@ label Error TypeError: Type '(x: String) => Int' is not compatible with type '(x: String|undefined) => Int' at index 2 */ +/* @@@ label Error TypeError: No matching call signature for gf(String, (x: String) => Int) */ +/* @@@ label1 Error TypeError: Type '(x: String) => Int' is not compatible with type '(x: String|undefined) => Int' at index 2 */ diff --git a/ets2panda/test/ast/parser/ets/lambda_optional_param_3.ets b/ets2panda/test/ast/parser/ets/lambda_optional_param_3.ets index 243d1920d6f13aaa1cd0503eb4339d9b6a809c0b..679b67e4f814e7603f51214110009fc633aa55e3 100644 --- a/ets2panda/test/ast/parser/ets/lambda_optional_param_3.ets +++ b/ets2panda/test/ast/parser/ets/lambda_optional_param_3.ets @@ -18,8 +18,9 @@ function gf(x: String, fn: (x: String = /* @@ label */"TEST") => Int): Int { } function main(): void { - gf("abc" as String, (x: String): Int => { return x=="TEST"?0:1}) + /* @@ label2 */gf("abc" as String, /* @@ label3 */(x: String): Int => { return x=="TEST"?0:1}) } -/* @@@ label Error SyntaxError: Default value is allowed only for optional parameters. */ -/* @@? 21:24 Error TypeError: Type '(x: String) => Int' is not compatible with type '(x: String|undefined) => Int' at index 2 */ +/* @@@ label Error SyntaxError: Default value is allowed only for optional parameters. */ +/* @@@ label2 Error TypeError: No matching call signature for gf(String, (x: String) => Int) */ +/* @@@ label3 Error TypeError: Type '(x: String) => Int' is not compatible with type '(x: String|undefined) => Int' at index 2 */ diff --git a/ets2panda/test/ast/parser/ets/lambda_optional_param_4.ets b/ets2panda/test/ast/parser/ets/lambda_optional_param_4.ets new file mode 100644 index 0000000000000000000000000000000000000000..52afac8ee74e998130618400baf906c1697cee18 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/lambda_optional_param_4.ets @@ -0,0 +1,21 @@ +/* + * 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 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 gf(x: String, fn: (x: String = /* @@ label */"TEST") => Int): Int { + return fn(x) +} + + +/* @@@ label Error SyntaxError: Default value is allowed only for optional parameters. */ diff --git a/ets2panda/test/parser/ets/lambda-type-inference-overloaded-expected.txt b/ets2panda/test/parser/ets/lambda-type-inference-overloaded-expected.txt index 2203a5146a498ba93346a9bcdc120d7fc3c8d873..275a33c42a46290cadf29f113373b3869995e06f 100644 --- a/ets2panda/test/parser/ets/lambda-type-inference-overloaded-expected.txt +++ b/ets2panda/test/parser/ets/lambda-type-inference-overloaded-expected.txt @@ -1637,7 +1637,7 @@ "program": "lambda-type-inference-overloaded.ets" }, "end": { - "line": 35, + "line": 38, "column": 1, "program": "lambda-type-inference-overloaded.ets" } diff --git a/ets2panda/test/parser/ets/lambda-type-inference-overloaded.ets b/ets2panda/test/parser/ets/lambda-type-inference-overloaded.ets index f49c757dc8cee0f9ad36e841497fde01eab462f1..17ac071757dea651972bc163e14118c834d6ae94 100644 --- a/ets2panda/test/parser/ets/lambda-type-inference-overloaded.ets +++ b/ets2panda/test/parser/ets/lambda-type-inference-overloaded.ets @@ -32,3 +32,6 @@ function main(): void { return y.length == x; }); } + +// NOTE (smartin): most specific selection should resolve the '() => void' parameter case, +// and infer the param types in the second case diff --git a/ets2panda/test/runtime/ets/ThrowStatementCloneFunction.ets b/ets2panda/test/runtime/ets/ThrowStatementCloneFunction.ets index a17d795587f54e95ae613de33144a5a1333bd8f6..ff46d44fd9f1eb595b4376221a352a021f397400 100644 --- a/ets2panda/test/runtime/ets/ThrowStatementCloneFunction.ets +++ b/ets2panda/test/runtime/ets/ThrowStatementCloneFunction.ets @@ -19,7 +19,7 @@ let p = new Promise((resolve: (value: string) => void, reject: (error: E }); p.then((value: string): void => { - console.log("Test failed. The promise should not be fulfilled."); + assertTrue(false); }, (err: Error): void => { if (err !== error) { return;