From 02403b93116943a4824035b94dc9647462c16022 Mon Sep 17 00:00:00 2001 From: Martin Sajti Date: Fri, 8 Aug 2025 10:14:28 +0200 Subject: [PATCH] Generic func type instantiation for identifiers Explicitly specifying the type parameters for a function reference should substitute the type argument types into the function type signature. The current implementation will only handle identifiers, however general handling of this instantiation expression will be possibly needed in the future. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICT0ZZ Internal issue: #27911 Test: build, runtime test, cts test Change-Id: I07214dab9bf18253a17dadd257bbee91dfa625e5 Signed-off-by: Martin Sajti --- ets2panda/checker/ets/helpers.cpp | 47 ++++++++++++++++- ets2panda/checker/types/signature.cpp | 7 +++ ets2panda/checker/types/signature.h | 21 +++++++- .../compiler/lowering/ets/lambdaLowering.cpp | 34 +++++++++---- ets2panda/ir/expressions/identifier.cpp | 15 +++++- ets2panda/ir/expressions/identifier.h | 15 +++++- ets2panda/parser/ETSparser.cpp | 9 +++- .../ets/generic_func_instantiation_2.ets | 28 +++++++++++ .../ets/generic_func_instantiation_3_neg.ets | 33 ++++++++++++ .../ets/generic_func_instantiation_4_neg.ets | 23 +++++++++ .../ast/parser/ets/unexpected_token_49.ets | 6 ++- .../ast/parser/ets/unexpected_token_50.ets | 6 ++- .../ets/generic_func_type_instantiation_1.ets | 50 +++++++++++++++++++ .../test-lists/recheck/recheck-ignored.txt | 1 + 14 files changed, 274 insertions(+), 21 deletions(-) create mode 100644 ets2panda/test/ast/compiler/ets/generic_func_instantiation_2.ets create mode 100644 ets2panda/test/ast/compiler/ets/generic_func_instantiation_3_neg.ets create mode 100644 ets2panda/test/ast/compiler/ets/generic_func_instantiation_4_neg.ets create mode 100644 ets2panda/test/runtime/ets/generic_func_type_instantiation_1.ets diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 259e0032e0..e0a3c37ae5 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -291,6 +291,50 @@ void ETSChecker::SaveCapturedVariable(varbinder::Variable *const var, ir::Identi } } +static checker::Type *SubstituteTypeArgsIntoIdentifierType(ETSChecker *checker, const ir::Identifier *const expr, + Type *const identType) +{ + if (LIKELY(expr->TypeParams() == nullptr)) { + return identType; + } + + if (!identType->IsETSFunctionType() || + identType->AsETSFunctionType()->CallSignaturesOfMethodOrArrow().front()->TypeParams().empty()) { + return identType; + } + + // NOTE (smartin): If there more than 1 call signature exist for a function type, then the reference is ambiguous, + // as inference from the context of a function reference is not implemented yet. This is thrown by + // 'TransformTypeForMethodReference'. As it'll only throw it after this check, return with error type here. This + // will need to be changed when the selection of the overloaded target signature is implemented based on the type + // inference from the context. + + if (identType->AsETSFunctionType()->CallSignaturesOfMethodOrArrow().size() != 1) { + checker->LogError(diagnostic::OVERLOADED_METHOD_AS_VALUE, expr->Start()); + return checker->GlobalBuiltinErrorType(); + } + + auto identTypeParams = identType->AsETSFunctionType()->CallSignaturesOfMethodOrArrow().front()->TypeParams(); + + auto newSub = Substitution {}; + for (std::size_t idx = 0; idx < identTypeParams.size(); idx++) { + auto *const typeArgType = expr->TypeParams()->Params()[idx]->GetType(checker); + newSub.emplace(identTypeParams[idx]->AsETSTypeParameter(), typeArgType); + } + + auto *const substitutedType = identType->Substitute(checker->Relation(), &newSub); + auto *const substitutedSig = substitutedType->AsETSFunctionType()->CallSignaturesOfMethodOrArrow().front(); + + // After substituted the concrete type arguments into the signatures, they are not generic anymore, remove the + // type params + auto &callSigTypeParams = substitutedSig->TypeParams(); + std::copy(callSigTypeParams.begin(), callSigTypeParams.end(), + back_inserter(substitutedSig->InstantiatedTypeParams())); + callSigTypeParams.clear(); + + return substitutedType; +} + Type *ETSChecker::ResolveIdentifier(ir::Identifier *ident) { if (ident->Variable() != nullptr) { @@ -338,7 +382,8 @@ Type *ETSChecker::ResolveIdentifier(ir::Identifier *ident) ValidatePropertyAccess(resolved, Context().ContainingClass(), ident->Start()); SaveCapturedVariable(resolved, ident); - return GetTypeOfVariable(resolved); + auto *const varType = GetTypeOfVariable(resolved); + return SubstituteTypeArgsIntoIdentifierType(this, ident, varType); } std::optional CheckLeftRightType(checker::ETSChecker *checker, checker::Type *unboxedL, diff --git a/ets2panda/checker/types/signature.cpp b/ets2panda/checker/types/signature.cpp index 0aaeab3066..0c81ca7bc8 100644 --- a/ets2panda/checker/types/signature.cpp +++ b/ets2panda/checker/types/signature.cpp @@ -43,6 +43,13 @@ Signature *Signature::Substitute(TypeRelation *relation, const Substitution *sub anyChange |= (newTparam != tparam); } } + if (!signatureInfo_->instantiatedTypeParams.empty()) { + for (auto *tparam : signatureInfo_->instantiatedTypeParams) { + auto *newTparam = tparam->Substitute(relation, substitution); + newSigInfo->instantiatedTypeParams.push_back(newTparam); + anyChange |= (newTparam != tparam); + } + } newSigInfo->minArgCount = signatureInfo_->minArgCount; for (auto *param : signatureInfo_->params) { diff --git a/ets2panda/checker/types/signature.h b/ets2panda/checker/types/signature.h index 4051395469..2fcb8ee6ae 100644 --- a/ets2panda/checker/types/signature.h +++ b/ets2panda/checker/types/signature.h @@ -30,16 +30,22 @@ namespace ark::es2panda::checker { class SignatureInfo final { public: - explicit SignatureInfo(ArenaAllocator *allocator) : typeParams {allocator->Adapter()}, params {allocator->Adapter()} + explicit SignatureInfo(ArenaAllocator *allocator) + : typeParams {allocator->Adapter()}, + instantiatedTypeParams {allocator->Adapter()}, + params {allocator->Adapter()} { } SignatureInfo(const SignatureInfo *other, ArenaAllocator *allocator) - : typeParams(allocator->Adapter()), params(allocator->Adapter()) + : typeParams(allocator->Adapter()), instantiatedTypeParams {allocator->Adapter()}, params(allocator->Adapter()) { for (auto *it : other->typeParams) { typeParams.push_back(it); } + for (auto *it : other->instantiatedTypeParams) { + instantiatedTypeParams.push_back(it); + } for (auto *it : other->params) { params.push_back(it->Copy(allocator, it->Declaration())); params.back()->SetTsType(it->TsType()); @@ -61,6 +67,7 @@ public: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) ArenaVector typeParams; + ArenaVector instantiatedTypeParams; uint32_t minArgCount {}; varbinder::LocalVariable *restVar {}; ArenaVector params; @@ -139,6 +146,16 @@ public: return signatureInfo_->typeParams; } + [[nodiscard]] const ArenaVector &InstantiatedTypeParams() const noexcept + { + return signatureInfo_->instantiatedTypeParams; + } + + [[nodiscard]] ArenaVector &InstantiatedTypeParams() noexcept + { + return signatureInfo_->instantiatedTypeParams; + } + [[nodiscard]] const ArenaVector &Params() const noexcept { return signatureInfo_->params; diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index 8399b8cc35..b4fc543b98 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -824,6 +824,23 @@ static ArenaVector CreateCallArgumentsForLambdaClassInvokeN(pu return callArguments; } +static void SetTypeParamsForInvokeSignature(public_lib::Context *ctx, LambdaClassInvokeInfo const *lciInfo, + ir::CallExpression *call) +{ + auto *allocator = ctx->allocator; + + auto origCallTypeParams = lciInfo->lambdaSignature->InstantiatedTypeParams(); + auto typeArgs = ArenaVector(allocator->Adapter()); + for (auto *tp : origCallTypeParams) { + typeArgs.push_back(allocator->New( + tp->Substitute(ctx->GetChecker()->Relation(), lciInfo->substitution), allocator)); + } + auto *typeArg = + util::NodeAllocator::ForceSetParent(allocator, std::move(typeArgs)); + call->SetTypeParams(typeArg); + typeArg->SetParent(call); +} + static ir::CallExpression *CreateCallForLambdaClassInvoke(public_lib::Context *ctx, LambdaInfo const *info, LambdaClassInvokeInfo const *lciInfo, bool wrapToObject, bool isInvokeN) @@ -833,12 +850,10 @@ static ir::CallExpression *CreateCallForLambdaClassInvoke(public_lib::Context *c auto callArguments = isInvokeN ? CreateCallArgumentsForLambdaClassInvokeN(ctx, info, lciInfo) : CreateCallArgumentsForLambdaClassInvoke(ctx, info, lciInfo, wrapToObject); - ir::Expression *calleeReceiver; - if (info->callReceiver != nullptr) { - calleeReceiver = parser->CreateFormattedExpression("this.@@I1", "$this"); - } else { - calleeReceiver = lciInfo->callee->Parent()->AsClassDefinition()->Ident()->Clone(allocator, nullptr); - } + ir::Expression *const calleeReceiver = + info->callReceiver != nullptr + ? parser->CreateFormattedExpression("this.@@I1", "$this") + : lciInfo->callee->Parent()->AsClassDefinition()->Ident()->Clone(allocator, nullptr); auto *calleeMemberExpr = util::NodeAllocator::ForceSetParent( allocator, calleeReceiver, lciInfo->callee->Key()->Clone(allocator, nullptr)->AsExpression(), @@ -847,10 +862,7 @@ static ir::CallExpression *CreateCallForLambdaClassInvoke(public_lib::Context *c auto *call = util::NodeAllocator::ForceSetParent(allocator, calleeMemberExpr, std::move(callArguments), nullptr, false); - // NOTE (smartin): the condition would be better to check the size of the signature's type parameters. But currently - // generic lambdas don't allocate type parameters for they global invoke function, so fix this when the generation - // will be corrected - if (lciInfo->callee->Function()->TypeParams() != nullptr) { + if (!lciInfo->lambdaSignature->TypeParams().empty()) { auto origCallTypeParams = lciInfo->lambdaSignature->TypeParams(); auto typeArgs = ArenaVector(allocator->Adapter()); for (auto *tp : origCallTypeParams) { @@ -861,6 +873,8 @@ static ir::CallExpression *CreateCallForLambdaClassInvoke(public_lib::Context *c util::NodeAllocator::ForceSetParent(allocator, std::move(typeArgs)); call->SetTypeParams(typeArg); typeArg->SetParent(call); + } else if (!lciInfo->lambdaSignature->InstantiatedTypeParams().empty()) { + SetTypeParamsForInvokeSignature(ctx, lciInfo, call); } if (lciInfo->classDefinition->TypeParams() != nullptr) { diff --git a/ets2panda/ir/expressions/identifier.cpp b/ets2panda/ir/expressions/identifier.cpp index 050fd78b37..b6bc8ce009 100644 --- a/ets2panda/ir/expressions/identifier.cpp +++ b/ets2panda/ir/expressions/identifier.cpp @@ -26,6 +26,15 @@ Identifier::Identifier([[maybe_unused]] Tag const tag, Identifier const &other, { name_ = other.name_; flags_ = other.flags_; + + if (other.TypeParams() != nullptr) { + ArenaVector clonedTypeParams(allocator->Adapter()); + for (auto *typeParam : other.TypeParams()->Params()) { + clonedTypeParams.emplace_back(typeParam->Clone(allocator, nullptr)); + } + SetTypeParams(allocator->New(std::move(clonedTypeParams))); + } + InitHistory(); } @@ -120,7 +129,8 @@ void Identifier::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", IsPrivateIdent() ? "PrivateIdentifier" : "Identifier"}, {"name", Name()}, {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}, - {"optional", AstDumper::Optional(IsOptional())}}); + {"optional", AstDumper::Optional(IsOptional())}, + {"typeParams", AstDumper::Optional(TypeParams())}}); } void Identifier::Dump(ir::SrcDumper *dumper) const @@ -143,6 +153,9 @@ void Identifier::Dump(ir::SrcDumper *dumper) const if (IsOptional()) { dumper->Add("?"); } + if (TypeParams() != nullptr) { + TypeParams()->Dump(dumper); + } dumper->PushTask([dumper, name = std::string(name_)] { dumper->DumpNode(name); }); } diff --git a/ets2panda/ir/expressions/identifier.h b/ets2panda/ir/expressions/identifier.h index fd0db4eb01..7dc0931b61 100644 --- a/ets2panda/ir/expressions/identifier.h +++ b/ets2panda/ir/expressions/identifier.h @@ -62,8 +62,8 @@ public: public: explicit Identifier(ArenaAllocator *const allocator); - explicit Identifier(util::StringView const name, ArenaAllocator *const allocator); - explicit Identifier(util::StringView const name, TypeNode *const typeAnnotation, ArenaAllocator *const allocator); + explicit Identifier(util::StringView name, ArenaAllocator *allocator); + explicit Identifier(util::StringView name, TypeNode *typeAnnotation, ArenaAllocator *allocator); explicit Identifier(Tag tag, Identifier const &other, ArenaAllocator *allocator); [[nodiscard]] const util::StringView &Name() const noexcept @@ -184,6 +184,16 @@ public: [[nodiscard]] Identifier *Clone(ArenaAllocator *allocator, AstNode *parent) override; [[nodiscard]] Identifier *CloneReference(ArenaAllocator *allocator, AstNode *parent); + TSTypeParameterInstantiation *TypeParams() const + { + return typeParams_; + } + + void SetTypeParams(TSTypeParameterInstantiation *newTypeParams) + { + typeParams_ = newTypeParams; + } + [[nodiscard]] ValidationInfo ValidateExpression(); void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -245,6 +255,7 @@ private: util::StringView name_; IdentifierFlags flags_ {IdentifierFlags::NONE}; + TSTypeParameterInstantiation *typeParams_ = nullptr; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index e4b25915ea..5d4b6fe3e3 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -2037,6 +2037,13 @@ bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, i return true; } + // NOTE (smartin): Now it's possible that an identifier of a call expression will get type parameters. When a type + // parameter instantiation node is added, review this part of the code. + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS && primaryExpr->IsIdentifier()) { + // Set identifier type params only if it's not a call expr + primaryExpr->AsIdentifier()->SetTypeParams(typeParams); + } + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { Lexer()->NextToken(); return true; @@ -2047,7 +2054,7 @@ bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, i } // unexpected_token_49,ets, 50, 51 - if (!Lexer()->GetToken().NewLine() && Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { LogExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); } diff --git a/ets2panda/test/ast/compiler/ets/generic_func_instantiation_2.ets b/ets2panda/test/ast/compiler/ets/generic_func_instantiation_2.ets new file mode 100644 index 0000000000..a67dc052a4 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/generic_func_instantiation_2.ets @@ -0,0 +1,28 @@ +/* + * 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(a0: T): T { return a0; } + +function main() { + let fooInt1: (a0: Int) => Int = foo + let fooInt2 = foo + let fooInt3: (a0: Int) => Int = fooInt2 + + let fooInt4 = foo + let fooInt5: (a0: Int) => Int = fooInt4 + + let fooInt6 = foo + let fooInt7: (a0: Int) => Int = fooInt6 +} diff --git a/ets2panda/test/ast/compiler/ets/generic_func_instantiation_3_neg.ets b/ets2panda/test/ast/compiler/ets/generic_func_instantiation_3_neg.ets new file mode 100644 index 0000000000..29702dafe1 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/generic_func_instantiation_3_neg.ets @@ -0,0 +1,33 @@ +/* + * 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(a0: T): T { return a0; } + +function main() { + let fooInt1: (a0: Int) => Int = /* @@ label1 */foo + let fooInt2 = foo + let fooInt3: (a0: Int) => Int = /* @@ label2 */fooInt2 + + let fooInt4 = foo + let fooInt5: (a0: Int) => Int = /* @@ label3 */fooInt4 + + let fooInt6 = foo + let fooInt7: (a0: Int) => Int = /* @@ label4 */fooInt6 +} + +/* @@@ label1 Error TypeError: Type '(a0: Double) => Double' cannot be assigned to type '(a0: Int) => Int' */ +/* @@@ label2 Error TypeError: Type '(a0: Double) => Double' cannot be assigned to type '(a0: Int) => Int' */ +/* @@@ label3 Error TypeError: Type '(a0: Double) => Double' cannot be assigned to type '(a0: Int) => Int' */ +/* @@@ label4 Error TypeError: Type '(a0: Double) => Double' cannot be assigned to type '(a0: Int) => Int' */ diff --git a/ets2panda/test/ast/compiler/ets/generic_func_instantiation_4_neg.ets b/ets2panda/test/ast/compiler/ets/generic_func_instantiation_4_neg.ets new file mode 100644 index 0000000000..ad70cbbe97 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/generic_func_instantiation_4_neg.ets @@ -0,0 +1,23 @@ +/* + * 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(a0: T): T { return a0; } +function foo(a0: T, a1: T): T { return a0; } + +function main() { + let fooInt1 = /* @@ label1 */foo +} + +/* @@@ label1 Error TypeError: Overloaded method is used as value */ diff --git a/ets2panda/test/ast/parser/ets/unexpected_token_49.ets b/ets2panda/test/ast/parser/ets/unexpected_token_49.ets index a08589fe31..5b208f83b3 100644 --- a/ets2panda/test/ast/parser/ets/unexpected_token_49.ets +++ b/ets2panda/test/ast/parser/ets/unexpected_token_49.ets @@ -18,7 +18,9 @@ function identity(arg: Type): Type { } let output = identity/* @@ label */"hehe" -/* @@? 19:14 Error TypeError: Expected 1 arguments, got 0. */ +/* @@? 19:14 Error TypeError: Expected 0 type arguments, got 1 . */ +/* @@? 19:14 Error TypeError: No matching call signature */ +/* @@? 19:14 Error TypeError: Expected 0 type arguments, got 1 . */ /* @@? 19:14 Error TypeError: No matching call signature */ /* @@? 19:44 Error SyntaxError: Unexpected token, expected '('. */ -/* @@? 25:1 Error SyntaxError: Expected ')', got 'end of stream'. */ +/* @@? 27:1 Error SyntaxError: Expected ')', got 'end of stream'. */ diff --git a/ets2panda/test/ast/parser/ets/unexpected_token_50.ets b/ets2panda/test/ast/parser/ets/unexpected_token_50.ets index d183229f0b..ca9e13535e 100644 --- a/ets2panda/test/ast/parser/ets/unexpected_token_50.ets +++ b/ets2panda/test/ast/parser/ets/unexpected_token_50.ets @@ -19,7 +19,9 @@ function identity(arg: Type): Type { let output = identity let output1 = identity/* @@ label */"hehe" -/* @@? 20:15 Error TypeError: Expected 1 arguments, got 0. */ +/* @@? 20:15 Error TypeError: Expected 0 type arguments, got 1 . */ +/* @@? 20:15 Error TypeError: No matching call signature */ +/* @@? 20:15 Error TypeError: Expected 0 type arguments, got 1 . */ /* @@? 20:15 Error TypeError: No matching call signature */ /* @@? 20:45 Error SyntaxError: Unexpected token, expected '('. */ -/* @@? 26:1 Error SyntaxError: Expected ')', got 'end of stream'. */ +/* @@? 28:1 Error SyntaxError: Expected ')', got 'end of stream'. */ diff --git a/ets2panda/test/runtime/ets/generic_func_type_instantiation_1.ets b/ets2panda/test/runtime/ets/generic_func_type_instantiation_1.ets new file mode 100644 index 0000000000..40eb6f815e --- /dev/null +++ b/ets2panda/test/runtime/ets/generic_func_type_instantiation_1.ets @@ -0,0 +1,50 @@ +/* + * 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. + */ + +class Base {} +class Derived extends Base { } + +function fooBB(p: T): T { return p }; +function fooBD(p: T): G { return p as G }; + +function main(): void { + let foobb = fooBB; + let foob_test1 = foobb(new Base()) + let foob_test2 = foobb(new Derived()) + + let foobd = fooBD + + foobb = foobd + + try { + foobb(new Base()) + arktest.assertTrue(false); + } catch (e) { + if(!(e instanceof ClassCastError) + || (e as ClassCastError).message != "generic_func_type_instantiation_1.Base cannot be cast to generic_func_type_instantiation_1.Derived") { + arktest.assertTrue(false); + } + } + + try { + foobd(new Base()) + arktest.assertTrue(false); + } catch (e) { + if(!(e instanceof ClassCastError) + || (e as ClassCastError).message != "generic_func_type_instantiation_1.Base cannot be cast to generic_func_type_instantiation_1.Derived") { + arktest.assertTrue(false); + } + } +} diff --git a/ets2panda/test/test-lists/recheck/recheck-ignored.txt b/ets2panda/test/test-lists/recheck/recheck-ignored.txt index 534532a35b..6c7ef51297 100644 --- a/ets2panda/test/test-lists/recheck/recheck-ignored.txt +++ b/ets2panda/test/test-lists/recheck/recheck-ignored.txt @@ -88,6 +88,7 @@ runtime/ets/lambda_with_receiver/lambda_with_receiver_trailing_name_duplicated.e runtime/ets/generic_lambda_6.ets runtime/ets/implement_interface.ets runtime/ets/typealias_function_name_conflict.ets +runtime/ets/generic_func_type_instantiation_1.ets #Test that failed before CheckerPhase (on ConstantExpressionLowering) ast/parser/ets/InvalidLexer.ets #Test that failed with abort before plugins-after-check phase -- Gitee