From 8aef5cb8bcce50475b0315f7388ed811decf157b Mon Sep 17 00:00:00 2001 From: Anna Antipina Date: Mon, 12 Feb 2024 21:18:13 +0300 Subject: [PATCH] Title: Fix overriding of the functions with non-identical signatures Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I91MGU Description: Softened the rules for overloading functions. Parameters are overridden with contravariance, result(return) type with covariance Test: ${ARK_SOURCE_DIR}/tests/tests-u-runner/runner.sh ${ARK_SOURCE_DIR} --ets-runtime --build-dir="${ARK_BUILD_DIR}" --heap-verifier="fail_on_verification:pre:into:before_g1_concurrent:post" --timeout=30 --force-generate --test-file Override-4.ets Signed-off-by: Anna Antipina --- ets2panda/checker/ETSAnalyzer.cpp | 2 +- ets2panda/checker/ETSchecker.h | 4 +- ets2panda/checker/ets/function.cpp | 46 +++--- ets2panda/checker/ets/helpers.cpp | 4 +- .../checker/types/ets/etsFunctionType.cpp | 2 +- ets2panda/checker/types/signature.cpp | 131 ++++++++++-------- ets2panda/checker/types/signature.h | 6 +- ets2panda/checker/types/ts/objectType.cpp | 4 +- ets2panda/checker/types/typeRelation.cpp | 4 +- ets2panda/checker/types/typeRelation.h | 8 +- ets2panda/compiler/core/ETSemitter.cpp | 4 +- ets2panda/test/runtime/ets/Override-4.ets | 39 ++++++ 12 files changed, 158 insertions(+), 96 deletions(-) create mode 100644 ets2panda/test/runtime/ets/Override-4.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 7917598b0e..1f6e615b3e 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -139,7 +139,7 @@ static void CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecke const auto *const funcType = variable->TsType()->AsETSFunctionType(); for (auto *funcSignature : funcType->CallSignatures()) { signature->SetReturnType(funcSignature->ReturnType()); - if (!checker->Relation()->IsIdenticalTo(signature, funcSignature)) { + if (!checker->Relation()->IsCompatibleTo(signature, funcSignature)) { continue; } diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 8c0b13990c..3d6d10032e 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -349,8 +349,8 @@ public: void ThrowOverrideError(Signature *signature, Signature *overriddenSignature, const OverrideErrorCode &errorCode); void CheckOverride(Signature *signature); bool CheckOverride(Signature *signature, ETSObjectType *site); - std::tuple CheckOverride(Signature *signature, Signature *other); - bool IsMethodOverridesOther(Signature *target, Signature *source); + OverrideErrorCode CheckOverride(Signature *signature, Signature *other); + bool IsMethodOverridesOther(Signature *base, Signature *derived); bool IsOverridableIn(Signature *signature); [[nodiscard]] bool AreOverrideEquivalent(Signature *s1, Signature *s2); [[nodiscard]] bool IsReturnTypeSubstitutable(Signature *s1, Signature *s2); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 34473739d3..b154503c4c 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -992,7 +992,7 @@ Signature *ETSChecker::CheckEveryAbstractSignatureIsOverridden(ETSFunctionType * bool isOverridden = false; for (auto sourceSig : source->CallSignatures()) { - Relation()->IsIdenticalTo(*targetSig, sourceSig); + Relation()->IsCompatibleTo(*targetSig, sourceSig); if (Relation()->IsTrue() && (*targetSig)->Function()->Id()->Name() == sourceSig->Function()->Id()->Name()) { target->CallSignatures().erase(targetSig); isOverridden = true; @@ -1023,31 +1023,32 @@ bool ETSChecker::IsOverridableIn(Signature *signature) return signature->HasSignatureFlag(SignatureFlags::PROTECTED); } -bool ETSChecker::IsMethodOverridesOther(Signature *target, Signature *source) +bool ETSChecker::IsMethodOverridesOther(Signature *base, Signature *derived) { - if (source->Function()->IsConstructor()) { + if (derived->Function()->IsConstructor()) { return false; } - if (target == source) { + if (base == derived) { return true; } - if (source->HasSignatureFlag(SignatureFlags::STATIC) != target->HasSignatureFlag(SignatureFlags::STATIC)) { + if (derived->HasSignatureFlag(SignatureFlags::STATIC) != base->HasSignatureFlag(SignatureFlags::STATIC)) { return false; } - if (IsOverridableIn(target)) { - SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK); - Relation()->IsIdenticalTo(target, source); + if (IsOverridableIn(base)) { + SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK | + TypeRelationFlag::OVERRIDING_CONTEXT); + Relation()->IsCompatibleTo(base, derived); if (Relation()->IsTrue()) { - CheckThrowMarkers(source, target); + CheckThrowMarkers(derived, base); - if (source->HasSignatureFlag(SignatureFlags::STATIC)) { + if (derived->HasSignatureFlag(SignatureFlags::STATIC)) { return false; } - source->Function()->SetOverride(); + derived->Function()->SetOverride(); return true; } } @@ -1070,26 +1071,26 @@ void ETSChecker::CheckThrowMarkers(Signature *source, Signature *target) } } -std::tuple ETSChecker::CheckOverride(Signature *signature, Signature *other) +OverrideErrorCode ETSChecker::CheckOverride(Signature *signature, Signature *other) { if (other->HasSignatureFlag(SignatureFlags::STATIC)) { ASSERT(signature->HasSignatureFlag(SignatureFlags::STATIC)); - return {true, OverrideErrorCode::NO_ERROR}; + return OverrideErrorCode::NO_ERROR; } if (other->IsFinal()) { - return {false, OverrideErrorCode::OVERRIDDEN_FINAL}; + return OverrideErrorCode::OVERRIDDEN_FINAL; } if (!IsReturnTypeSubstitutable(signature, other)) { - return {false, OverrideErrorCode::INCOMPATIBLE_RETURN}; + return OverrideErrorCode::INCOMPATIBLE_RETURN; } if (signature->ProtectionFlag() > other->ProtectionFlag()) { - return {false, OverrideErrorCode::OVERRIDDEN_WEAKER}; + return OverrideErrorCode::OVERRIDDEN_WEAKER; } - return {true, OverrideErrorCode::NO_ERROR}; + return OverrideErrorCode::NO_ERROR; } Signature *ETSChecker::AdjustForTypeParameters(Signature *source, Signature *target) @@ -1149,6 +1150,7 @@ bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) return isOverridingAnySignature; } + bool suitableSignatureFound = false; for (auto *it : target->TsType()->AsETSFunctionType()->CallSignatures()) { auto *itSubst = AdjustForTypeParameters(signature, it); @@ -1169,9 +1171,10 @@ bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) continue; } - auto [success, errorCode] = CheckOverride(signature, itSubst); - - if (!success) { + auto errorCode = CheckOverride(signature, itSubst); + if (errorCode == OverrideErrorCode::NO_ERROR) { + suitableSignatureFound = true; + } else if (!suitableSignatureFound) { ThrowOverrideError(signature, it, errorCode); } @@ -2749,7 +2752,8 @@ bool ETSChecker::AreOverrideEquivalent(Signature *const s1, Signature *const s2) // types are also the same (after the formal parameter types of N are adapted to the type parameters of M). // Signatures s1 and s2 are override-equivalent only if s1 and s2 are the same. - return s1->Function()->Id()->Name() == s2->Function()->Id()->Name() && Relation()->IsIdenticalTo(s1, s2); + SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::OVERRIDING_CONTEXT); + return s1->Function()->Id()->Name() == s2->Function()->Id()->Name() && Relation()->IsCompatibleTo(s1, s2); } bool ETSChecker::IsReturnTypeSubstitutable(Signature *const s1, Signature *const s2) diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index a4e7677631..dc6f5822db 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1528,7 +1528,7 @@ ETSFunctionType *ETSChecker::FindFunctionInVectorGivenByName(util::StringView na bool ETSChecker::IsFunctionContainsSignature(ETSFunctionType *funcType, Signature *signature) { for (auto *it : funcType->CallSignatures()) { - Relation()->IsIdenticalTo(it, signature); + Relation()->IsCompatibleTo(it, signature); if (Relation()->IsTrue()) { return true; } @@ -1541,7 +1541,7 @@ void ETSChecker::CheckFunctionContainsClashingSignature(const ETSFunctionType *f { for (auto *it : funcType->CallSignatures()) { SavedTypeRelationFlagsContext strfCtx(Relation(), TypeRelationFlag::NONE); - Relation()->IsIdenticalTo(it, signature); + Relation()->IsCompatibleTo(it, signature); if (Relation()->IsTrue() && it->Function()->Id()->Name() == signature->Function()->Id()->Name()) { std::stringstream ss; it->ToString(ss, nullptr, true); diff --git a/ets2panda/checker/types/ets/etsFunctionType.cpp b/ets2panda/checker/types/ets/etsFunctionType.cpp index 72dbc3492a..2727488971 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -49,7 +49,7 @@ void ETSFunctionType::Identical(TypeRelation *relation, Type *other) return; } - callSignatures_[0]->Identical(relation, other->AsETSFunctionType()->CallSignatures()[0]); + callSignatures_[0]->Compatible(relation, other->AsETSFunctionType()->CallSignatures()[0]); } bool ETSFunctionType::AssignmentSource(TypeRelation *relation, Type *target) diff --git a/ets2panda/checker/types/signature.cpp b/ets2panda/checker/types/signature.cpp index 2546195761..02447428bf 100644 --- a/ets2panda/checker/types/signature.cpp +++ b/ets2panda/checker/types/signature.cpp @@ -198,13 +198,30 @@ std::size_t GetToCheckParamCount(Signature *signature, bool isEts) } } // namespace -bool Signature::IdenticalParameter(TypeRelation *relation, Type *type1, Type *type2) +bool Signature::CheckParameter(TypeRelation *relation, Type *type1, Type *type2) { relation->IsIdenticalTo(type1, type2); + if (relation->IsOverridingCheck() && !relation->IsTrue()) { + relation->IsSupertypeOf(type1, type2); + } + return relation->IsTrue(); +} + +bool Signature::CheckReturnType(TypeRelation *relation, Type *type1, Type *type2) +{ + if (relation->NoReturnTypeCheck()) { + return relation->Result(true); + } + if (relation->IsOverridingCheck()) { + relation->IsSupertypeOf(type2, type1); + } else { + relation->IsIdenticalTo(type1, type2); + } + return relation->IsTrue(); } -void Signature::Identical(TypeRelation *relation, Signature *other) +void Signature::Compatible(TypeRelation *relation, Signature *other) { bool isEts = relation->GetChecker()->IsETSChecker(); auto const thisToCheckParametersNumber = GetToCheckParamCount(this, isEts); @@ -219,70 +236,64 @@ void Signature::Identical(TypeRelation *relation, Signature *other) } } - if (relation->NoReturnTypeCheck()) { - relation->Result(true); - } else { - relation->IsIdenticalTo(this->ReturnType(), other->ReturnType()); + if (!CheckReturnType(relation, this->ReturnType(), other->ReturnType())) { + return; } - if (relation->IsTrue()) { - /* In ETS, the functions "foo(a: int)" and "foo(a: int, b: int = 1)" should be considered as having an - equivalent signature. Hence, we only need to check if the mandatory parameters of the signature with - more mandatory parameters can match the parameters of the other signature (including the optional - parameter or rest parameters) here. - - XXX_to_check_parameters_number is calculated beforehand by counting mandatory parameters. - Signature::params() stores all parameters (mandatory and optional), excluding the rest parameter. - Signature::restVar() stores the rest parameters of the function. - - For example: - foo(a: int): params().size: 1, to_check_param_number: 1, restVar: nullptr - foo(a: int, b: int = 0): params().size: 2, to_check_param_number: 1, restVar: nullptr - foo(a: int, ...b: int[]): params().size: 1, to_check_param_number: 1, restVar: ...b: int[] - - Note that optional parameters always come after mandatory parameters, and signatures containing both - optional and rest parameters are not allowed. - - "to_check_parameters_number" is the number of parameters that need to be checked to ensure identical. - "parameters_number" is the number of parameters that can be checked in Signature::params(). - */ - auto const toCheckParametersNumber = std::max(thisToCheckParametersNumber, otherToCheckParametersNumber); - auto const parametersNumber = - std::min({this->Params().size(), other->Params().size(), toCheckParametersNumber}); - - std::size_t i = 0U; - for (; i < parametersNumber; ++i) { - if (!IdenticalParameter(relation, this->Params()[i]->TsType(), other->Params()[i]->TsType())) { - return; - } - } + /* In ETS, the functions "foo(a: int)" and "foo(a: int, b: int = 1)" should be considered as having an + equivalent signature. Hence, we only need to check if the mandatory parameters of the signature with + more mandatory parameters can match the parameters of the other signature (including the optional + parameter or rest parameters) here. - /* "i" could be one of the following three cases: - 1. == to_check_parameters_number, we have finished the checking and can directly return. - 2. == other->Params().size(), must be < this_to_check_parameters_number in this case since - xxx->Params().size() always >= xxx_to_check_parameters_number. We need to check the remaining - mandatory parameters of "this" against ths RestVar of "other". - 3. == this->Params().size(), must be < other_to_check_parameters_number as described in 2, and - we need to check the remaining mandatory parameters of "other" against the RestVar of "this". - */ - if (i == toCheckParametersNumber) { + XXXToCheckParametersNumber is calculated beforehand by counting mandatory parameters. + Signature::params() stores all parameters (mandatory and optional), excluding the rest parameter. + Signature::restVar() stores the rest parameters of the function. + + For example: + foo(a: int): params().size: 1, ToCheckParametersNumber: 1, restVar: nullptr + foo(a: int, b: int = 0): params().size: 2, ToCheckParametersNumber: 1, restVar: nullptr + foo(a: int, ...b: int[]): params().size: 1, ToCheckParametersNumber: 1, restVar: ...b: int[] + + Note that optional parameters always come after mandatory parameters, and signatures containing both + optional and rest parameters are not allowed. + + "ToCheckParametersNumber" is the number of parameters that need to be checked to ensure identical. + "parametersNumber" is the number of parameters that can be checked in Signature::params(). + */ + auto const toCheckParametersNumber = std::max(thisToCheckParametersNumber, otherToCheckParametersNumber); + auto const parametersNumber = std::min({this->Params().size(), other->Params().size(), toCheckParametersNumber}); + + std::size_t i = 0U; + for (; i < parametersNumber; ++i) { + if (!CheckParameter(relation, this->Params()[i]->TsType(), other->Params()[i]->TsType())) { return; } - bool isOtherMandatoryParamsMatched = i < thisToCheckParametersNumber; - ArenaVector const ¶meters = - isOtherMandatoryParamsMatched ? this->Params() : other->Params(); - varbinder::LocalVariable const *restParameter = - isOtherMandatoryParamsMatched ? other->RestVar() : this->RestVar(); - if (restParameter == nullptr) { - relation->Result(false); + } + + /* "i" could be one of the following three cases: + 1. == toCheckParametersNumber, we have finished the checking and can directly return. + 2. == other->Params().size(), must be < thisToCheckParametersNumber in this case since + xxx->Params().size() always >= xxxtoCheckParametersNumber. We need to check the remaining + mandatory parameters of "this" against ths RestVar of "other". + 3. == this->Params().size(), must be < otherToCheckParametersNumber as described in 2, and + we need to check the remaining mandatory parameters of "other" against the RestVar of "this". + */ + if (i == toCheckParametersNumber) { + return; + } + bool isOtherMandatoryParamsMatched = i < thisToCheckParametersNumber; + ArenaVector const ¶meters = + isOtherMandatoryParamsMatched ? this->Params() : other->Params(); + varbinder::LocalVariable const *restParameter = isOtherMandatoryParamsMatched ? other->RestVar() : this->RestVar(); + if (restParameter == nullptr) { + relation->Result(false); + return; + } + auto *const restParameterType = restParameter->TsType()->AsETSArrayType()->ElementType(); + for (; i < toCheckParametersNumber; ++i) { + if (!CheckParameter(relation, parameters[i]->TsType(), restParameterType)) { return; } - auto *const restParameterType = restParameter->TsType()->AsETSArrayType()->ElementType(); - for (; i < toCheckParametersNumber; ++i) { - if (!IdenticalParameter(relation, parameters[i]->TsType(), restParameterType)) { - return; - } - } } } @@ -308,7 +319,7 @@ bool Signature::CheckFunctionalInterfaces(TypeRelation *relation, Type *source, ->AsETSFunctionType() ->CallSignatures()[0]; - relation->IsIdenticalTo(sourceInvokeFunc, targetInvokeFunc); + relation->IsCompatibleTo(sourceInvokeFunc, targetInvokeFunc); return true; } diff --git a/ets2panda/checker/types/signature.h b/ets2panda/checker/types/signature.h index 6f1576a7c1..63127d3e98 100644 --- a/ets2panda/checker/types/signature.h +++ b/ets2panda/checker/types/signature.h @@ -250,13 +250,15 @@ public: void ToString(std::stringstream &ss, const varbinder::Variable *variable, bool printAsMethod = false, bool precise = false) const; std::string ToString() const; - void Identical(TypeRelation *relation, Signature *other); + void Compatible(TypeRelation *relation, Signature *other); bool CheckFunctionalInterfaces(TypeRelation *relation, Type *source, Type *target); void AssignmentTarget(TypeRelation *relation, Signature *source); Signature *BoxPrimitives(ETSChecker *checker); private: - bool IdenticalParameter(TypeRelation *relation, Type *type1, Type *type2); + bool CheckParameter(TypeRelation *relation, Type *type1, Type *type2); + bool CheckReturnType(TypeRelation *relation, Type *type1, Type *type2); + checker::SignatureInfo *signatureInfo_; Type *returnType_; ir::ScriptFunction *func_ {}; diff --git a/ets2panda/checker/types/ts/objectType.cpp b/ets2panda/checker/types/ts/objectType.cpp index f3cf29a4e7..a50001c4c1 100644 --- a/ets2panda/checker/types/ts/objectType.cpp +++ b/ets2panda/checker/types/ts/objectType.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021 - 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 @@ -36,7 +36,7 @@ bool ObjectType::SignatureRelatedToSomeSignature(TypeRelation *relation, Signatu ArenaVector *targetSignatures) { for (auto it = targetSignatures->begin(); it != targetSignatures->end();) { - if (relation->IsIdenticalTo(sourceSignature, *it)) { + if (relation->IsCompatibleTo(sourceSignature, *it)) { targetSignatures->erase(it); return true; } diff --git a/ets2panda/checker/types/typeRelation.cpp b/ets2panda/checker/types/typeRelation.cpp index 2938dd202b..95b2f59266 100644 --- a/ets2panda/checker/types/typeRelation.cpp +++ b/ets2panda/checker/types/typeRelation.cpp @@ -68,7 +68,7 @@ bool TypeRelation::IsIdenticalTo(Type *source, Type *target) return result_ == RelationResult::TRUE; } -bool TypeRelation::IsIdenticalTo(Signature *source, Signature *target) +bool TypeRelation::IsCompatibleTo(Signature *source, Signature *target) { if (source == target) { Result(true); @@ -76,7 +76,7 @@ bool TypeRelation::IsIdenticalTo(Signature *source, Signature *target) } result_ = RelationResult::FALSE; - target->Identical(this, source); + target->Compatible(this, source); return result_ == RelationResult::TRUE; } diff --git a/ets2panda/checker/types/typeRelation.h b/ets2panda/checker/types/typeRelation.h index 54c7ae5d32..729dc1f138 100644 --- a/ets2panda/checker/types/typeRelation.h +++ b/ets2panda/checker/types/typeRelation.h @@ -62,6 +62,7 @@ enum class TypeRelationFlag : uint32_t { CHECK_PROXY = 1U << 21U, NO_CHECK_TRAILING_LAMBDA = 1U << 23U, NO_THROW_GENERIC_TYPEALIAS = 1U << 24U, + OVERRIDING_CONTEXT = 1U << 25U, ASSIGNMENT_CONTEXT = WIDENING | BOXING | UNBOXING, CASTING_CONTEXT = NARROWING | WIDENING | BOXING | UNBOXING | UNCHECKED_CAST, @@ -212,6 +213,11 @@ public: return (flags_ & TypeRelationFlag::NO_THROW_GENERIC_TYPEALIAS) != 0; } + [[nodiscard]] bool IsOverridingCheck() const noexcept + { + return (flags_ & TypeRelationFlag::OVERRIDING_CONTEXT) != 0; + } + const Checker *GetChecker() const { return checker_; @@ -265,8 +271,8 @@ public: } bool IsIdenticalTo(Type *source, Type *target); - bool IsIdenticalTo(Signature *source, Signature *target); bool IsIdenticalTo(IndexInfo *source, IndexInfo *target); + bool IsCompatibleTo(Signature *source, Signature *target); bool IsAssignableTo(Type *source, Type *target); bool IsComparableTo(Type *source, Type *target); bool IsCastableTo(Type *const source, Type *const target); diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index 6244f01927..9550537d7d 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -638,11 +638,11 @@ ir::MethodDefinition *ETSEmitter::FindAsyncImpl(ir::ScriptFunction *asyncFunc) auto *checker = static_cast(Context()->Checker()); checker::TypeRelation *typeRel = checker->Relation(); checker::SavedTypeRelationFlagsContext savedFlagsCtx(typeRel, checker::TypeRelationFlag::NO_RETURN_TYPE_CHECK); - method->Function()->Signature()->Identical(typeRel, asyncFunc->Signature()); + method->Function()->Signature()->Compatible(typeRel, asyncFunc->Signature()); auto overloadIt = method->Overloads().begin(); while (overloadIt != method->Overloads().end() && !typeRel->IsTrue()) { method = *overloadIt; - method->Function()->Signature()->Identical(typeRel, asyncFunc->Signature()); + method->Function()->Signature()->Compatible(typeRel, asyncFunc->Signature()); ++overloadIt; } return typeRel->IsTrue() ? method : nullptr; diff --git a/ets2panda/test/runtime/ets/Override-4.ets b/ets2panda/test/runtime/ets/Override-4.ets new file mode 100644 index 0000000000..026d253e76 --- /dev/null +++ b/ets2panda/test/runtime/ets/Override-4.ets @@ -0,0 +1,39 @@ +/* + * 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 X {} +class Y extends X {} + +abstract class A { + foo(x: Y): string { return "A.foo(Y)" } + abstract foo(x: Double): String + foo2(x: Y): Object { return "A.foo(Y)" } +} + +class B extends A { + foo(x: X): string { return "B.foo(X)" } + foo(x: Floating): String { return "B.foo(Floating)" } +} + +class C extends A { + foo(x: Double): String { return "C.foo(Double)" } + override foo2(x: Y): String { return "C.foo2(Y)" } +} + +function main() { + assert(new B().foo(new Y()) == "A.foo(Y)"); + assert(new B().foo(new Double()) == "B.foo(Floating)"); + assert(new C().foo2(new Y()) == "C.foo2(Y)") +} \ No newline at end of file -- Gitee