diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 423de0971dfb0569f476fc09b2035ada3e78b540..6c6fcb6a2aaed28ff08b1637cd73a4c7008303cb 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -415,9 +415,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() @@ -474,7 +473,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 IsValidRestArgument(ir::Expression *argument, Signature *substitutedSig, TypeRelationFlag flags, std::size_t index); bool SetPreferredTypeForArrayArgument(ir::ArrayExpression *arrayExpr, Signature *substitutedSig); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index f42c123c760130414ae1a5beef82b2a2157f2fe3..e6727e911fe00a0887ed399e0bc2a0e07cdc2ddf 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -418,21 +418,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->Params()[index]->Declaration()->Node()->AsExpression(), lambda)) { - return true; - } - } - - return false; -} - static bool IsInvalidArgumentAsIdentifier(varbinder::Scope *scope, const ir::Identifier *identifier) { auto result = scope->Find(identifier->Name()); @@ -467,8 +452,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; } } @@ -549,19 +534,17 @@ 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 = + auto *const paramType = GetNonNullishType(substitutedSig->Params()[index]->TsType())->MaybeBaseTypeOfGradualType(); if (argument->IsObjectExpression()) { ES2PANDA_ASSERT(paramType != nullptr); - if (!paramType->IsETSObjectType()) { - return false; - } - if (paramType->AsETSObjectType()->IsBoxedPrimitive()) { + if (!paramType->IsETSObjectType() || paramType->AsETSObjectType()->IsBoxedPrimitive()) { return false; } + argument->SetPreferredType(paramType); } @@ -578,11 +561,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(); - ERROR_SANITY_CHECK(this, targetParm->IsETSParameterExpression(), return false); - if (CheckLambdaAssignable(targetParm->AsETSParameterExpression(), lambda)) { + if (DoesLambdaMatchRequiredArity(paramType, arrowFunExpr->Function())) { continue; } return false; @@ -617,7 +607,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, @@ -2867,7 +2857,7 @@ bool ETSChecker::ValidateOrderSignatureRequiredParams(Signature *substitutedSig, 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 (!CheckLambdaAssignable(targetParm->AsETSParameterExpression(), lambda)) { + if (!DoesLambdaMatchRequiredArity(targetParm->Check(this), lambda)) { return false; } } diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 259e0032e0c495742122f420e60cccde06df7411..058546598cedfb0fda42e0dddbf7530932904d88 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -2656,26 +2656,6 @@ std::vector ETSChecker::FindTypeInferenceArguments(const ArenaVectorAsETSUnionType()->Types()) { - if (type->IsETSFunctionType()) { - assignable |= lambda->Params().size() <= type->AsETSFunctionType()->Params().size(); - continue; - } - - if (type->IsETSTypeReference()) { - auto aliasType = util::Helpers::DerefETSTypeReference(type); - assignable |= aliasType->IsETSFunctionType() && - lambda->Params().size() <= aliasType->AsETSFunctionType()->Params().size(); - } - } - - return assignable; -} - 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 20ea468dcedfeb49f2913116aa694bc23e54b44a..f6e281d038487b225d656c2f304a4ce5131233fc 100644 --- a/ets2panda/checker/ets/typeCheckingHelpers.cpp +++ b/ets2panda/checker/ets/typeCheckingHelpers.cpp @@ -1452,36 +1452,24 @@ void ETSChecker::CheckUnboxedSourceTypeWithWideningAssignable(TypeRelation *rela } // #22952: optional arrow leftovers -bool ETSChecker::CheckLambdaAssignable(ir::Expression *param, ir::ScriptFunction *lambda) +bool ETSChecker::DoesLambdaMatchRequiredArity(const Type *const targetType, + const ir::ScriptFunction *const callingLambda) { - ES2PANDA_ASSERT(param->IsETSParameterExpression()); - ir::AstNode *typeAnn = param->AsETSParameterExpression()->Ident()->TypeAnnotation(); - if (typeAnn == nullptr) { - return false; - } - if (typeAnn->IsETSTypeReference() && !typeAnn->AsETSTypeReference()->TsType()->IsETSArrayType()) { - typeAnn = util::Helpers::DerefETSTypeReference(typeAnn); - } - if (typeAnn->IsTSTypeParameter()) { - return true; + // 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 (!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()) { - return CheckLambdaAssignableUnion(typeAnn, lambda); - } - Type *paramType = param->AsETSParameterExpression()->Ident()->TsType(); - if (Relation()->IsSupertypeOf(paramType, GlobalBuiltinFunctionType())) { - lambda->Parent()->Check(this); - return true; - } - return false; + 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); + }); } - ir::ETSFunctionType *calleeType = typeAnn->AsETSFunctionType(); - return lambda->Params().size() <= calleeType->Params().size(); + return targetType->IsETSObjectType() && Relation()->IsSupertypeOf(targetType, GlobalBuiltinFunctionType()); } bool ETSChecker::CheckLambdaInfer(ir::AstNode *typeAnnotation, ir::ArrowFunctionExpression *const arrowFuncExpr, @@ -1507,6 +1495,18 @@ bool ETSChecker::CheckLambdaInfer(ir::AstNode *typeAnnotation, ir::ArrowFunction return true; } +// Extracted because of function line limit on CI +bool CheckIfLambdaIsInvokable(ETSChecker *checker, ir::ArrowFunctionExpression *const arrowFuncExpr, + Type *const parameterType, TypeRelationFlag functionFlags) +{ + Type *const argumentType = arrowFuncExpr->Check(checker); + functionFlags |= TypeRelationFlag::NO_THROW; + + InvocationContext invocationCtx(checker->Relation(), arrowFuncExpr, argumentType, parameterType, + arrowFuncExpr->Start(), std::nullopt, functionFlags); + return invocationCtx.IsInvocable(); +} + bool ETSChecker::CheckLambdaTypeAnnotation(ir::ETSParameterExpression *param, ir::ArrowFunctionExpression *const arrowFuncExpr, Type *const parameterType, TypeRelationFlag flags) @@ -1515,14 +1515,6 @@ bool ETSChecker::CheckLambdaTypeAnnotation(ir::ETSParameterExpression *param, if (typeAnnotation->IsETSTypeReference()) { typeAnnotation = util::Helpers::DerefETSTypeReference(typeAnnotation); } - auto checkInvocable = [&arrowFuncExpr, ¶meterType, this](TypeRelationFlag functionFlags) { - Type *const argumentType = arrowFuncExpr->Check(this); - functionFlags |= TypeRelationFlag::NO_THROW; - - checker::InvocationContext invocationCtx(Relation(), arrowFuncExpr, argumentType, parameterType, - arrowFuncExpr->Start(), std::nullopt, functionFlags); - return invocationCtx.IsInvocable(); - }; // process `single` type as usual. if (!typeAnnotation->IsETSUnionType()) { @@ -1534,7 +1526,8 @@ bool ETSChecker::CheckLambdaTypeAnnotation(ir::ETSParameterExpression *param, return true; } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - return CheckLambdaInfer(typeAnnotation, arrowFuncExpr, nonNullishParam) && checkInvocable(flags); + return CheckLambdaInfer(typeAnnotation, arrowFuncExpr, nonNullishParam) && + CheckIfLambdaIsInvokable(this, arrowFuncExpr, parameterType, flags); } // Preserve actual lambda types @@ -1557,7 +1550,8 @@ bool ETSChecker::CheckLambdaTypeAnnotation(ir::ETSParameterExpression *param, auto *typeNode = typeAnnsOfUnion[ix]; auto *paramNode = typeParamOfUnion[ix]; // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - if (CheckLambdaInfer(typeNode, arrowFuncExpr, paramNode) && checkInvocable(flags)) { + if (CheckLambdaInfer(typeNode, arrowFuncExpr, paramNode) && + CheckIfLambdaIsInvokable(this, arrowFuncExpr, parameterType, flags)) { return true; } diff --git a/ets2panda/checker/types/ets/etsFunctionType.cpp b/ets2panda/checker/types/ets/etsFunctionType.cpp index 669ab5d1ed0a67aaf076429635f2f8b91605e10d..9a9bbff5cf9330f82b73b8b26e6524037be54041 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -228,11 +228,14 @@ 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; } 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/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 4188d3c5ce5aa0c2c94b98a55477fc66fd08dcd7..df96c84c9fc0b08bfb5111ac9c9c15129e052c86 100644 --- a/ets2panda/test/parser/ets/lambda-type-inference-overloaded-expected.txt +++ b/ets2panda/test/parser/ets/lambda-type-inference-overloaded-expected.txt @@ -1499,7 +1499,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..f88ed3472dcb4914fef9e244703fdf7badb27eb3 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."); + arktest.assertTrue(false); }, (err: Error): void => { if (err !== error) { return;