From 6dcff0708a6871e42203cac75d098c0f1a44cad8 Mon Sep 17 00:00:00 2001 From: zengzengran Date: Wed, 4 Jun 2025 22:36:27 +0800 Subject: [PATCH 01/14] draft parser node and set overload for class method --- ets2panda/BUILD.gn | 3 + ets2panda/CMakeLists.txt | 1 + ets2panda/checker/ETSAnalyzer.cpp | 7 ++ ets2panda/checker/SemanticAnalyzer.h | 1 + ets2panda/checker/TSAnalyzerUnreachable.cpp | 5 + .../compiler/core/ETSCompilerUnrechable.cpp | 5 + .../compiler/core/JSCompilerUnreachable.cpp | 5 + .../lowering/scopesInit/scopesInitPhase.cpp | 112 +++++++++++++++++- .../lowering/scopesInit/scopesInitPhase.h | 2 + ets2panda/ir/astNodeFlags.h | 13 +- ets2panda/ir/astNodeMapping.h | 1 + ets2panda/ir/base/methodDefinition.h | 5 + ets2panda/ir/base/overloadDefinition.cpp | 87 ++++++++++++++ ets2panda/ir/base/overloadDefinition.h | 84 +++++++++++++ ets2panda/lexer/scripts/keywords.yaml | 4 + ets2panda/parser/ETSparser.cpp | 6 + ets2panda/parser/ETSparser.h | 1 + ets2panda/parser/ETSparserClasses.cpp | 33 ++++++ ets2panda/public/CMakeLists.txt | 2 + .../public/headers_parser/supported_types.py | 1 + .../test/ast/parser/ets/overload_test.ets | 43 +++++++ ets2panda/varbinder/ETSBinder.cpp | 8 ++ ets2panda/varbinder/ETSBinder.h | 1 + 23 files changed, 426 insertions(+), 4 deletions(-) create mode 100644 ets2panda/ir/base/overloadDefinition.cpp create mode 100644 ets2panda/ir/base/overloadDefinition.h create mode 100644 ets2panda/test/ast/parser/ets/overload_test.ets diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 0982392c38..478d437fc8 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -288,6 +288,7 @@ libes2panda_sources = [ "ir/base/decorator.cpp", "ir/base/metaProperty.cpp", "ir/base/methodDefinition.cpp", + "ir/base/overloadDefinition.cpp" "ir/base/property.cpp", "ir/base/scriptFunction.cpp", "ir/base/scriptFunctionSignature.cpp", @@ -720,6 +721,7 @@ HEADERS_TO_BE_PARSED = [ "ir/ts/tsImportEqualsDeclaration.h", "ir/validationInfo.h", "ir/base/methodDefinition.h", + "ir/base/overloadDefinition.h", "ir/ts/tsIntersectionType.h", "checker/types/ts/nullType.h", "checker/types/ts/unknownType.h", @@ -967,6 +969,7 @@ ES2PANDA_API_GENERATED = [ "$LIBGEN_DIR/gen/headers/ir/expressions/directEvalExpression.yaml", "$LIBGEN_DIR/gen/headers/ir/ts/tsTypeParameterDeclaration.yaml", "$LIBGEN_DIR/gen/headers/ir/base/methodDefinition.yaml", + "$LIBGEN_DIR/gen/headers/ir/base/overloadDefinition.yaml", "$LIBGEN_DIR/gen/headers/ir/ts/tsNullKeyword.yaml", "$LIBGEN_DIR/gen/headers/ir/ts/tsInterfaceHeritage.yaml", "$LIBGEN_DIR/gen/headers/checker/types/ts/enumLiteralType.yaml", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 3cef5f00dc..26998fcb87 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -338,6 +338,7 @@ set(ES2PANDA_LIB_SRC ir/base/decorator.cpp ir/base/metaProperty.cpp ir/base/methodDefinition.cpp + ir/base/overloadDefinition.cpp ir/base/property.cpp ir/base/scriptFunction.cpp ir/base/scriptFunctionSignature.cpp diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index f5b0778cde..c3c2614031 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -302,6 +302,13 @@ void ETSAnalyzer::CheckMethodModifiers(ir::MethodDefinition *node) const node->SetTsType(checker->GlobalTypeError()); } } +// TODO check OverloadDefinition +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::OverloadDefinition *node) const +{ + ETSChecker *checker = GetETSChecker(); + ES2PANDA_ASSERT(node); + return checker->GlobalTypeError(); +} checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Property *expr) const { diff --git a/ets2panda/checker/SemanticAnalyzer.h b/ets2panda/checker/SemanticAnalyzer.h index b0db804c08..9dda3202d0 100644 --- a/ets2panda/checker/SemanticAnalyzer.h +++ b/ets2panda/checker/SemanticAnalyzer.h @@ -27,6 +27,7 @@ #include "ir/base/decorator.h" #include "ir/base/metaProperty.h" #include "ir/base/methodDefinition.h" +#include "ir/base/overloadDefinition.h" #include "ir/base/property.h" #include "ir/base/scriptFunction.h" #include "ir/base/spreadElement.h" diff --git a/ets2panda/checker/TSAnalyzerUnreachable.cpp b/ets2panda/checker/TSAnalyzerUnreachable.cpp index e5c22b6907..dbdd9a1440 100644 --- a/ets2panda/checker/TSAnalyzerUnreachable.cpp +++ b/ets2panda/checker/TSAnalyzerUnreachable.cpp @@ -48,6 +48,11 @@ checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::MethodDefinition *node) co ES2PANDA_UNREACHABLE(); } +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::OverloadDefinition *node) const +{ + ES2PANDA_UNREACHABLE(); +} + checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::Property *expr) const { ES2PANDA_UNREACHABLE(); diff --git a/ets2panda/compiler/core/ETSCompilerUnrechable.cpp b/ets2panda/compiler/core/ETSCompilerUnrechable.cpp index edcf0a2205..dea45f8750 100644 --- a/ets2panda/compiler/core/ETSCompilerUnrechable.cpp +++ b/ets2panda/compiler/core/ETSCompilerUnrechable.cpp @@ -52,6 +52,11 @@ void ETSCompiler::Compile([[maybe_unused]] const ir::MethodDefinition *node) con ES2PANDA_UNREACHABLE(); } +void ETSCompiler::Compile([[maybe_unused]] const ir::OverloadDefinition *node) const +{ + ES2PANDA_UNREACHABLE(); +} + void ETSCompiler::Compile([[maybe_unused]] const ir::Property *expr) const { ES2PANDA_UNREACHABLE(); diff --git a/ets2panda/compiler/core/JSCompilerUnreachable.cpp b/ets2panda/compiler/core/JSCompilerUnreachable.cpp index 391a89c24c..931a0088c5 100644 --- a/ets2panda/compiler/core/JSCompilerUnreachable.cpp +++ b/ets2panda/compiler/core/JSCompilerUnreachable.cpp @@ -48,6 +48,11 @@ void JSCompiler::Compile([[maybe_unused]] const ir::MethodDefinition *node) cons ES2PANDA_UNREACHABLE(); } +void JSCompiler::Compile([[maybe_unused]] const ir::OverloadDefinition *node) const +{ + ES2PANDA_UNREACHABLE(); +} + void JSCompiler::Compile([[maybe_unused]] const ir::Property *expr) const { ES2PANDA_UNREACHABLE(); diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index e19ee51185..12ef1a13a8 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -414,7 +414,20 @@ void ScopesInitPhase::IterateNoTParams(ir::ClassDefinition *classDef) CallNode(classDef->Annotations()); CallNode(classDef->Implements()); CallNode(classDef->Ctor()); - CallNode(classDef->Body()); + // CallNode(classDef->Body()); + for (auto property : classDef->Body()) { + if (property->IsOverloadDefinition()) { + continue; + } + CallNode(property); + } + // After initializing the scope for all methods, set the overloads for the OverloadDefinition + for (auto property : classDef->Body()) { + if (property->IsOverloadDefinition()) { + CallNode(property); + ; + } + } } void ScopesInitPhase::LogDiagnostic(const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams ¶ms, @@ -541,7 +554,7 @@ void ScopesInitPhase::Finalize() auto &body = ast->AsTSInterfaceBody()->Body(); auto it = body.begin(); while (it != body.end()) { - if ((*it)->IsMethodDefinition() && + if ((*it)->IsMethodDefinition() && (*it)->AsMethodDefinition()->Function()->Body() == nullptr && ((*it)->AsMethodDefinition()->Function()->Flags() & (ir::ScriptFunctionFlags::OVERLOAD | ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD)) != 0U) { it = body.erase(it); @@ -1012,6 +1025,7 @@ void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Iden var->AddFlag(varbinder::VariableFlags::METHOD); methodName->SetVariable(var); } + //TODO constructor maybe other for (auto *overload : method->Overloads()) { ES2PANDA_ASSERT((overload->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) || (overload->Function()->Flags() & ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD)); @@ -1024,6 +1038,12 @@ void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Iden } ES2PANDA_ASSERT((method->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) == 0U); + if (method->Function()->Body() != nullptr) { + auto foundMethod = found->Declaration()->Node()->AsMethodDefinition(); + found->Declaration()->BindNode(method); + method = foundMethod; + } + AddOverload(method, found); method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); @@ -1036,6 +1056,65 @@ void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Iden } } +void InitScopesPhaseETS::DeclareClassOverload(ir::OverloadDefinition *overloadDef) +{ + ES2PANDA_ASSERT(VarBinder()->GetScope()->IsClassScope()); + + const auto overloadName = overloadDef->Id(); + auto *const clsScope = VarBinder()->GetScope()->AsClassScope(); + auto options = + overloadDef->IsStatic() + ? varbinder::ResolveBindingOptions::STATIC_VARIABLES | varbinder::ResolveBindingOptions::STATIC_DECLARATION + : varbinder::ResolveBindingOptions::VARIABLES | varbinder::ResolveBindingOptions::DECLARATION; + auto variable = clsScope->FindLocal(overloadName->Name(), options); + if (variable != nullptr) { + VarBinder()->ThrowRedeclaration(overloadName->Start(), overloadName->Name(), variable->Declaration()->Type()); + } + + varbinder::LocalScope *targetScope {}; + if (overloadDef->IsStatic()) { + targetScope = clsScope->StaticMethodScope(); + } else { + targetScope = clsScope->InstanceMethodScope(); + } + for (auto *methodName : overloadDef->GetOverloadIdentifiers()) { + auto *found = + targetScope->FindLocal(methodName->AsIdentifier()->Name(), varbinder::ResolveBindingOptions::BINDINGS); + // TODO method not found; + if (found == nullptr) { + VarBinder()->ThrowRedeclaration(overloadName->Start(), overloadName->Name(), + variable->Declaration()->Type()); + continue; + } + // TODO only binding method; + if (!found->Declaration()->Node()->IsMethodDefinition()) { + VarBinder()->ThrowRedeclaration(overloadName->Start(), overloadName->Name(), + variable->Declaration()->Type()); + continue; + } + auto *method = found->Declaration()->Node()->AsMethodDefinition(); + // TODO only binding our_style method; + if (method->IsTsOverload()) { + VarBinder()->ThrowRedeclaration(overloadName->Start(), overloadName->Name(), + variable->Declaration()->Type()); + continue; + } + overloadDef->AddOverloads(method); + method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); + methodName->SetVariable(found); + } + + auto classCtx = varbinder::LexicalScope::Enter(VarBinder(), targetScope); + auto var = std::get<1>(VarBinder()->NewVarDecl(overloadName->Start(), Allocator(), + overloadName->Name(), overloadDef)); + var->SetScope(clsScope); + if (targetScope->HasFlag(varbinder::ScopeFlags::STATIC)) { + var->AddFlag(varbinder::VariableFlags::STATIC); + } + var->AddFlag(varbinder::VariableFlags::METHOD); + overloadName->SetVariable(var); +} + void InitScopesPhaseETS::VisitETSReExportDeclaration(ir::ETSReExportDeclaration *reExport) { if (!reExport->GetETSImportDeclarations()->IsValid()) { @@ -1094,8 +1173,35 @@ void InitScopesPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enumMember) Iterate(enumMember); } +void InitScopesPhaseETS::VisitOverloadDefinition(ir::OverloadDefinition *overload) +{ + if (overload->Key()->AsIdentifier()->Name() == "foo") { + std::cout << 123 << std::endl; + } + + auto *curScope = VarBinder()->GetScope(); + const auto overloadName = overload->Id(); + auto res = + curScope->Find(overloadName->Name(), overload->IsStatic() ? varbinder::ResolveBindingOptions::ALL_STATIC + : varbinder::ResolveBindingOptions::ALL_NON_STATIC); + if (res.variable != nullptr) { + VarBinder()->ThrowRedeclaration(overloadName->Start(), res.name, varbinder::DeclType::METHOD); + } + + auto result = curScope->FindLocal(overloadName->Name(), varbinder::ResolveBindingOptions::ALL_DECLARATION); + if (result != nullptr) { + VarBinder()->ThrowLocalRedeclaration(overloadName->Start(), result->Name()); + } + + Iterate(overload); + DeclareClassOverload(overload); +} + void InitScopesPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method) { + if (method->Key()->AsIdentifier()->Name() == "foo111") { + std::cout<<123<Function()->Scope() != nullptr) { return; } @@ -1291,7 +1397,7 @@ void InitScopesPhaseETS::FilterOverloads(ArenaVector &prop auto condition = [](ir::AstNode *prop) { if (prop->IsMethodDefinition()) { const auto func = prop->AsMethodDefinition()->Function(); - return func->IsOverload(); + return func->IsOverload() && func->Body() == nullptr; } return false; }; diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h index e3b5d7e556..c073234e90 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h @@ -344,6 +344,7 @@ private: void DeclareClassMethod(ir::MethodDefinition *method); void MaybeAddOverload(ir::MethodDefinition *method, ir::Identifier *methodName, varbinder::Variable *found, varbinder::ClassScope *clsScope, varbinder::LocalScope *targetScope); + void DeclareClassOverload(ir::OverloadDefinition *overloadDef); void VisitClassStaticBlock(ir::ClassStaticBlock *staticBlock) override; void VisitBlockExpression(ir::BlockExpression *blockExpr) override; @@ -354,6 +355,7 @@ private: void VisitETSParameterExpression(ir::ETSParameterExpression *paramExpr) override; void VisitETSImportDeclaration(ir::ETSImportDeclaration *importDecl) override; void VisitTSEnumMember(ir::TSEnumMember *enumMember) override; + void VisitOverloadDefinition(ir::OverloadDefinition *method) override; void VisitMethodDefinition(ir::MethodDefinition *method) override; void VisitETSFunctionType(ir::ETSFunctionType *funcType) override; void VisitETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *newClassExpr) override; diff --git a/ets2panda/ir/astNodeFlags.h b/ets2panda/ir/astNodeFlags.h index 617e3e42f8..46ee70aef3 100644 --- a/ets2panda/ir/astNodeFlags.h +++ b/ets2panda/ir/astNodeFlags.h @@ -79,7 +79,18 @@ enum class ModifierFlags : uint32_t { EXPORTED = EXPORT | DEFAULT_EXPORT | EXPORT_TYPE }; -enum class PrivateFieldKind { FIELD, METHOD, GET, SET, STATIC_FIELD, STATIC_METHOD, STATIC_GET, STATIC_SET }; +enum class PrivateFieldKind { + FIELD, + METHOD, + GET, + SET, + OVERLOAD, + STATIC_FIELD, + STATIC_METHOD, + STATIC_GET, + STATIC_SET, + STATIC_OVERLOAD +}; enum class ScriptFunctionFlags : uint32_t { NONE = 0U, diff --git a/ets2panda/ir/astNodeMapping.h b/ets2panda/ir/astNodeMapping.h index 0c2e397721..faa323351c 100644 --- a/ets2panda/ir/astNodeMapping.h +++ b/ets2panda/ir/astNodeMapping.h @@ -73,6 +73,7 @@ _(UNDEFINED_LITERAL, UndefinedLiteral) \ _(NUMBER_LITERAL, NumberLiteral) \ _(OMITTED_EXPRESSION, OmittedExpression) \ + _(OVERLOAD_DEFINITION, OverloadDefinition) \ _(PREFIX_ASSERTION_EXPRESSION, PrefixAssertionExpression) \ _(PROPERTY, Property) \ _(REGEXP_LITERAL, RegExpLiteral) \ diff --git a/ets2panda/ir/base/methodDefinition.h b/ets2panda/ir/base/methodDefinition.h index af54efb580..47ac731ce1 100644 --- a/ets2panda/ir/base/methodDefinition.h +++ b/ets2panda/ir/base/methodDefinition.h @@ -128,6 +128,11 @@ public: void SetDefaultAccessModifier(bool isDefault); + [[nodiscard]] bool IsTsOverload() const noexcept + { + return !overloads_.empty(); + } + [[nodiscard]] const OverloadsT &Overloads() const noexcept { return GetHistoryNodeAs()->overloads_; diff --git a/ets2panda/ir/base/overloadDefinition.cpp b/ets2panda/ir/base/overloadDefinition.cpp new file mode 100644 index 0000000000..ccd4444143 --- /dev/null +++ b/ets2panda/ir/base/overloadDefinition.cpp @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#include "overloadDefinition.h" +#include "checker/ETSchecker.h" + +namespace ark::es2panda::ir { +PrivateFieldKind OverloadDefinition::ToPrivateFieldKind(bool const isStatic) const +{ + return isStatic ? PrivateFieldKind::STATIC_OVERLOAD : PrivateFieldKind::OVERLOAD; +} + +void OverloadDefinition::ResolveReferences(const NodeTraverser &cb) const +{ + cb(key_); + + for (auto *it : VectorIterationGuard(overloadIdentifiers_)) { + cb(it); + } +} + +void OverloadDefinition::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) +{ + cb(key_); + for (auto *&it : VectorIterationGuard(overloadIdentifiers_)) { + if (auto *transformedNode = cb(it); it != transformedNode) { + it->SetTransformedNode(transformationName, transformedNode); + it = transformedNode->AsMethodDefinition(); + } + } +} + +void OverloadDefinition::Iterate(const NodeTraverser &cb) const +{ + cb(key_); + for (auto *it : VectorIterationGuard(overloadIdentifiers_)) { + cb(it); + } +} + +void OverloadDefinition::Dump(ir::AstDumper *dumper) const +{ + dumper->Add({{"type", "OverloadDefinition"}, + {"key", key_}, + {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(flags_))}, + {"static", IsStatic()}, + {"overloads", overloads_}, + {"overloadidentifiers", overloadIdentifiers_}}); +} +// TODO SrcDumper for OverloadDefinition +void OverloadDefinition::Dump(ir::SrcDumper *dumper) const +{ + dumper->Add("overload decl src dump is not implement, overload "); + key_->Dump(dumper); + dumper->Add("{"); + for (auto *id : overloadIdentifiers_) { + id->Dump(dumper); + dumper->Add(", "); + } + dumper->Add("};"); + return; +} + +void OverloadDefinition::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} + +checker::Type *OverloadDefinition::Check([[maybe_unused]] checker::TSChecker *checker) +{ + return nullptr; +} + +checker::VerifiedType OverloadDefinition::Check([[maybe_unused]] checker::ETSChecker *checker) +{ + return {this, checker->GetAnalyzer()->Check(this)}; +} +} // namespace ark::es2panda::ir \ No newline at end of file diff --git a/ets2panda/ir/base/overloadDefinition.h b/ets2panda/ir/base/overloadDefinition.h new file mode 100644 index 0000000000..3c3b12fb00 --- /dev/null +++ b/ets2panda/ir/base/overloadDefinition.h @@ -0,0 +1,84 @@ +/** + * 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. + */ + +#ifndef ES2PANDA_IR_OVERLOAD_DEFINITION_H +#define ES2PANDA_IR_OVERLOAD_DEFINITION_H + +#include "ir/typeNode.h" +#include "methodDefinition.h" + +namespace ark::es2panda::ir { +class OverloadDefinition : public ClassElement { +public: + OverloadDefinition() = delete; + ~OverloadDefinition() override = default; + + NO_COPY_SEMANTIC(OverloadDefinition); + NO_MOVE_SEMANTIC(OverloadDefinition); + + explicit OverloadDefinition(Expression *const key, ModifierFlags const modifiers, ArenaAllocator *const allocator) + : ClassElement(AstNodeType::OVERLOAD_DEFINITION, key, nullptr, modifiers, allocator, false), + overloads_(allocator->Adapter()), + overloadIdentifiers_(allocator->Adapter()) + { + } + + [[nodiscard]] ArenaVector &GetOverloadIdentifiers() noexcept + { + return overloadIdentifiers_; + } + + [[nodiscard]] ArenaVector &GetOverloads() noexcept + { + return overloads_; + } + + void SetOverloadIdentifiers(ArenaVector overloadIdentifiers) + { + overloadIdentifiers_ = std::move(overloadIdentifiers); + } + + void SetOverloads(ArenaVector overloads) + { + overloads_ = std::move(overloads); + } + + void AddOverloads(MethodDefinition *overload) + { + overloads_.push_back(overload); + } + + void ResolveReferences(const NodeTraverser &cb) const; + + PrivateFieldKind ToPrivateFieldKind(bool isStatic) const override; + void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; + void Iterate(const NodeTraverser &cb) const override; + void Dump(ir::AstDumper *dumper) const override; + void Dump(ir::SrcDumper *dumper) const override; + void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Accept(ASTVisitorT *v) override + { + v->Accept(this); + } + +private: + ArenaVector overloads_; + ArenaVector overloadIdentifiers_; +}; +} // namespace ark::es2panda::ir + +#endif diff --git a/ets2panda/lexer/scripts/keywords.yaml b/ets2panda/lexer/scripts/keywords.yaml index 3ed7f5ff79..afecef9f21 100644 --- a/ets2panda/lexer/scripts/keywords.yaml +++ b/ets2panda/lexer/scripts/keywords.yaml @@ -416,6 +416,10 @@ keywords: token: KEYW_OUT keyword_like: [ets] + - name: 'overload' + token: KEYW_OVERLOAD + keyword_like: [ets] + - name: 'override' token: KEYW_OVERRIDE keyword: [ets] diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 2d5df77c03..eaf2c3f9f2 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -642,6 +642,12 @@ ir::AstNode *ETSParser::ParseInnerRest(const ArenaVector &propert } } + if (Lexer()->TryEatTokenFromKeywordType(lexer::TokenType::KEYW_OVERLOAD)) { + auto *classOverload = ParseClassOverloadDefinition( memberModifiers); + classOverload->SetStart(startLoc); + return classOverload; + } + auto *memberName = ExpectIdentifier(false, false, TypeAnnotationParsingOptions::NO_OPTS); // don't report error if (memberName == nullptr) { // log error here LogUnexpectedToken(Lexer()->GetToken()); diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 1d7b1ee848..bc1ac4b7e4 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -233,6 +233,7 @@ private: ir::ModifierFlags ParseClassFieldModifiers(bool seenStatic); ir::ModifierFlags ParseClassMethodModifierFlag(); ir::ModifierFlags ParseClassMethodModifiers(bool seenStatic); + ir::OverloadDefinition *ParseClassOverloadDefinition(ir::ModifierFlags modifiers); ir::MethodDefinition *ParseClassMethodDefinition(ir::Identifier *methodName, ir::ModifierFlags modifiers, bool isDefault); ir::ScriptFunction *ParseFunction(ParserStatus newStatus); diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp index 0876670671..294087c1a1 100644 --- a/ets2panda/parser/ETSparserClasses.cpp +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -534,6 +534,39 @@ void ETSParser::ParseClassFieldDefinition(ir::Identifier *fieldName, ir::Modifie declarations->push_back(field); } +ir::OverloadDefinition *ETSParser::ParseClassOverloadDefinition(ir::ModifierFlags modifiers) +{ + auto *overloadName = ExpectIdentifier(false, true, TypeAnnotationParsingOptions::NO_OPTS); + auto *overloadDef = AllocNode(overloadName->Clone(Allocator(), nullptr)->AsExpression(), + modifiers, Allocator()); + + auto startLoc = Lexer()->GetToken().Start(); + if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) { + // TODO add error message + LogError(diagnostic::TYPE_ALIAS_INVALID_NAME); + } + ArenaVector overloads(Allocator()->Adapter()); + lexer::SourcePosition endLoc; + auto parseElement = [this, &overloads, overloadDef]() { + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + LogExpectedToken(lexer::TokenType::LITERAL_IDENT); + } + + auto *identifier = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + identifier->SetParent(overloadDef); + identifier->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + + overloads.push_back(identifier); + return true; + }; + + ParseList(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::NONE, parseElement, &endLoc, true); + overloadDef->SetOverloadIdentifiers(std::move(overloads)); + overloadDef->SetRange({startLoc, endLoc}); + return overloadDef; +} + ir::MethodDefinition *ETSParser::ParseClassMethodDefinition(ir::Identifier *methodName, ir::ModifierFlags modifiers, bool isDefault) { diff --git a/ets2panda/public/CMakeLists.txt b/ets2panda/public/CMakeLists.txt index 12227ac6fe..809e121242 100644 --- a/ets2panda/public/CMakeLists.txt +++ b/ets2panda/public/CMakeLists.txt @@ -237,6 +237,7 @@ set (HEADERS_TO_BE_PARSED ${ES2PANDA_ROOT}/ir/ts/tsImportEqualsDeclaration.h ${ES2PANDA_ROOT}/ir/validationInfo.h ${ES2PANDA_ROOT}/ir/base/methodDefinition.h + ${ES2PANDA_ROOT}/ir/base/overloadDefinition.h ${ES2PANDA_ROOT}/ir/ts/tsIntersectionType.h ${ES2PANDA_ROOT}/checker/types/ts/nullType.h ${ES2PANDA_ROOT}/checker/types/ts/unknownType.h @@ -487,6 +488,7 @@ set (ES2PANDA_API_GENERATED ${LIBGEN_DIR}/gen/headers/ir/expressions/directEvalExpression.yaml ${LIBGEN_DIR}/gen/headers/ir/ts/tsTypeParameterDeclaration.yaml ${LIBGEN_DIR}/gen/headers/ir/base/methodDefinition.yaml + ${LIBGEN_DIR}/gen/headers/ir/base/overloadDefinition.yaml ${LIBGEN_DIR}/gen/headers/ir/ts/tsNullKeyword.yaml ${LIBGEN_DIR}/gen/headers/ir/ts/tsInterfaceHeritage.yaml ${LIBGEN_DIR}/gen/headers/checker/types/ts/enumLiteralType.yaml diff --git a/ets2panda/public/headers_parser/supported_types.py b/ets2panda/public/headers_parser/supported_types.py index be10e6eb98..c464f578c6 100644 --- a/ets2panda/public/headers_parser/supported_types.py +++ b/ets2panda/public/headers_parser/supported_types.py @@ -64,6 +64,7 @@ ast_nodes_supported = [ "MemberExpression", "MetaProperty", "MethodDefinition", + "OverloadDefinition", "NamedType", "NewExpression", "NullLiteral", diff --git a/ets2panda/test/ast/parser/ets/overload_test.ets b/ets2panda/test/ast/parser/ets/overload_test.ets new file mode 100644 index 0000000000..d7c13e94fd --- /dev/null +++ b/ets2panda/test/ast/parser/ets/overload_test.ets @@ -0,0 +1,43 @@ +/* + * 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 A{} +class B{} +class C{} +class TempAny{} + +class Test1 { + foo111(a: A): A { + return a; + } + foo112(a: B): B { + return a; + } + + foo113(a: C): C { + console.log(a) + return a; + } + overload foo{foo111,foo112,foo113} +} + +class Test2 { + foo111(a: A): A; + foo111(a: B): B; + foo111(a: C): C; + foo111(...args:TempAny[]):TempAny{ + return args[0]; + } +} diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index f2983e06ca..577c250f17 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -449,6 +449,11 @@ void ETSBinder::ResolveMethodDefinition(ir::MethodDefinition *methodDef) thisParam->Declaration()->BindNode(thisParam_); } +void ETSBinder::BuildOverloadDefinition(ir::OverloadDefinition *overloadDef) +{ + overloadDef->ResolveReferences([this](auto *childNode) { ResolveReference(childNode); }); +} + void ETSBinder::BuildMemberExpression(ir::MemberExpression *memberExpr) { ResolveReference(memberExpr->Object()); @@ -1088,6 +1093,9 @@ void ETSBinder::HandleCustomNodes(ir::AstNode *childNode) case ir::AstNodeType::METHOD_DEFINITION: { return BuildMethodDefinition(childNode->AsMethodDefinition()); } + case ir::AstNodeType::OVERLOAD_DEFINITION: { + return BuildOverloadDefinition(childNode->AsOverloadDefinition()); + } case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { return BuildETSNewClassInstanceExpression(childNode->AsETSNewClassInstanceExpression()); } diff --git a/ets2panda/varbinder/ETSBinder.h b/ets2panda/varbinder/ETSBinder.h index 140596eccd..4aec0cb3ea 100644 --- a/ets2panda/varbinder/ETSBinder.h +++ b/ets2panda/varbinder/ETSBinder.h @@ -139,6 +139,7 @@ public: void BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl); void BuildMemberExpression(ir::MemberExpression *memberExpr); void BuildMethodDefinition(ir::MethodDefinition *methodDef); + void BuildOverloadDefinition(ir::OverloadDefinition *overloadDef); void BuildAnnotationDeclaration(ir::AnnotationDeclaration *annoDecl); void BuildAnnotationUsage(ir::AnnotationUsage *annoUsage); void BuildImportDeclaration(ir::ETSImportDeclaration *decl); -- Gitee From 90206e449404e7baacd81852de804e3822407cac Mon Sep 17 00:00:00 2001 From: zengzengran Date: Thu, 5 Jun 2025 15:25:58 +0800 Subject: [PATCH 02/14] draft parser node and set overload for interface method and global function --- .../topLevelStmts/globalDeclTransformer.cpp | 14 ++++++ .../ets/topLevelStmts/globalDeclTransformer.h | 1 + .../lowering/scopesInit/scopesInitPhase.cpp | 42 ++++++++++-------- .../lowering/scopesInit/scopesInitPhase.h | 5 ++- ets2panda/parser/ETSparser.cpp | 33 ++++++++++++++ ets2panda/parser/ETSparser.h | 2 + ets2panda/parser/ETSparserClasses.cpp | 39 +++++++++++++++++ ets2panda/parser/ETSparserStatements.cpp | 3 ++ .../parser/ets/overload_class_method_test.ets | 43 +++++++++++++++++++ ...verload_global_function_our_style_test.ets | 34 +++++++++++++++ ...overload_global_function_ts_style_test.ets | 26 +++++++++++ .../ets/overload_interface_method_test.ets | 34 +++++++++++++++ ets2panda/varbinder/variableFlags.h | 1 + 13 files changed, 256 insertions(+), 21 deletions(-) create mode 100644 ets2panda/test/ast/parser/ets/overload_class_method_test.ets create mode 100644 ets2panda/test/ast/parser/ets/overload_global_function_our_style_test.ets create mode 100644 ets2panda/test/ast/parser/ets/overload_global_function_ts_style_test.ets create mode 100644 ets2panda/test/ast/parser/ets/overload_interface_method_test.ets diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp index dc8869fffa..29710baf09 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp @@ -36,8 +36,22 @@ GlobalDeclTransformer::ResultT GlobalDeclTransformer::TransformStatements(const return std::move(result_); } +void GlobalDeclTransformer::VisitOverloadDefinition(ir::OverloadDefinition *overloadDefinition) +{ + if (overloadDefinition->Key()->AsIdentifier()->Name() == "foo" || + overloadDefinition->Key()->AsIdentifier()->Name() == "foo111") { + std::cout << 123 << std::endl; + } + // TODO Maybe export flag + + result_.classProperties.emplace_back(overloadDefinition); +} + void GlobalDeclTransformer::VisitFunctionDeclaration(ir::FunctionDeclaration *funcDecl) { + if (funcDecl->Function()->Id()->Name() == "foo111") { + std::cout<<123<(allocator_, funcDecl->Function()); funcDecl->Function()->SetStart(funcDecl->Function()->Id()->Start()); funcExpr->SetRange(funcDecl->Function()->Range()); diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.h b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.h index 8e38b224e1..ff1cc19f84 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.h +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.h @@ -79,6 +79,7 @@ public: */ ResultT TransformStatements(const ArenaVector &stmts); + void VisitOverloadDefinition(ir::OverloadDefinition *overloadDefinition) override; void VisitFunctionDeclaration(ir::FunctionDeclaration *funcDecl) override; void VisitVariableDeclaration(ir::VariableDeclaration *varDecl) override; void VisitClassStaticBlock(ir::ClassStaticBlock *classStaticBlock) override; diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 12ef1a13a8..3827896da6 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -542,6 +542,14 @@ void ScopesInitPhase::Prepare(ScopesInitPhase::PhaseContext *ctx, parser::Progra program_ = program; } +static bool IsTsOverloadSignatrue(ir::AstNode *ast) +{ + return ast->IsMethodDefinition() && + (ast->AsMethodDefinition()->Function()->Flags() & + (ir::ScriptFunctionFlags::OVERLOAD | ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD)) != 0U && + ast->AsMethodDefinition()->BaseOverloadMethod() != nullptr; +} + void ScopesInitPhase::Finalize() { ES2PANDA_ASSERT(program_->Ast() != nullptr); @@ -554,9 +562,7 @@ void ScopesInitPhase::Finalize() auto &body = ast->AsTSInterfaceBody()->Body(); auto it = body.begin(); while (it != body.end()) { - if ((*it)->IsMethodDefinition() && (*it)->AsMethodDefinition()->Function()->Body() == nullptr && - ((*it)->AsMethodDefinition()->Function()->Flags() & - (ir::ScriptFunctionFlags::OVERLOAD | ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD)) != 0U) { + if (IsTsOverloadSignatrue((*it))) { it = body.erase(it); } else { ++it; @@ -1008,10 +1014,10 @@ void InitScopesPhaseETS::DeclareClassMethod(ir::MethodDefinition *method) } void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Identifier *methodName, - varbinder::Variable *found, varbinder::ClassScope *clsScope, + varbinder::Variable *overloadMethodVariable, varbinder::ClassScope *clsScope, varbinder::LocalScope *targetScope) { - if (found == nullptr) { + if (overloadMethodVariable == nullptr) { auto classCtx = varbinder::LexicalScope::Enter(VarBinder(), targetScope); auto *var = methodName->Variable(); @@ -1025,7 +1031,7 @@ void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Iden var->AddFlag(varbinder::VariableFlags::METHOD); methodName->SetVariable(var); } - //TODO constructor maybe other + // TODO constructor maybe other for (auto *overload : method->Overloads()) { ES2PANDA_ASSERT((overload->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) || (overload->Function()->Flags() & ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD)); @@ -1038,21 +1044,19 @@ void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Iden } ES2PANDA_ASSERT((method->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) == 0U); - if (method->Function()->Body() != nullptr) { - auto foundMethod = found->Declaration()->Node()->AsMethodDefinition(); - found->Declaration()->BindNode(method); - method = foundMethod; - } - - AddOverload(method, found); - method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); + auto *foundMethod = overloadMethodVariable->Declaration()->Node()->AsMethodDefinition(); + overloadMethodVariable->Declaration()->BindNode(method); // default params overloads - for (auto *overload : method->Overloads()) { + for (auto *overload : foundMethod->Overloads()) { ES2PANDA_ASSERT((overload->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) != 0U); - AddOverload(overload, found); + AddOverload(overload, overloadMethodVariable); } - method->ClearOverloads(); + + AddOverload(foundMethod, overloadMethodVariable); + foundMethod->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); + + foundMethod->ClearOverloads(); } } @@ -1111,7 +1115,7 @@ void InitScopesPhaseETS::DeclareClassOverload(ir::OverloadDefinition *overloadDe if (targetScope->HasFlag(varbinder::ScopeFlags::STATIC)) { var->AddFlag(varbinder::VariableFlags::STATIC); } - var->AddFlag(varbinder::VariableFlags::METHOD); + var->AddFlag(varbinder::VariableFlags::OVERLOAD); overloadName->SetVariable(var); } @@ -1175,7 +1179,7 @@ void InitScopesPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enumMember) void InitScopesPhaseETS::VisitOverloadDefinition(ir::OverloadDefinition *overload) { - if (overload->Key()->AsIdentifier()->Name() == "foo") { + if (overload->Key()->AsIdentifier()->Name() == "foo" || overload->Key()->AsIdentifier()->Name() == "foo111") { std::cout << 123 << std::endl; } diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h index c073234e90..e7dc5d49d4 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.h @@ -342,8 +342,9 @@ private: void BindVarDecl(ir::Identifier *binding, ir::Expression *init, varbinder::Decl *decl, varbinder::Variable *var) override; void DeclareClassMethod(ir::MethodDefinition *method); - void MaybeAddOverload(ir::MethodDefinition *method, ir::Identifier *methodName, varbinder::Variable *found, - varbinder::ClassScope *clsScope, varbinder::LocalScope *targetScope); + void MaybeAddOverload(ir::MethodDefinition *method, ir::Identifier *methodName, + varbinder::Variable *overloadMethodVariable, varbinder::ClassScope *clsScope, + varbinder::LocalScope *targetScope); void DeclareClassOverload(ir::OverloadDefinition *overloadDef); void VisitClassStaticBlock(ir::ClassStaticBlock *staticBlock) override; diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index eaf2c3f9f2..895184dfdd 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -2101,6 +2101,39 @@ void ETSParser::CheckDeclare() } } +ir::OverloadDefinition *ETSParser::ParseOverloadDefinition(ir::ModifierFlags modifiers) +{ + auto *overloadName = ExpectIdentifier(false, true, TypeAnnotationParsingOptions::NO_OPTS); + auto *overloadDef = AllocNode(overloadName->Clone(Allocator(), nullptr)->AsExpression(), + modifiers, Allocator()); + + auto startLoc = Lexer()->GetToken().Start(); + if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) { + // TODO add error message + LogError(diagnostic::TYPE_ALIAS_INVALID_NAME); + } + ArenaVector overloads(Allocator()->Adapter()); + lexer::SourcePosition endLoc; + auto parseElement = [this, &overloads, overloadDef]() { + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + LogExpectedToken(lexer::TokenType::LITERAL_IDENT); + } + + auto *identifier = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + identifier->SetParent(overloadDef); + identifier->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + + overloads.push_back(identifier); + return true; + }; + + ParseList(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::NONE, parseElement, &endLoc, true); + overloadDef->SetOverloadIdentifiers(std::move(overloads)); + overloadDef->SetRange({startLoc, endLoc}); + return overloadDef; +} + ir::FunctionDeclaration *ETSParser::ParseFunctionDeclaration(bool canBeAnonymous, ir::ModifierFlags modifiers) { lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index bc1ac4b7e4..cadd16c834 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -227,6 +227,7 @@ private: ir::AstNode *ParseInterfaceField(); ir::TypeNode *ParseInterfaceTypeAnnotation(ir::Identifier *name); void ParseInterfaceModifiers(ir::ModifierFlags &fieldModifiers, bool &optionalField); + ir::OverloadDefinition *ParseInterfaceOverload(ir::ModifierFlags flags); ir::MethodDefinition *ParseInterfaceMethod(ir::ModifierFlags flags, ir::MethodDefinitionKind methodKind); void ReportAccessModifierError(const lexer::Token &token); std::tuple ParseClassMemberAccessModifiers(); @@ -388,6 +389,7 @@ private: ir::Statement *ParseInterfaceDeclaration(bool isStatic) override; ir::TypeNode *ParseThisType(TypeAnnotationParsingOptions *options); ir::Statement *ParseFunctionStatement(StatementParsingFlags flags) override; + ir::OverloadDefinition *ParseOverloadDefinition(ir::ModifierFlags modifiers); ir::FunctionDeclaration *ParseFunctionDeclaration(bool canBeAnonymous, ir::ModifierFlags modifiers); ir::FunctionDeclaration *ParseAccessorWithReceiver(ir::ModifierFlags modifiers); ir::TypeNode *ParseExtensionFunctionsTypeAnnotation(); diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp index 294087c1a1..8d8f0bdc64 100644 --- a/ets2panda/parser/ETSparserClasses.cpp +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -1107,6 +1107,39 @@ static lexer::SourcePosition GetEndLoc(ir::BlockStatement *body, ir::ScriptFunct return lexer->GetToken().End(); } +ir::OverloadDefinition *ETSParser::ParseInterfaceOverload(ir::ModifierFlags modifiers) +{ + auto *overloadName = ExpectIdentifier(false, true, TypeAnnotationParsingOptions::NO_OPTS); + auto *overloadDef = AllocNode(overloadName->Clone(Allocator(), nullptr)->AsExpression(), + modifiers, Allocator()); + + auto startLoc = Lexer()->GetToken().Start(); + if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) { + // TODO add error message + LogError(diagnostic::TYPE_ALIAS_INVALID_NAME); + } + ArenaVector overloads(Allocator()->Adapter()); + lexer::SourcePosition endLoc; + auto parseElement = [this, &overloads, overloadDef]() { + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + LogExpectedToken(lexer::TokenType::LITERAL_IDENT); + } + + auto *identifier = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + identifier->SetParent(overloadDef); + identifier->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + + overloads.push_back(identifier); + return true; + }; + + ParseList(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::NONE, parseElement, &endLoc, true); + overloadDef->SetOverloadIdentifiers(std::move(overloads)); + overloadDef->SetRange({startLoc, endLoc}); + return overloadDef; +} + ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags, ir::MethodDefinitionKind methodKind) { ir::Identifier *name = nullptr; @@ -1231,6 +1264,12 @@ ir::AstNode *ETSParser::ParseTypeLiteralOrInterfaceMember() auto readonlyTok = Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_READONLY); bool isReadonly = readonlyTok.has_value(); + if (Lexer()->TryEatTokenFromKeywordType(lexer::TokenType::KEYW_OVERLOAD)) { + auto *overloadDefinition = ParseInterfaceOverload(modifiers); + overloadDefinition->SetStart(startLoc); + return overloadDefinition; + } + if (nextCp == lexer::LEX_CHAR_LEFT_PAREN || nextCp == lexer::LEX_CHAR_LESS_THAN) { if (isReadonly) { LogError(diagnostic::READONLY_INTERFACE_METHOD, {}, startLoc); diff --git a/ets2panda/parser/ETSparserStatements.cpp b/ets2panda/parser/ETSparserStatements.cpp index 3a3bcf9294..7d49dba7ed 100644 --- a/ets2panda/parser/ETSparserStatements.cpp +++ b/ets2panda/parser/ETSparserStatements.cpp @@ -212,6 +212,9 @@ ir::Statement *ETSParser::ParseTopLevelDeclStatement(StatementParsingFlags flags result = ParseTopLevelAnnotation(memberModifiers); break; case lexer::TokenType::LITERAL_IDENT: { + if (Lexer()->TryEatTokenFromKeywordType(lexer::TokenType::KEYW_OVERLOAD)) { + return ParseOverloadDefinition(memberModifiers); + } if (IsNamespaceDecl()) { return ParseNamespaceStatement(memberModifiers); } diff --git a/ets2panda/test/ast/parser/ets/overload_class_method_test.ets b/ets2panda/test/ast/parser/ets/overload_class_method_test.ets new file mode 100644 index 0000000000..d7c13e94fd --- /dev/null +++ b/ets2panda/test/ast/parser/ets/overload_class_method_test.ets @@ -0,0 +1,43 @@ +/* + * 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 A{} +class B{} +class C{} +class TempAny{} + +class Test1 { + foo111(a: A): A { + return a; + } + foo112(a: B): B { + return a; + } + + foo113(a: C): C { + console.log(a) + return a; + } + overload foo{foo111,foo112,foo113} +} + +class Test2 { + foo111(a: A): A; + foo111(a: B): B; + foo111(a: C): C; + foo111(...args:TempAny[]):TempAny{ + return args[0]; + } +} diff --git a/ets2panda/test/ast/parser/ets/overload_global_function_our_style_test.ets b/ets2panda/test/ast/parser/ets/overload_global_function_our_style_test.ets new file mode 100644 index 0000000000..6f9b00587e --- /dev/null +++ b/ets2panda/test/ast/parser/ets/overload_global_function_our_style_test.ets @@ -0,0 +1,34 @@ +/* + * 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 A{} +class B{} +class C{} +class TempAny{} + + +function foo111(a: A): A { + return a; +} +function foo112(a: B): B { + return a; +} + +function foo113(a: C): C { + console.log(a) + return a; +} + +overload foo{ foo111, foo112, foo113 } diff --git a/ets2panda/test/ast/parser/ets/overload_global_function_ts_style_test.ets b/ets2panda/test/ast/parser/ets/overload_global_function_ts_style_test.ets new file mode 100644 index 0000000000..8dd9405000 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/overload_global_function_ts_style_test.ets @@ -0,0 +1,26 @@ +/* + * 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 A{} +class B{} +class C{} +class TempAny{} + +function foo111(a: A): A; +function foo111(a: B): B; +function foo111(a: C): C; +function foo111(...args: TempAny[]): TempAny { + return args[0]; +} diff --git a/ets2panda/test/ast/parser/ets/overload_interface_method_test.ets b/ets2panda/test/ast/parser/ets/overload_interface_method_test.ets new file mode 100644 index 0000000000..009db76adf --- /dev/null +++ b/ets2panda/test/ast/parser/ets/overload_interface_method_test.ets @@ -0,0 +1,34 @@ +/* + * 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 A{} +class B{} +class C{} +class TempAny{} + +interface Test1 { + foo111(a: A): A; + foo112(a: B): B; + foo113(a: C): C; + overload foo{foo111,foo112,foo113}; +} + +interface Test2 { + foo111(a: A): A; + foo111(a: B): B; + foo111(a: C): C; + foo111(...args:TempAny[]); +} + diff --git a/ets2panda/varbinder/variableFlags.h b/ets2panda/varbinder/variableFlags.h index 1177e71a30..de6c1db470 100644 --- a/ets2panda/varbinder/variableFlags.h +++ b/ets2panda/varbinder/variableFlags.h @@ -165,6 +165,7 @@ enum class VariableFlags : uint64_t { ANNOTATIONUSAGE = 1ULL << 34ULL, NAMESPACE = 1ULL << 35ULL, INIT_IN_STATIC_BLOCK = 1ULL << 36ULL, + OVERLOAD = 1ULL << 37ULL, HOIST_VAR = HOIST | VAR, CLASS_OR_INTERFACE = CLASS | INTERFACE, -- Gitee From bf17451b29e333cea5d53f02982081486da66922 Mon Sep 17 00:00:00 2001 From: zengzengran Date: Thu, 5 Jun 2025 20:03:55 +0800 Subject: [PATCH 03/14] Fix identifier variable of constructors and overload methods is nullptr --- .../compiler/lowering/scopesInit/scopesInitPhase.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 3827896da6..6a8af8fe39 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -1031,7 +1031,7 @@ void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Iden var->AddFlag(varbinder::VariableFlags::METHOD); methodName->SetVariable(var); } - // TODO constructor maybe other + // TODO constructor crete overload for optinal parameter, maybe other, for (auto *overload : method->Overloads()) { ES2PANDA_ASSERT((overload->Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) || (overload->Function()->Flags() & ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD)); @@ -1046,6 +1046,13 @@ void InitScopesPhaseETS::MaybeAddOverload(ir::MethodDefinition *method, ir::Iden auto *foundMethod = overloadMethodVariable->Declaration()->Node()->AsMethodDefinition(); overloadMethodVariable->Declaration()->BindNode(method); + method->Id()->SetVariable(overloadMethodVariable); + + // Before scopeinitphase, some overloads have been created for the optional constructor + for (auto *overload : method->Overloads()) { + overload->Id()->SetVariable(overloadMethodVariable); + overload->SetParent(overloadMethodVariable->Declaration()->Node()); + } // default params overloads for (auto *overload : foundMethod->Overloads()) { -- Gitee From 33f82fd5350255ab9cadb5513962c603fee0b9b4 Mon Sep 17 00:00:00 2001 From: zengzengran Date: Thu, 5 Jun 2025 22:38:54 +0800 Subject: [PATCH 04/14] modifier and export for overloaddefinition --- .../ets/topLevelStmts/importExportDecls.cpp | 5 +++ .../ets/topLevelStmts/importExportDecls.h | 1 + ets2panda/parser/ETSparserClasses.cpp | 3 +- ... overload_modifier_overloaddefinition.ets} | 39 ++++++++++++++----- 4 files changed, 38 insertions(+), 10 deletions(-) rename ets2panda/test/ast/parser/ets/{overload_test.ets => overload_modifier_overloaddefinition.ets} (56%) diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp index fd25d833a5..dcca3862b3 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp @@ -150,6 +150,11 @@ void ImportExportDecls::VisitFunctionDeclaration(ir::FunctionDeclaration *funcDe fieldMap_.emplace(funcDecl->Function()->Id()->Name(), funcDecl->Function()); } +void ImportExportDecls::VisitOverloadDefinition(ir::OverloadDefinition *overloadDefinition) +{ + fieldMap_.emplace(overloadDefinition->Id()->Name(), overloadDefinition); +} + void ImportExportDecls::VisitVariableDeclaration(ir::VariableDeclaration *varDecl) { for (const auto &decl : varDecl->Declarators()) { diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.h b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.h index f5b04f3f5b..fdf7e22038 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.h +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.h @@ -74,6 +74,7 @@ public: void PreMergeNamespaces(parser::Program *program); private: + void VisitOverloadDefinition(ir::OverloadDefinition *overloadDefinition) override; void VisitFunctionDeclaration(ir::FunctionDeclaration *funcDecl) override; void VisitVariableDeclaration(ir::VariableDeclaration *varDecl) override; void VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl) override; diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp index 8d8f0bdc64..5d4fdac402 100644 --- a/ets2panda/parser/ETSparserClasses.cpp +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -1433,7 +1433,8 @@ std::pair ETSParser::ParseMemberModifi } Lexer()->NextToken(); - if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) { + if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION && + Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_OVERLOAD) { // async_function_bas.ets if (isAsync) { LogError(diagnostic::ASYNC_FLAG_ONLY_FOR_TOP_FUN); diff --git a/ets2panda/test/ast/parser/ets/overload_test.ets b/ets2panda/test/ast/parser/ets/overload_modifier_overloaddefinition.ets similarity index 56% rename from ets2panda/test/ast/parser/ets/overload_test.ets rename to ets2panda/test/ast/parser/ets/overload_modifier_overloaddefinition.ets index d7c13e94fd..56b4187afa 100644 --- a/ets2panda/test/ast/parser/ets/overload_test.ets +++ b/ets2panda/test/ast/parser/ets/overload_modifier_overloaddefinition.ets @@ -19,25 +19,46 @@ class C{} class TempAny{} class Test1 { - foo111(a: A): A { + async foo111(a: A): A { return a; } - foo112(a: B): B { + async foo112(a: B): B { return a; } - foo113(a: C): C { + async foo113(a: C): C { console.log(a) return a; } - overload foo{foo111,foo112,foo113} + async overload foo{foo111,foo112,foo113} } class Test2 { - foo111(a: A): A; - foo111(a: B): B; - foo111(a: C): C; - foo111(...args:TempAny[]):TempAny{ - return args[0]; + static foo111(a: A): A { + return a; + } + static foo112(a: B): B { + return a; + } + + static foo113(a: C): C { + console.log(a) + return a; + } + static overload foo{foo111,foo112,foo113} +} + +class Test3 { + private foo111(a: A): A { + return a; + } + private foo112(a: B): B { + return a; + } + + private foo113(a: C): C { + console.log(a) + return a; } + private overload foo{foo111,foo112,foo113} } -- Gitee From a412975718100e36423c584a32ee4ce1ba18cf14 Mon Sep 17 00:00:00 2001 From: tengtengh Date: Fri, 6 Jun 2025 10:24:30 +0800 Subject: [PATCH 05/14] forbid use OverloadDefinition::overloads_ --- ets2panda/ir/base/overloadDefinition.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ets2panda/ir/base/overloadDefinition.h b/ets2panda/ir/base/overloadDefinition.h index 3c3b12fb00..09226136da 100644 --- a/ets2panda/ir/base/overloadDefinition.h +++ b/ets2panda/ir/base/overloadDefinition.h @@ -50,10 +50,12 @@ public: overloadIdentifiers_ = std::move(overloadIdentifiers); } - void SetOverloads(ArenaVector overloads) - { - overloads_ = std::move(overloads); - } + // TODO please don't use it first, consider deleting `overloads_` later. + // void SetOverloads(ArenaVector overloads) + // { + // ES2PANDA_UNREACHABLE(); // please don't use it first + // // overloads_ = std::move(overloads); + // } void AddOverloads(MethodDefinition *overload) { @@ -76,6 +78,7 @@ public: } private: + // TODO please don't use `overloads_` first, consider deleting `overloads_` later. ArenaVector overloads_; ArenaVector overloadIdentifiers_; }; -- Gitee From fd494232b107f819b0aa7425b6a58f155673d33a Mon Sep 17 00:00:00 2001 From: tengtengh Date: Fri, 6 Jun 2025 10:32:05 +0800 Subject: [PATCH 06/14] remove overloadDefinition::overloads_ field Signed-off-by: tengtengh --- ets2panda/ir/base/overloadDefinition.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ets2panda/ir/base/overloadDefinition.h b/ets2panda/ir/base/overloadDefinition.h index 09226136da..bceb82a1e5 100644 --- a/ets2panda/ir/base/overloadDefinition.h +++ b/ets2panda/ir/base/overloadDefinition.h @@ -40,10 +40,11 @@ public: return overloadIdentifiers_; } - [[nodiscard]] ArenaVector &GetOverloads() noexcept - { - return overloads_; - } + // TODO please don't use it first, consider deleting `overloads_` later. + // [[nodiscard]] ArenaVector &GetOverloads() noexcept + // { + // return overloads_; + // } void SetOverloadIdentifiers(ArenaVector overloadIdentifiers) { @@ -57,10 +58,11 @@ public: // // overloads_ = std::move(overloads); // } - void AddOverloads(MethodDefinition *overload) - { - overloads_.push_back(overload); - } + // TODO please don't use it first, consider deleting `overloads_` later. + // void AddOverloads(MethodDefinition *overload) + // { + // overloads_.push_back(overload); + // } void ResolveReferences(const NodeTraverser &cb) const; @@ -79,7 +81,7 @@ public: private: // TODO please don't use `overloads_` first, consider deleting `overloads_` later. - ArenaVector overloads_; + // ArenaVector overloads_; ArenaVector overloadIdentifiers_; }; } // namespace ark::es2panda::ir -- Gitee From ceafe1818ab0bc64711c6ddaa72cd2b35b5bc707 Mon Sep 17 00:00:00 2001 From: tengtengh Date: Fri, 6 Jun 2025 10:35:30 +0800 Subject: [PATCH 07/14] remove overloadDefinition::overloads_ field 2 Signed-off-by: tengtengh --- ets2panda/ir/base/overloadDefinition.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ets2panda/ir/base/overloadDefinition.h b/ets2panda/ir/base/overloadDefinition.h index bceb82a1e5..3900528cde 100644 --- a/ets2panda/ir/base/overloadDefinition.h +++ b/ets2panda/ir/base/overloadDefinition.h @@ -30,7 +30,7 @@ public: explicit OverloadDefinition(Expression *const key, ModifierFlags const modifiers, ArenaAllocator *const allocator) : ClassElement(AstNodeType::OVERLOAD_DEFINITION, key, nullptr, modifiers, allocator, false), - overloads_(allocator->Adapter()), + // overloads_(allocator->Adapter()), overloadIdentifiers_(allocator->Adapter()) { } -- Gitee From 62630fc99e3fb71f46d8c7a7133ea9a9a411df52 Mon Sep 17 00:00:00 2001 From: tengtengh Date: Fri, 6 Jun 2025 10:57:34 +0800 Subject: [PATCH 08/14] remove overloadDefinition::overloads_ field 3 Signed-off-by: tengtengh --- ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp | 2 +- ets2panda/ir/base/overloadDefinition.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 6a8af8fe39..2819d07a6d 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -1110,7 +1110,7 @@ void InitScopesPhaseETS::DeclareClassOverload(ir::OverloadDefinition *overloadDe variable->Declaration()->Type()); continue; } - overloadDef->AddOverloads(method); + // overloadDef->AddOverloads(method); method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); methodName->SetVariable(found); } diff --git a/ets2panda/ir/base/overloadDefinition.cpp b/ets2panda/ir/base/overloadDefinition.cpp index ccd4444143..b66a8b9619 100644 --- a/ets2panda/ir/base/overloadDefinition.cpp +++ b/ets2panda/ir/base/overloadDefinition.cpp @@ -56,7 +56,7 @@ void OverloadDefinition::Dump(ir::AstDumper *dumper) const {"key", key_}, {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(flags_))}, {"static", IsStatic()}, - {"overloads", overloads_}, + // {"overloads", overloads_}, {"overloadidentifiers", overloadIdentifiers_}}); } // TODO SrcDumper for OverloadDefinition -- Gitee From a7237db997b4d9f75b42c3954ce64636bb2a3ec7 Mon Sep 17 00:00:00 2001 From: zengzengran Date: Fri, 6 Jun 2025 19:37:24 +0800 Subject: [PATCH 09/14] parser constructor Notice:overload constructor identifier is constructorOverloadDefinition instead of constructor --- .../lowering/scopesInit/scopesInitPhase.cpp | 12 ++++- ets2panda/compiler/scripts/signatures.yaml | 4 ++ ets2panda/ir/base/overloadDefinition.cpp | 2 +- ets2panda/ir/base/overloadDefinition.h | 15 ++++-- ets2panda/parser/ETSparser.cpp | 12 +++-- ets2panda/parser/ETSparserClasses.cpp | 15 ++++-- .../ast/parser/ets/overload_constructor.ets | 49 +++++++++++++++++++ 7 files changed, 97 insertions(+), 12 deletions(-) create mode 100644 ets2panda/test/ast/parser/ets/overload_constructor.ets diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 2819d07a6d..8ae41cdbc8 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -1083,11 +1083,19 @@ void InitScopesPhaseETS::DeclareClassOverload(ir::OverloadDefinition *overloadDe } varbinder::LocalScope *targetScope {}; - if (overloadDef->IsStatic()) { + if (overloadDef->IsConstructorOverloadDefinition()) { targetScope = clsScope->StaticMethodScope(); + + auto *found = targetScope->FindLocal(Signatures::CONSTRUCTOR_NAME, varbinder::ResolveBindingOptions::BINDINGS); + if (found != nullptr) { + ir::Identifier *anonyConstructor = + Allocator()->New(Signatures::CONSTRUCTOR_NAME, Allocator()); + overloadDef->PushFront(anonyConstructor); + } } else { - targetScope = clsScope->InstanceMethodScope(); + targetScope = overloadDef->IsStatic() ? clsScope->StaticMethodScope() : clsScope->InstanceMethodScope(); } + for (auto *methodName : overloadDef->GetOverloadIdentifiers()) { auto *found = targetScope->FindLocal(methodName->AsIdentifier()->Name(), varbinder::ResolveBindingOptions::BINDINGS); diff --git a/ets2panda/compiler/scripts/signatures.yaml b/ets2panda/compiler/scripts/signatures.yaml index ba71dc0e6c..f10f337aa0 100644 --- a/ets2panda/compiler/scripts/signatures.yaml +++ b/ets2panda/compiler/scripts/signatures.yaml @@ -222,6 +222,10 @@ defines: comment: ETS annotation type - name: 'use static' ref: STATIC_PROGRAM_FLAG + - name: 'constructor' + ref: CONSTRUCTOR_NAME + - name: 'constructorOverloadDefinition' + ref: CONSTRUCTOR_OVERLOAD_DEFINITION_NAME packages: - name: 'std.core' diff --git a/ets2panda/ir/base/overloadDefinition.cpp b/ets2panda/ir/base/overloadDefinition.cpp index b66a8b9619..36316e9cc5 100644 --- a/ets2panda/ir/base/overloadDefinition.cpp +++ b/ets2panda/ir/base/overloadDefinition.cpp @@ -37,7 +37,7 @@ void OverloadDefinition::TransformChildren(const NodeTransformer &cb, std::strin for (auto *&it : VectorIterationGuard(overloadIdentifiers_)) { if (auto *transformedNode = cb(it); it != transformedNode) { it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsMethodDefinition(); + it = transformedNode->AsIdentifier(); } } } diff --git a/ets2panda/ir/base/overloadDefinition.h b/ets2panda/ir/base/overloadDefinition.h index 3900528cde..452f6d5317 100644 --- a/ets2panda/ir/base/overloadDefinition.h +++ b/ets2panda/ir/base/overloadDefinition.h @@ -35,7 +35,7 @@ public: { } - [[nodiscard]] ArenaVector &GetOverloadIdentifiers() noexcept + [[nodiscard]] ArenaVector &GetOverloadIdentifiers() noexcept { return overloadIdentifiers_; } @@ -46,11 +46,20 @@ public: // return overloads_; // } - void SetOverloadIdentifiers(ArenaVector overloadIdentifiers) + void PushFront(Identifier *overloadIdentifier) + { + overloadIdentifiers_.insert(overloadIdentifiers_.begin(), overloadIdentifier); + } + + void SetOverloadIdentifiers(ArenaVector overloadIdentifiers) { overloadIdentifiers_ = std::move(overloadIdentifiers); } + [[nodiscard]] bool IsConstructorOverloadDefinition(){ + return (flags_ & ModifierFlags::CONSTRUCTOR) != 0; + } + // TODO please don't use it first, consider deleting `overloads_` later. // void SetOverloads(ArenaVector overloads) // { @@ -82,7 +91,7 @@ public: private: // TODO please don't use `overloads_` first, consider deleting `overloads_` later. // ArenaVector overloads_; - ArenaVector overloadIdentifiers_; + ArenaVector overloadIdentifiers_; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 895184dfdd..2b0dc25d4d 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -580,9 +580,15 @@ ir::AstNode *ETSParser::ParseInnerConstructorDeclaration(ir::ModifierFlags membe 0) { LogError(diagnostic::INVALID_DECORATOR_CONSTRUCTOR); } - auto *memberName = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + + lexer::Token constructorToken = Lexer()->GetToken(); + Lexer()->TryEatTokenType(lexer::TokenType::KEYW_CONSTRUCTOR); memberModifiers |= ir::ModifierFlags::CONSTRUCTOR; - Lexer()->NextToken(); + + ir::Identifier *memberName = Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT + ? ExpectIdentifier(false, true) + : AllocNode(constructorToken.Ident(), Allocator()); + auto *classMethod = ParseClassMethodDefinition(memberName, memberModifiers, isDefault); classMethod->SetStart(startLoc); @@ -2112,7 +2118,7 @@ ir::OverloadDefinition *ETSParser::ParseOverloadDefinition(ir::ModifierFlags mod // TODO add error message LogError(diagnostic::TYPE_ALIAS_INVALID_NAME); } - ArenaVector overloads(Allocator()->Adapter()); + ArenaVector overloads(Allocator()->Adapter()); lexer::SourcePosition endLoc; auto parseElement = [this, &overloads, overloadDef]() { if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp index 5d4fdac402..24dc8b8e43 100644 --- a/ets2panda/parser/ETSparserClasses.cpp +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -536,7 +536,16 @@ void ETSParser::ParseClassFieldDefinition(ir::Identifier *fieldName, ir::Modifie ir::OverloadDefinition *ETSParser::ParseClassOverloadDefinition(ir::ModifierFlags modifiers) { - auto *overloadName = ExpectIdentifier(false, true, TypeAnnotationParsingOptions::NO_OPTS); + ir::Identifier *overloadName = nullptr; + //TODO NOTICE:overload constructor name is "constructorOverloadDefinition" + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CONSTRUCTOR) { + overloadName = AllocNode(compiler::Signatures::CONSTRUCTOR_OVERLOAD_DEFINITION_NAME, Allocator()); + modifiers |= ir::ModifierFlags::CONSTRUCTOR; + Lexer()->NextToken(); + } else { + overloadName = ExpectIdentifier(false, true, TypeAnnotationParsingOptions::NO_OPTS); + } + auto *overloadDef = AllocNode(overloadName->Clone(Allocator(), nullptr)->AsExpression(), modifiers, Allocator()); @@ -545,7 +554,7 @@ ir::OverloadDefinition *ETSParser::ParseClassOverloadDefinition(ir::ModifierFlag // TODO add error message LogError(diagnostic::TYPE_ALIAS_INVALID_NAME); } - ArenaVector overloads(Allocator()->Adapter()); + ArenaVector overloads(Allocator()->Adapter()); lexer::SourcePosition endLoc; auto parseElement = [this, &overloads, overloadDef]() { if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { @@ -1118,7 +1127,7 @@ ir::OverloadDefinition *ETSParser::ParseInterfaceOverload(ir::ModifierFlags modi // TODO add error message LogError(diagnostic::TYPE_ALIAS_INVALID_NAME); } - ArenaVector overloads(Allocator()->Adapter()); + ArenaVector overloads(Allocator()->Adapter()); lexer::SourcePosition endLoc; auto parseElement = [this, &overloads, overloadDef]() { if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { diff --git a/ets2panda/test/ast/parser/ets/overload_constructor.ets b/ets2panda/test/ast/parser/ets/overload_constructor.ets new file mode 100644 index 0000000000..9bc26d275b --- /dev/null +++ b/ets2panda/test/ast/parser/ets/overload_constructor.ets @@ -0,0 +1,49 @@ +/* + * 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 A{} +class B{} +class C{} +class TempAny{} + +class Test1 { + constructor fromA(a:A){} + constructor fromB(a:B){} + constructor fromC(a:C){} + + overload constructor {fromA,fromB,fromC} +} + +class Test2 { + constructor(){} + constructor fromA(a:A){} + constructor fromB(a:B){} + + overload constructor {fromA,fromB} +} + +class Test3 { + constructor() + constructor(a:A) + constructor(a:B) + constructor(...args:any){} +} + +class Test4 { + constructor con() + constructor con(a:A) + constructor con(a:B) + constructor con(...args:any){} +} -- Gitee From ac197aaa1bf05b6e877632b83231c57006e8b0ce Mon Sep 17 00:00:00 2001 From: tengtengh Date: Sat, 7 Jun 2025 19:24:00 +0800 Subject: [PATCH 10/14] checker ts-style overload declaration, TODO:static Signed-off-by: tengtengh --- ets2panda/checker/ETSAnalyzer.cpp | 63 +++++++++++++- ets2panda/checker/ets/object.cpp | 82 ++++++++++++------- .../compiler/lowering/ets/lambdaLowering.cpp | 15 +++- .../lowering/scopesInit/scopesInitPhase.cpp | 4 +- ets2panda/ir/base/overloadDefinition.h | 2 +- .../overload_different_access_modifier1.ets | 33 ++++++++ .../overload_different_access_modifier2.ets | 33 ++++++++ .../overload_different_access_modifier3.ets | 32 ++++++++ .../overload_different_access_modifier4.ets | 33 ++++++++ .../overload/overload_duplicate_method.ets | 35 ++++++++ ...erload_qualified_name_must_be_function.ets | 33 ++++++++ ets2panda/util/diagnostic/semantic.yaml | 16 ++++ 12 files changed, 343 insertions(+), 38 deletions(-) create mode 100644 ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier1.ets create mode 100644 ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier2.ets create mode 100644 ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier3.ets create mode 100644 ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier4.ets create mode 100644 ets2panda/test/ast/compiler/ets/overload/overload_duplicate_method.ets create mode 100644 ets2panda/test/ast/compiler/ets/overload/overload_qualified_name_must_be_function.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index c3c2614031..b54352bb11 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -302,12 +302,69 @@ void ETSAnalyzer::CheckMethodModifiers(ir::MethodDefinition *node) const node->SetTsType(checker->GlobalTypeError()); } } + +static void CheckDuplicationInOverloadDeclaration(ETSChecker *const checker, ir::OverloadDefinition *const node) +{ + auto set = ArenaSet(checker->ProgramAllocator()->Adapter()); + for (ir::Identifier *const id : node->OverloadIdentifiers()) { + if (set.find(id->Name()) != set.end()) { + checker->LogError(diagnostic::METHOD_ONLY_ONCE_IN_OVERLOAD, {id->Name()}, id->Start()); + } else { + set.insert(id->Name()); + } + } +} + +static bool CheckAccessModifierForOverloadDeclaration(const ir::ModifierFlags &overLoadAliasFlags, const ir::ModifierFlags &identFlags) +{ + static ir::ModifierFlags checkedModifiers = ir::ModifierFlags::PROTECTED | ir::ModifierFlags::PRIVATE | ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC; + return (overLoadAliasFlags ^ identFlags) & checkedModifiers; +} + + + // TODO check OverloadDefinition -checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::OverloadDefinition *node) const +checker::Type *ETSAnalyzer::Check(ir::OverloadDefinition *node) const { ETSChecker *checker = GetETSChecker(); - ES2PANDA_ASSERT(node); - return checker->GlobalTypeError(); + ES2PANDA_ASSERT(node != nullptr); + ES2PANDA_ASSERT(node->Key()); + + auto *funcType = checker->CreateETSMethodType(node->Key()->AsIdentifier()->Name(), {{}, checker->ProgramAllocator()->Adapter()}); + + if (!node->Key()->IsIdentifier()) { + checker->LogError(diagnostic::OVERLOAD_NAME_MUST_BE_IDENTIFIER, {}, node->Key()->Start()); + return checker->GlobalTypeError(); + } + + CheckDuplicationInOverloadDeclaration(checker, node); + + for (auto *ident : node->OverloadIdentifiers()) { + Type* identType = checker->ResolveIdentifier(ident); + identType->AddTypeFlag(TypeFlag::ETS_METHOD); + ident->SetTsType(identType); + + auto *identDeclNode = ident->Variable()->Declaration()->Node(); + if(!identDeclNode->IsMethodDefinition()) { + checker->LogError(diagnostic::OVERLOAD_QUALIFIED_NAME_MUST_FUNCTION, {}, ident->Start()); + continue; + } + + Type *type = identDeclNode->AsMethodDefinition()->TsType(); + ES2PANDA_ASSERT(type->IsETSFunctionType()); + for (auto s: type->AsETSFunctionType()->CallSignatures()) { + funcType->AddCallSignature(s); + } + + if (CheckAccessModifierForOverloadDeclaration(node->Modifiers(), identDeclNode->Modifiers())) { + checker->LogError(diagnostic::OVERLOAD_SAME_ACCESS_MODIFIERS, {}, ident->Start()); + } + + } + + node->SetTsType(funcType); + + return funcType; } checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Property *expr) const diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index b656a25717..fa71c5d10a 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -549,49 +549,65 @@ static void ResolveDeclaredMethodsOfObject(ETSChecker *checker, const ETSObjectT { for (auto &[_, it] : scope->InstanceMethodScope()->Bindings()) { (void)_; - auto *method = it->Declaration()->Node()->AsMethodDefinition(); - auto *function = method->Function(); - if (function->IsProxy()) { - continue; - } + if (it->Declaration()->Node()->IsMethodDefinition()) { + auto *method = it->Declaration()->Node()->AsMethodDefinition(); + auto *function = method->Function(); + + if (function->IsProxy()) { + continue; + } - it->AddFlag(checker->GetAccessFlagFromNode(method)); - auto *funcType = checker->BuildMethodSignature(method); - if (!funcType->IsTypeError()) { - funcType->SetVariable(it); + it->AddFlag(checker->GetAccessFlagFromNode(method)); + auto *funcType = checker->BuildMethodSignature(method); + if (!funcType->IsTypeError()) { + funcType->SetVariable(it); + } + it->SetTsType(funcType); + method->SetTsType(funcType); + type->AddProperty(it->AsLocalVariable()); + } else if (it->Declaration()->Node()->IsOverloadDefinition()) { + auto *method = it->Declaration()->Node()->AsOverloadDefinition(); + auto *overloadDef = it->Declaration()->Node()->AsOverloadDefinition(); + Type *funcType = overloadDef->Check(checker); + if (!funcType->IsTypeError()) { + funcType->SetVariable(it); + } + it->SetTsType(funcType); + method->SetTsType(funcType); + type->AddProperty(it->AsLocalVariable()); + } else { + ES2PANDA_UNREACHABLE(); } - it->SetTsType(funcType); - method->SetTsType(funcType); - type->AddProperty(it->AsLocalVariable()); } for (auto &[_, it] : scope->StaticMethodScope()->Bindings()) { (void)_; - if (!it->Declaration()->Node()->IsMethodDefinition()) { - continue; - } + if (it->Declaration()->Node()->IsMethodDefinition()) { + auto *method = it->Declaration()->Node()->AsMethodDefinition(); + auto *function = method->Function(); - auto *method = it->Declaration()->Node()->AsMethodDefinition(); - auto *function = method->Function(); + if (function->IsProxy()) { + continue; + } - if (function->IsProxy()) { - continue; - } + it->AddFlag(checker->GetAccessFlagFromNode(method)); + auto *funcType = checker->BuildMethodSignature(method); + if (!funcType->IsTypeError()) { + funcType->SetVariable(it); + } + it->SetTsType(funcType); + method->SetTsType(funcType); - it->AddFlag(checker->GetAccessFlagFromNode(method)); - auto *funcType = checker->BuildMethodSignature(method); - if (!funcType->IsTypeError()) { - funcType->SetVariable(it); - } - it->SetTsType(funcType); - method->SetTsType(funcType); + if (method->IsConstructor() && funcType->IsETSFunctionType()) { + type->AddConstructSignature(funcType->AsETSFunctionType()->CallSignatures()); + continue; + } - if (method->IsConstructor() && funcType->IsETSFunctionType()) { - type->AddConstructSignature(funcType->AsETSFunctionType()->CallSignatures()); - continue; + type->AddProperty(it->AsLocalVariable()); + } else if (it->Declaration()->Node()->IsOverloadDefinition()) { + // TODO static } - type->AddProperty(it->AsLocalVariable()); } } @@ -893,6 +909,10 @@ void ETSChecker::CheckInterfaceFunctions(ETSObjectType *classType) for (auto *const &interface : interfaces) { for (auto *const &prop : interface->Methods()) { + // TODO recheck whether it should be passed. + if (prop->Declaration()->Node()->IsOverloadDefinition()) { + continue; + } ir::MethodDefinition *node = prop->Declaration()->Node()->AsMethodDefinition(); if (prop->TsType()->IsTypeError()) { continue; diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index d3ad50c52a..784abc915c 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -1212,6 +1212,18 @@ static bool IsEnumFunctionCall(const ir::Identifier *const id) return false; } +static bool IsOverLoadDefineBody(ir::Identifier *const id) +{ + if (id->Parent() != nullptr && id->Parent()->IsOverloadDefinition()) { + for (ir::Identifier *const ident : id->Parent()->AsOverloadDefinition()->OverloadIdentifiers()) { + if (ident == id) { + return true; + } + } + } + return false; +} + static bool IsValidFunctionDeclVar(const varbinder::Variable *const var) { // Note: If a function is accessor, then no need to build lambda class. @@ -1231,7 +1243,8 @@ static ir::AstNode *BuildLambdaClassWhenNeeded(public_lib::Context *ctx, ir::Ast // We are running this lowering only for ETS files // so it is correct to pass ETS extension here to isReference() if (id->IsReference(ScriptExtension::ETS) && id->TsType() != nullptr && id->TsType()->IsETSFunctionType() && - !IsInCalleePosition(id) && !IsEnumFunctionCall(id) && IsValidFunctionDeclVar(var)) { + !IsInCalleePosition(id) && !IsEnumFunctionCall(id) && !IsOverLoadDefineBody(id) && + IsValidFunctionDeclVar(var)) { return ConvertFunctionReference(ctx, id); } } diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 8ae41cdbc8..fdeeb17b09 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -1095,8 +1095,7 @@ void InitScopesPhaseETS::DeclareClassOverload(ir::OverloadDefinition *overloadDe } else { targetScope = overloadDef->IsStatic() ? clsScope->StaticMethodScope() : clsScope->InstanceMethodScope(); } - - for (auto *methodName : overloadDef->GetOverloadIdentifiers()) { + for (auto *methodName : overloadDef->OverloadIdentifiers()) { auto *found = targetScope->FindLocal(methodName->AsIdentifier()->Name(), varbinder::ResolveBindingOptions::BINDINGS); // TODO method not found; @@ -1120,6 +1119,7 @@ void InitScopesPhaseETS::DeclareClassOverload(ir::OverloadDefinition *overloadDe } // overloadDef->AddOverloads(method); method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); + methodName->SetVariable(found); } diff --git a/ets2panda/ir/base/overloadDefinition.h b/ets2panda/ir/base/overloadDefinition.h index 452f6d5317..b2af6fbd51 100644 --- a/ets2panda/ir/base/overloadDefinition.h +++ b/ets2panda/ir/base/overloadDefinition.h @@ -35,7 +35,7 @@ public: { } - [[nodiscard]] ArenaVector &GetOverloadIdentifiers() noexcept + [[nodiscard]] ArenaVector &OverloadIdentifiers() noexcept { return overloadIdentifiers_; } diff --git a/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier1.ets b/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier1.ets new file mode 100644 index 0000000000..c3643e3679 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier1.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. + */ + +class A{} +class B{} +class C{} +class TempAny{} + +class Test1 { + foo111(a: A): A { + return a; + } + foo112(a: B): B { + return a; + } + + private overload foo{/* @@ label1 */foo111,/* @@ label2 */foo112} +} + +/* @@@ label1 Error TypeError: Overload alias and overload method must have exactly the same modifiers (public, private, protected, and static) */ +/* @@@ label2 Error TypeError: Overload alias and overload method must have exactly the same modifiers (public, private, protected, and static) */ diff --git a/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier2.ets b/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier2.ets new file mode 100644 index 0000000000..829ce95522 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier2.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. + */ + +class A{} +class B{} +class C{} +class TempAny{} + +class Test1 { + foo111(a: A): A { + return a; + } + foo112(a: B): B { + return a; + } + + protected overload foo{/* @@ label1 */foo111,/* @@ label2 */foo112} +} + +/* @@@ label1 Error TypeError: Overload alias and overload method must have exactly the same modifiers (public, private, protected, and static) */ +/* @@@ label2 Error TypeError: Overload alias and overload method must have exactly the same modifiers (public, private, protected, and static) */ diff --git a/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier3.ets b/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier3.ets new file mode 100644 index 0000000000..c276eede32 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier3.ets @@ -0,0 +1,32 @@ +/* + * 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 A{} +class B{} +class C{} +class TempAny{} + +class Test1 { + private foo111(a: A): A { + return a; + } + protected foo112(a: B): B { + return a; + } + + private overload foo{/* @@ label1 */foo111,/* @@ label2 */foo112} +} + +/* @@@ label2 Error TypeError: Overload alias and overload method must have exactly the same modifiers (public, private, protected, and static) */ diff --git a/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier4.ets b/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier4.ets new file mode 100644 index 0000000000..6cf01c7ded --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/overload/overload_different_access_modifier4.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. + */ + +class A{} +class B{} +class C{} +class TempAny{} + +class Test1 { + public foo111(a: A): A { + return a; + } + public foo112(a: B): B { + return a; + } + + private overload foo{/* @@ label1 */foo111,/* @@ label2 */foo112} +} + +/* @@@ label1 Error TypeError: Overload alias and overload method must have exactly the same modifiers (public, private, protected, and static) */ +/* @@@ label2 Error TypeError: Overload alias and overload method must have exactly the same modifiers (public, private, protected, and static) */ diff --git a/ets2panda/test/ast/compiler/ets/overload/overload_duplicate_method.ets b/ets2panda/test/ast/compiler/ets/overload/overload_duplicate_method.ets new file mode 100644 index 0000000000..490761ec0f --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/overload/overload_duplicate_method.ets @@ -0,0 +1,35 @@ +/* + * 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 A{} +class B{} +class C{} +class TempAny{} + +class Test1 { + foo111(a: A): A { + return a; + } + foo112(a: B): B { + return a; + } + + foo113(a: C): C { + return a; + } + overload foo{foo111,foo112,foo113,foo111} +} + +/* @@? 32:39 Error TypeError: Method 'foo111' can appear at most once in method declaration */ diff --git a/ets2panda/test/ast/compiler/ets/overload/overload_qualified_name_must_be_function.ets b/ets2panda/test/ast/compiler/ets/overload/overload_qualified_name_must_be_function.ets new file mode 100644 index 0000000000..5e564822a4 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/overload/overload_qualified_name_must_be_function.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. + */ + +class A{} +class B{} +class C{} +class TempAny{} + +class Test1 { + foo111: int = 1 + foo112(a: B): B { + return a; + } + + foo113(a: C): C { + return a; + } + overload foo{foo111,foo112,foo113} +} + +/* @@? 32:39 Error TypeError: Method 'foo111' can appear at most once in method declaration */ diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index 7565ace3dd..122145b5a6 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -1474,3 +1474,19 @@ semantic: - name: SUPER_NOT_ACCESSIBLE id: 372 message: "Class field '{}' defined by the parent class is not accessible in the child class via super." + +- name: OVERLOAD_NAME_MUST_BE_IDENTIFIER + id: 373 + message: "The name of overload declaration should be an identifier." + +- name: OVERLOAD_QUALIFIED_NAME_MUST_FUNCTION + id: 374 + message: "Qualified name '{}' must refer to an accessible function." + +- name: METHOD_ONLY_ONCE_IN_OVERLOAD + id: 375 + message: "Method '{}' can appear at most once in method declaration" + +- name: OVERLOAD_SAME_ACCESS_MODIFIERS + id: 376 + message: "Overload alias and overload method must have exactly the same modifiers (public, private, protected, and static)" -- Gitee From 1b19809aafa57110f7528f86aab9b982bb19ccc7 Mon Sep 17 00:00:00 2001 From: lixl9 Date: Sun, 8 Jun 2025 19:18:09 +0800 Subject: [PATCH 11/14] Generate overloaded bytecode --- ets2panda/compiler/core/ETSemitter.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index 8f0b822ef9..13cd8aea2e 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -284,6 +284,10 @@ void ETSEmitter::GenAnnotation() for (auto *signature : globalRecordTable->Signatures()) { auto *scriptFunc = signature->Node()->AsScriptFunction(); + const auto *methodDef = util::Helpers::GetContainingClassMethodDefinition(scriptFunc); + if (!methodDef->IsTsOverload() && methodDef->BaseOverloadMethod() != nullptr) { + continue; + } auto func = GenScriptFunction(scriptFunc, this); if (scriptFunc->IsDeclare()) { func.metadata->SetAttribute(Signatures::EXTERNAL); @@ -415,6 +419,9 @@ void ETSEmitter::EmitDefaultFieldValue(pandasm::Field &classField, const ir::Exp void ETSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external) { + if (!methodDef->IsTsOverload() && methodDef->BaseOverloadMethod() != nullptr) { + return; + } auto *scriptFunc = methodDef->Function(); auto func = GenScriptFunction(scriptFunc, this); -- Gitee From f3f6434accc9df6d5d81e511c2622834a51e668f Mon Sep 17 00:00:00 2001 From: tengtengh Date: Sun, 8 Jun 2025 19:53:55 +0800 Subject: [PATCH 12/14] Temporary: skip the error from stdlib Signed-off-by: tengtengh --- ets2panda/checker/checker.cpp | 3 +++ ets2panda/varbinder/ETSBinder.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ets2panda/checker/checker.cpp b/ets2panda/checker/checker.cpp index 39c4be1b59..ecc874603c 100644 --- a/ets2panda/checker/checker.cpp +++ b/ets2panda/checker/checker.cpp @@ -41,6 +41,9 @@ void Checker::Initialize(varbinder::VarBinder *varbinder) void Checker::LogError(const diagnostic::DiagnosticKind &diagnostic, const util::DiagnosticMessageParams &diagnosticParams, const lexer::SourcePosition &pos) { + if (pos.Program()->IsStdLib()) { + return; + } diagnosticEngine_.LogDiagnostic(diagnostic, diagnosticParams, pos); } diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index 577c250f17..90c9e86af5 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -1494,6 +1494,9 @@ bool ETSBinder::IsDynamicNamespaceVariable(const Variable *var) const noexcept void ETSBinder::ThrowError(const lexer::SourcePosition &pos, const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams ¶ms) const { + if (pos.Program()->IsStdLib()) { + return; + } GetContext()->diagnosticEngine->LogDiagnostic(kind, params, pos); } -- Gitee From 2db303088de3d9f88b18b9c074b8fa4eadc0221e Mon Sep 17 00:00:00 2001 From: Ocean Date: Fri, 6 Jun 2025 19:19:14 +0800 Subject: [PATCH 13/14] support declare overload process --- .../lowering/ets/declareOverloadLowering.cpp | 246 +++++++++++------- .../lowering/ets/declareOverloadLowering.h | 3 +- ets2panda/compiler/lowering/phase.cpp | 2 +- 3 files changed, 155 insertions(+), 96 deletions(-) diff --git a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp index 4033c033f3..5009c452f5 100644 --- a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp +++ b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp @@ -20,124 +20,182 @@ #include "util/options.h" namespace ark::es2panda::compiler { +static bool CheckFunctionSignature(ir::ScriptFunction *func) +{ + auto *returnTypeAnnotation = func->ReturnTypeAnnotation(); + if (returnTypeAnnotation == nullptr) { + return false; + } + if (returnTypeAnnotation->ToString() != "any") { + // If the function has a void return type, we do not need to build a signature implementation. + return false; + } + + auto ¶ms = func->Params(); + if (params.size() != 1 || !params.front()->IsSpreadElement()) { + // If the function has no type parameters, we do not need to build a signature implementation. + return false; + } + auto *param = params.front()->AsSpreadElement(); + if (param->TypeAnnotation() == nullptr || !(param->TypeAnnotation()->ToString() != "Any[]")) { + // If the function has no type parameters, we do not need to build a signature implementation. + return false; + } + + return true; +} -void GenerateOverloadHelperParams(public_lib::Context *ctx, uint32_t minArg, size_t maxArg, bool hasRestVar, - ArenaVector ¶ms) +static ir::TSTypeParameterDeclaration *CreateParameterDeclaraion(ir::MethodDefinition *method, public_lib::Context *ctx) { - auto *checker = ctx->GetChecker()->AsETSChecker(); - auto *allocator = ctx->allocator; - - if (!hasRestVar) { - for (size_t idx = 0; idx < maxArg; ++idx) { - auto *id = Gensym(allocator); - auto *typeAnnotation = ctx->AllocNode(checker->GlobalETSAnyType(), allocator); - id->SetTsTypeAnnotation(typeAnnotation); - typeAnnotation->SetParent(id); - auto *param = ctx->AllocNode(id, false, allocator); - param->SetOptional(idx >= minArg); - params.push_back(param); - } - return; + auto const allocator = ctx->allocator; + if (method->Function()->TypeParams() == nullptr || method->Function()->TypeParams()->Params().empty()) { + return nullptr; } - auto *restIdent = Gensym(allocator); - auto *spread = ctx->AllocNode(ir::AstNodeType::REST_ELEMENT, allocator, restIdent); - auto *arr = checker->CreateETSArrayType(checker->GlobalETSAnyType(), false); - auto *typeAnnotation = ctx->AllocNode(arr, allocator); + ArenaVector typeParams(allocator->Adapter()); + + auto parentParams = method->Function()->TypeParams()->Params(); + std::for_each(parentParams.begin(), parentParams.end(), [&typeParams, allocator](ir::TSTypeParameter *par) { + ir::Identifier *ident = par->Name()->Clone(allocator, nullptr)->AsIdentifier(); + auto *constraint = + par->Constraint() != nullptr ? par->Constraint()->Clone(allocator, nullptr)->AsTypeNode() : nullptr; + auto *defaultType = + par->DefaultType() != nullptr ? par->DefaultType()->Clone(allocator, nullptr)->AsTypeNode() : nullptr; + auto *typeParam = util::NodeAllocator::ForceSetParent(allocator, ident, constraint, + defaultType, allocator); + typeParams.push_back(typeParam); + }); + return util::NodeAllocator::ForceSetParent(allocator, std::move(typeParams), + typeParams.size()); +} + +static ir::FunctionSignature CreateFunctionSignature(ir::MethodDefinition *method, + ArenaVector funcParam, public_lib::Context *ctx) +{ + auto const allocator = ctx->allocator; - spread->SetTsTypeAnnotation(typeAnnotation); - spread->SetTsType(arr); - restIdent->SetTsType(arr); - auto *param = ctx->AllocNode(spread, nullptr, allocator); + ir::TSTypeParameterDeclaration *typeParamDecl = CreateParameterDeclaraion(method, ctx); + auto *returnTypeAnnotation = + method->Function()->ReturnTypeAnnotation() != nullptr + ? method->Function()->ReturnTypeAnnotation()->Clone(allocator, nullptr)->AsTypeNode() + : nullptr; - restIdent->SetParent(spread); - typeAnnotation->SetParent(spread); - spread->SetParent(param); - params.push_back(param); + return ir::FunctionSignature(typeParamDecl, std::move(funcParam), returnTypeAnnotation); } -void BuildOverloadHelperFunction(public_lib::Context *ctx, ir::MethodDefinition *method) +static ir::FunctionExpression *CreateAnyFunctionExpression(ir::MethodDefinition *method, public_lib::Context *ctx) { - auto *checker = ctx->GetChecker()->AsETSChecker(); - auto *allocator = ctx->allocator; - auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); - - auto const &[minArg, maxArg, needHelperOverload, isDeclare, hasRestVar, returnVoid] = method->GetOverloadInfo(); - ES2PANDA_ASSERT(needHelperOverload); - - auto params = ArenaVector(allocator->Adapter()); - GenerateOverloadHelperParams(ctx, minArg, maxArg, hasRestVar, params); - - auto *returnType = returnVoid ? checker->GlobalVoidType() : checker->GlobalETSAnyType(); - auto *returnAnno = ctx->AllocNode(returnType, allocator); - - ir::ScriptFunctionFlags functionFlag = method->Function()->Flags(); - auto *func = ctx->AllocNode( - allocator, - ir::ScriptFunction::ScriptFunctionData {nullptr, ir::FunctionSignature(nullptr, std::move(params), returnAnno), - functionFlag, method->Function()->Modifiers()}); - auto *methodId = ctx->AllocNode(method->Id()->Name(), allocator); - func->SetIdent(methodId); - auto *funcExpr = ctx->AllocNode(func); - auto *methodIdClone = methodId->Clone(allocator, nullptr); - auto *helperOverload = ctx->AllocNode(method->Kind(), methodIdClone, funcExpr, - method->Modifiers(), allocator, false); - - method->AddOverload(helperOverload); - helperOverload->Function()->ClearFlag((ir::ScriptFunctionFlags::OVERLOAD)); - helperOverload->SetParent(method); - - checker::SavedCheckerContext scc(checker, checker->Context().Status(), method->Function()->Signature()->Owner()); - Rebind(ctx->phaseManager, varBinder, helperOverload); - helperOverload->Function()->AddFlag((ir::ScriptFunctionFlags::OVERLOAD)); - auto funcScope = helperOverload->Function()->Scope(); - funcScope->BindName(method->Function()->Scope()->Name()); - - helperOverload->Function()->Id()->SetVariable(helperOverload->Id()->Variable()); - checker->BuildFunctionSignature(helperOverload->Function(), method->IsConstructor()); - - auto *const overloadType = checker->BuildMethodType(helperOverload->Function()); - helperOverload->SetTsType(overloadType); - - ES2PANDA_ASSERT(method->TsType()->IsETSFunctionType()); - method->TsType()->AsETSFunctionType()->SetHelperSignature(helperOverload->Function()->Signature()); + lexer::SourcePosition startLoc(method->Start()); + lexer::SourcePosition endLoc = startLoc; + ArenaVector args(ctx->allocator->Adapter()); + // tofix: The function signature for overloads is always `xxx(...p: any[]) => any` + auto *const anySpread = util::NodeAllocator::ForceSetParent( + ctx->allocator, ir::AstNodeType::REST_ELEMENT, ctx->allocator, + ctx->AllocNode("p", ctx->allocator)); + auto *const param = util::NodeAllocator::ForceSetParent( + ctx->allocator, anySpread, ctx->Allocator(), ctx->Allocator()); + anySpread->SetParent(param); + auto *const anyType = ctx->AllocNode(ir::PrimitiveType::INT, ctx->allocator); + auto *const anyArrayType = ctx->AllocNode(anyType, ctx->allocator); + anyType->SetParent(anyArrayType); + anyArrayType->SetParent(anySpread); + param->SetTypeAnnotation(anyArrayType); + args.push_back(param); + ir::FunctionSignature signature = CreateFunctionSignature(method, std::move(args), ctx); + + auto const allocator = ctx->allocator; + ir::Identifier *id = nullptr; + + auto *funcNode = util::NodeAllocator::ForceSetParent( + allocator, allocator, + ir::ScriptFunction::ScriptFunctionData { + nullptr, std::move(signature), method->Function()->Flags(), {}, method->Function()->Language()}); + funcNode->AddModifier(method->Function()->Modifiers()); + funcNode->SetRange({startLoc, endLoc}); + auto *const returnAnyType = ctx->AllocNode(ir::PrimitiveType::INT, ctx->allocator); + funcNode->SetReturnTypeAnnotation(returnAnyType); + returnAnyType->SetParent(funcNode); + + id = method->Id()->Clone(allocator, nullptr)->AsIdentifier(); + funcNode->SetIdent(id); + return util::NodeAllocator::ForceSetParent(allocator, funcNode); } -void UpdateCallSignature(public_lib::Context *ctx, ir::CallExpression *expr) +static void UpdateMethodParent(public_lib::Context *ctx, ir::MethodDefinition *method, ir::MethodDefinition *overloadMethod) { - ES2PANDA_ASSERT(expr->Signature()->HasSignatureFlag(checker::SignatureFlags::DUPLICATE_ASM)); + auto *parent = method->Parent(); + ArenaVector origBody {ctx->allocator->Adapter()}; + ES2PANDA_ASSERT(parent->IsClassDefinition() || parent->IsTSInterfaceBody()); + if (parent->IsClassDefinition()) { + auto *classParent = method->Parent()->AsClassDefinition(); + origBody = classParent->Body(); + } else { + auto *interfaceParent = method->Parent()->AsTSInterfaceBody(); + origBody = interfaceParent->Body(); + } - auto *checker = ctx->GetChecker()->AsETSChecker(); - expr->SetTsType(nullptr); - expr->Check(checker); + ArenaVector body {ctx->allocator->Adapter()}; + for (auto *child : origBody) { + if (child == method) { + body.push_back(overloadMethod); + } else { + body.push_back(child); + } + } + origBody.swap(body); +} + +static void BuildBaseFunctionSignature(public_lib::Context *ctx, ir::MethodDefinition *method) +{ + ES2PANDA_ASSERT(method->IsTsOverload()); + auto const allocator = ctx->allocator; + auto *funcExpression = CreateAnyFunctionExpression(method, ctx); + auto *ident = funcExpression->Function()->Id()->Clone(allocator, nullptr); + auto *const overloadMethod = util::NodeAllocator::ForceSetParent( + allocator, method->Kind(), ident, funcExpression, method->Modifiers(), allocator, false); + + overloadMethod->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); + overloadMethod->SetRange(funcExpression->Range()); + overloadMethod->SetParent(method->Parent()); + for (auto *overload : method->Overloads()) { + overload->SetBaseOverloadMethod(overloadMethod); + overload->SetParent(overloadMethod); + overloadMethod->AddOverload(overload); + } + method->SetBaseOverloadMethod(overloadMethod); + method->ClearOverloads(); + overloadMethod->AddOverload(method); + + UpdateMethodParent(ctx, method, overloadMethod); + method->SetParent(overloadMethod); + auto *scope = NearestScope(method->Parent()); + auto localCtx = + varbinder::LexicalScope::Enter(ctx->parserProgram->VarBinder()->AsETSBinder(), scope); + InitScopesPhaseETS::RunExternalNode(overloadMethod, ctx->parserProgram->VarBinder()); + overloadMethod->SetStart(method->Start()); +} + +static void TryBuildSignatureImplementation(public_lib::Context *ctx, ir::MethodDefinition *method) +{ + ES2PANDA_ASSERT(method->IsTsOverload()); + if (CheckFunctionSignature(method->Function())) { + return; + } + BuildBaseFunctionSignature(ctx, method); } bool DeclareOverloadLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - // Note: Generate helper overload method program->Ast()->TransformChildrenRecursively( [ctx](ir::AstNode *ast) { - if (ast->IsMethodDefinition() && ast->AsMethodDefinition()->GetOverloadInfo().needHelperOverload) { - BuildOverloadHelperFunction(ctx, ast->AsMethodDefinition()); + if (ast->IsMethodDefinition() && ast->AsMethodDefinition()->IsTsOverload()) { + TryBuildSignatureImplementation(ctx, ast->AsMethodDefinition()); + return ast->Parent(); } return ast; }, Name()); - // Note: Update signature for call expression - program->Ast()->TransformChildrenRecursively( - [ctx](ir::AstNode *ast) { - if (!ast->IsCallExpression() || ast->AsCallExpression()->Signature() == nullptr) { - return ast; - } - - if (ast->AsCallExpression()->Signature()->HasSignatureFlag(checker::SignatureFlags::DUPLICATE_ASM)) { - UpdateCallSignature(ctx, ast->AsCallExpression()); - } - - return ast; - }, - Name()); return true; } diff --git a/ets2panda/compiler/lowering/ets/declareOverloadLowering.h b/ets2panda/compiler/lowering/ets/declareOverloadLowering.h index 9842ce6b0c..df9a35eb42 100644 --- a/ets2panda/compiler/lowering/ets/declareOverloadLowering.h +++ b/ets2panda/compiler/lowering/ets/declareOverloadLowering.h @@ -20,7 +20,8 @@ namespace ark::es2panda::compiler { -class DeclareOverloadLowering : public PhaseForDeclarations { +// Currently, this phase limit to work on main program to help debug +class DeclareOverloadLowering : public PhaseForBodies { public: std::string_view Name() const override { diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 7525670200..38a1aef34b 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -113,6 +113,7 @@ std::vector GetETSPhaseList() new InterfacePropertyDeclarationsPhase, new ConstantExpressionLowering, new EnumLoweringPhase, + new DeclareOverloadLowering, new ResolveIdentifiers, new PluginPhase {g_pluginsAfterBind, ES2PANDA_STATE_BOUND, &util::Plugin::AfterBind}, new CapturedVariables, @@ -127,7 +128,6 @@ std::vector GetETSPhaseList() new AnnotationCopyPostLowering, new DynamicImportLowering, new AsyncMethodLowering, - new DeclareOverloadLowering, new EnumPostCheckLoweringPhase, new SpreadConstructionPhase, new RestArgsLowering, -- Gitee From 90866ffb8c3c720ff72ef715ff3eede8660586da Mon Sep 17 00:00:00 2001 From: zengzengran Date: Tue, 10 Jun 2025 09:47:26 +0800 Subject: [PATCH 14/14] CallExpression 1 --- ets2panda/BUILD.gn | 1 + ets2panda/CMakeLists.txt | 1 + ets2panda/checker/ETSAnalyzer.cpp | 14 +++- ets2panda/checker/checker.cpp | 3 + .../checker/types/ets/etsFunctionType.cpp | 6 +- ets2panda/checker/types/ets/etsFunctionType.h | 38 +++++++++++ ets2panda/checker/types/ets/etsObjectType.cpp | 33 ++++++--- ets2panda/checker/types/ets/etsObjectType.h | 6 +- .../lowering/ets/overloadMappingLoweing.cpp | 67 +++++++++++++++++++ .../lowering/ets/overloadMappingLoweing.h | 31 +++++++++ ets2panda/compiler/lowering/phase.cpp | 2 + ets2panda/ir/astNode.cpp | 4 +- ets2panda/ir/base/methodDefinition.h | 5 ++ ets2panda/ir/expressions/memberExpression.cpp | 1 + .../test/ast/parser/ets/overload_call.ets | 52 ++++++++++++++ .../parser/ets/overload_class_method_test.ets | 2 +- .../ast/parser/ets/overload_constructor.ets | 4 +- ...overload_global_function_ts_style_test.ets | 2 +- .../ets/overload_interface_method_test.ets | 2 +- 19 files changed, 249 insertions(+), 25 deletions(-) create mode 100644 ets2panda/compiler/lowering/ets/overloadMappingLoweing.cpp create mode 100644 ets2panda/compiler/lowering/ets/overloadMappingLoweing.h create mode 100644 ets2panda/test/ast/parser/ets/overload_call.ets diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 478d437fc8..b472662b4a 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -236,6 +236,7 @@ libes2panda_sources = [ "compiler/lowering/ets/opAssignment.cpp", "compiler/lowering/ets/optionalArgumentsLowering.cpp", "compiler/lowering/ets/optionalLowering.cpp", + "compiler/lowering/ets/overloadMappingLoweing.cpp", "compiler/lowering/ets/packageImplicitImport.cpp", "compiler/lowering/ets/partialExportClassGen.cpp", "compiler/lowering/ets/promiseVoid.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 26998fcb87..c6bbbb9aca 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -307,6 +307,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/unionLowering.cpp compiler/lowering/ets/optionalArgumentsLowering.cpp compiler/lowering/ets/optionalLowering.cpp + compiler/lowering/ets/overloadMappingLoweing.cpp compiler/lowering/ets/expandBrackets.cpp compiler/lowering/ets/packageImplicitImport.cpp compiler/lowering/ets/partialExportClassGen.cpp diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index b54352bb11..5e5c145af8 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -233,8 +233,9 @@ checker::Type *ETSAnalyzer::Check(ir::MethodDefinition *node) const } // NOTE: aszilagyi. make it correctly check for open function not have body - if (!scriptFunc->HasBody() && !(node->IsAbstract() || node->IsNative() || node->IsDeclare() || - checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) { + if (!scriptFunc->HasBody() && + !(node->IsAbstract() || node->IsNative() || node->IsDeclare() || node->IsTsOverloadSignatrue() || + checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) { checker->LogError(diagnostic::FUNCTION_WITHOUT_BODY, {}, scriptFunc->Start()); return returnErrorType(); } @@ -281,7 +282,8 @@ void ETSAnalyzer::CheckMethodModifiers(ir::MethodDefinition *node) const return; } - if ((node->IsAbstract() || (!node->Function()->HasBody() && !node->IsNative() && !node->IsDeclare())) && + if ((node->IsAbstract() || + (!node->Function()->HasBody() && !node->IsNative() && !node->IsDeclare() && !node->IsTsOverloadSignatrue())) && !(checker->HasStatus(checker::CheckerStatus::IN_ABSTRACT) || checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) { checker->LogError(diagnostic::ABSTRACT_IN_CONCRETE, {}, node->Start()); @@ -1471,6 +1473,7 @@ Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, Type *calleeType) con return checker->GlobalTypeError(); } + // TODO 对TS,设置signature和tstype,还需要过滤implement signature,calleeType设置了overload flag, 对java,暂时不变,后续lowering Signature *const signature = ResolveSignature(checker, expr, calleeType); if (signature == nullptr) { return checker->GlobalTypeError(); @@ -1606,6 +1609,11 @@ checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const } ES2PANDA_ASSERT(!expr->IsOptional()); + if (expr->Callee()->IsMemberExpression() && expr->Callee()->AsMemberExpression()->Property()->IsIdentifier() && + expr->Callee()->AsMemberExpression()->Property()->AsIdentifier()->Name() == "foo111") { + std::cout<<123<Callee(); checker::Type *calleeType = checker->GetApparentType(expr->Callee()->Check(checker)); if (calleeType->IsTypeError()) { diff --git a/ets2panda/checker/checker.cpp b/ets2panda/checker/checker.cpp index ecc874603c..733ffe4d5e 100644 --- a/ets2panda/checker/checker.cpp +++ b/ets2panda/checker/checker.cpp @@ -49,6 +49,9 @@ void Checker::LogError(const diagnostic::DiagnosticKind &diagnostic, void Checker::LogError(const diagnostic::DiagnosticKind &diagnostic, const lexer::SourcePosition &pos) { + if (pos.Program()->IsStdLib()) { + return; + } LogError(diagnostic, {}, pos); } diff --git a/ets2panda/checker/types/ets/etsFunctionType.cpp b/ets2panda/checker/types/ets/etsFunctionType.cpp index cb1fe63b87..792da37196 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -25,7 +25,8 @@ ETSFunctionType::ETSFunctionType([[maybe_unused]] ETSChecker *checker, util::Str callSignatures_(std::move(signatures)), extensionFunctionSigs_(ArenaVector(checker->ProgramAllocator()->Adapter())), extensionAccessorSigs_(ArenaVector(checker->ProgramAllocator()->Adapter())), - name_(name) + name_(name), + functionOverloadType_(FunctionOverloadType::NONE) { auto flag = TypeFlag::NONE; for (auto *sig : callSignatures_) { @@ -48,7 +49,8 @@ ETSFunctionType::ETSFunctionType(ETSChecker *checker, Signature *signature) name_(""), assemblerName_(checker->GlobalBuiltinFunctionType(signature->MinArgCount(), signature->HasRestParameter()) ->AsETSObjectType() - ->AssemblerName()) + ->AssemblerName()), + functionOverloadType_(FunctionOverloadType::NONE) { } diff --git a/ets2panda/checker/types/ets/etsFunctionType.h b/ets2panda/checker/types/ets/etsFunctionType.h index 14eea128aa..c559f127a7 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.h +++ b/ets2panda/checker/types/ets/etsFunctionType.h @@ -22,6 +22,13 @@ namespace ark::es2panda::checker { +enum class FunctionOverloadType { + NONE, + SINGLE_FUNCTION, + OVERLOAD_DEFINITION, + OVERLOAD_SIGNATURE, +}; + class ETSFunctionType : public Type { public: // create an "arrow" type @@ -159,6 +166,36 @@ public: return helperSignature_ != nullptr; } + bool SetFunctionOverloadType(FunctionOverloadType functionOverloadType) noexcept + { + if (functionOverloadType_ != FunctionOverloadType::NONE && functionOverloadType_ != functionOverloadType) { + return false; + } + + functionOverloadType_ = functionOverloadType; + return true; + } + + FunctionOverloadType GetFunctionOverloadType() const + { + return functionOverloadType_; + } + + bool IsSingleFunction() + { + return functionOverloadType_ == FunctionOverloadType::SINGLE_FUNCTION; + } + + bool IsOverloadDefinition() + { + return functionOverloadType_ == FunctionOverloadType::OVERLOAD_DEFINITION; + } + + bool IsOverloadSignatrue() + { + return functionOverloadType_ == FunctionOverloadType::OVERLOAD_SIGNATURE; + } + private: ArenaVector callSignatures_; ArenaVector extensionFunctionSigs_; @@ -166,6 +203,7 @@ private: util::StringView const name_; util::StringView const assemblerName_; Signature *helperSignature_ {}; + FunctionOverloadType functionOverloadType_; }; } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 61a6db0141..79ba597bfb 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -172,12 +172,14 @@ static void UpdateDeclarationForGetterSetter(varbinder::LocalVariable *res, cons } res->Reset(decl, var->Flags()); } - +//TODO varbinder::LocalVariable *ETSObjectType::CreateSyntheticVarFromEverySignature(const util::StringView &name, PropertySearchFlags flags) const { std::vector signatures; - varbinder::LocalVariable *functionalInterface = CollectSignaturesForSyntheticType(signatures, name, flags); + ETSFunctionType *funcType = CreateMethodTypeForProp(name); + varbinder::LocalVariable *functionalInterface = + CollectSignaturesForSyntheticType(signatures, name, flags, funcType); // #22952: the called function *always* returns nullptr ES2PANDA_ASSERT(functionalInterface == nullptr); (void)functionalInterface; @@ -189,7 +191,6 @@ varbinder::LocalVariable *ETSObjectType::CreateSyntheticVarFromEverySignature(co varbinder::LocalVariable *res = allocator_->New(varbinder::VariableFlags::SYNTHETIC | varbinder::VariableFlags::METHOD); - ETSFunctionType *funcType = CreateMethodTypeForProp(name); for (auto &s : signatures) { funcType->AddCallSignature(s); } @@ -208,8 +209,8 @@ ETSFunctionType *ETSObjectType::CreateMethodTypeForProp(const util::StringView & return GetRelation()->GetChecker()->AsETSChecker()->CreateETSMethodType(name, {{}, Allocator()->Adapter()}); } -static void AddSignature(std::vector &signatures, PropertySearchFlags flags, ETSChecker *checker, - varbinder::LocalVariable *found) +void ETSObjectType::AddSignature(std::vector &signatures, PropertySearchFlags flags, ETSChecker *checker, + varbinder::LocalVariable *found, ETSFunctionType *funcType)const { for (auto *it : found->TsType()->AsETSFunctionType()->CallSignatures()) { if (std::find(signatures.begin(), signatures.end(), it) != signatures.end()) { @@ -230,11 +231,21 @@ static void AddSignature(std::vector &signatures, PropertySearchFla // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage) signatures.emplace_back(it); } -} + FunctionOverloadType functionOverloadType = + found->Declaration()->Node()->IsOverloadDefinition() ? FunctionOverloadType::OVERLOAD_DEFINITION + : found->Declaration()->Node()->AsMethodDefinition()->IsTsOverload() ? FunctionOverloadType::OVERLOAD_SIGNATURE + : FunctionOverloadType::NONE; + + if (!funcType->SetFunctionOverloadType(functionOverloadType)) { + checker->LogError(diagnostic::OVERLOAD_NAME_MUST_BE_IDENTIFIER, {}, found->Declaration()->Node()->Start()); + } +} +// TODO varbinder::LocalVariable *ETSObjectType::CollectSignaturesForSyntheticType(std::vector &signatures, const util::StringView &name, - PropertySearchFlags flags) const + PropertySearchFlags flags, + ETSFunctionType *funcType) const { auto *checker = GetRelation()->GetChecker()->AsETSChecker(); @@ -242,7 +253,7 @@ varbinder::LocalVariable *ETSObjectType::CollectSignaturesForSyntheticType(std:: if (auto *found = GetOwnProperty(name); found != nullptr && !found->TsType()->IsTypeError()) { ES2PANDA_ASSERT(found->TsType()->IsETSFunctionType()); - AddSignature(signatures, flags, checker, found); + AddSignature(signatures, flags, checker, found, funcType); } } @@ -250,12 +261,12 @@ varbinder::LocalVariable *ETSObjectType::CollectSignaturesForSyntheticType(std:: if (auto *found = GetOwnProperty(name); found != nullptr && !found->TsType()->IsTypeError()) { ES2PANDA_ASSERT(found->TsType()->IsETSFunctionType()); - AddSignature(signatures, flags, checker, found); + AddSignature(signatures, flags, checker, found, funcType); } } if (superType_ != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) { - superType_->CollectSignaturesForSyntheticType(signatures, name, flags); + superType_->CollectSignaturesForSyntheticType(signatures, name, flags, funcType); } ArenaVector interfaces(Allocator()->Adapter()); @@ -268,7 +279,7 @@ varbinder::LocalVariable *ETSObjectType::CollectSignaturesForSyntheticType(std:: interface->GetProperty(name, flags | PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION); found != nullptr && !found->TsType()->IsTypeError()) { ES2PANDA_ASSERT(found->TsType()->IsETSFunctionType()); - AddSignature(signatures, flags, checker, found); + AddSignature(signatures, flags, checker, found, funcType); } } } diff --git a/ets2panda/checker/types/ets/etsObjectType.h b/ets2panda/checker/types/ets/etsObjectType.h index 20e5811f3d..c1a7fd86f0 100644 --- a/ets2panda/checker/types/ets/etsObjectType.h +++ b/ets2panda/checker/types/ets/etsObjectType.h @@ -354,8 +354,10 @@ public: varbinder::LocalVariable *CreateSyntheticVarFromEverySignature(const util::StringView &name, PropertySearchFlags flags) const; varbinder::LocalVariable *CollectSignaturesForSyntheticType(std::vector &signatures, - const util::StringView &name, - PropertySearchFlags flags) const; + const util::StringView &name, PropertySearchFlags flags, + ETSFunctionType *funcType) const; + void AddSignature(std::vector &signatures, PropertySearchFlags flags, ETSChecker *checker, + varbinder::LocalVariable *found, ETSFunctionType *funcType) const; bool CheckIdenticalFlags(ETSObjectType *other) const; ETSObjectType *CreateETSObjectType(ir::AstNode *declNode, ETSObjectFlags flags); void Iterate(const PropertyTraverser &cb) const; diff --git a/ets2panda/compiler/lowering/ets/overloadMappingLoweing.cpp b/ets2panda/compiler/lowering/ets/overloadMappingLoweing.cpp new file mode 100644 index 0000000000..d3565c74e2 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/overloadMappingLoweing.cpp @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#include "overloadMappingLoweing.h" +#include "checker/ETSchecker.h" +#include "compiler/lowering/util.h" + +namespace ark::es2panda::compiler { + +std::string_view OverloadMappingLowering::Name() const +{ + return "OverloadMappingLowering"; +} + +static ir::CallExpression *MethodMapping(public_lib::Context *ctx, ir::CallExpression *callExpression) +{ + auto *checker = ctx->GetChecker()->AsETSChecker(); + + auto *signature = callExpression->Signature(); + ES2PANDA_ASSERT(signature->OwnerVar()->Declaration()->Node()->IsMethodDefinition()); + auto *methodDef = signature->OwnerVar()->Declaration()->Node()->AsMethodDefinition(); + auto oldReturnType = callExpression->TsType(); + + ES2PANDA_ASSERT(callExpression->Callee()->IsMemberExpression()) + ir::AstNode *callee = callExpression->Callee()->AsMemberExpression(); + while (callee->IsMemberExpression() && callee->AsMemberExpression()->Property()->IsMemberExpression()) { + callee = callee->AsMemberExpression()->Property()->AsMemberExpression()->Property(); + } + auto *ident = callee->AsMemberExpression()->Property()->AsIdentifier(); + ident->SetName(methodDef->Key()->AsIdentifier()->Name()); + Recheck(ctx->phaseManager, checker->VarBinder()->AsETSBinder(), checker, callExpression); + // TODO modifier error + if (!checker->Relation()->IsIdenticalTo(callExpression->TsType(), oldReturnType)) { + checker->LogError(diagnostic::OVERLOAD_NAME_MUST_BE_IDENTIFIER, {},callExpression->Start()); + } + return callExpression; +} + +bool OverloadMappingLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) +{ + program->Ast()->TransformChildrenRecursively( + // CC-OFFNXT(G.FMT.14-CPP) project code style + [ctx](ir::AstNode *const node) -> ir::AstNode * { + if (node->IsCallExpression() && node->AsCallExpression()->Callee()->TsType() != nullptr && + node->AsCallExpression()->Callee()->TsType()->AsETSFunctionType()->IsOverloadDefinition()) { + return MethodMapping(ctx, node->AsCallExpression()); + } + return node; + }, + Name()); + + return true; +} + +} // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/overloadMappingLoweing.h b/ets2panda/compiler/lowering/ets/overloadMappingLoweing.h new file mode 100644 index 0000000000..2efcadbdc4 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/overloadMappingLoweing.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef ES2PANDA_COMPILER_LOWERING_OVERLOAD_MAPPING_LOWERING_H +#define ES2PANDA_COMPILER_LOWERING_OVERLOAD_MAPPING_LOWERING_H + +#include "compiler/lowering/phase.h" + +namespace ark::es2panda::compiler { + +class OverloadMappingLowering : public PhaseForDeclarations { +public: + std::string_view Name() const override; + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; +}; + +} // namespace ark::es2panda::compiler + +#endif diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 38a1aef34b..ed986be6f4 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -51,6 +51,7 @@ #include "compiler/lowering/ets/opAssignment.h" #include "compiler/lowering/ets/optionalArgumentsLowering.h" #include "compiler/lowering/ets/optionalLowering.h" +#include "compiler/lowering/ets/overloadMappingLoweing.h" #include "compiler/lowering/ets/packageImplicitImport.h" #include "compiler/lowering/ets/partialExportClassGen.h" #include "compiler/lowering/ets/promiseVoid.h" @@ -128,6 +129,7 @@ std::vector GetETSPhaseList() new AnnotationCopyPostLowering, new DynamicImportLowering, new AsyncMethodLowering, + new OverloadMappingLowering, new EnumPostCheckLoweringPhase, new SpreadConstructionPhase, new RestArgsLowering, diff --git a/ets2panda/ir/astNode.cpp b/ets2panda/ir/astNode.cpp index 3b8a45b1bc..96d2fcb0f9 100644 --- a/ets2panda/ir/astNode.cpp +++ b/ets2panda/ir/astNode.cpp @@ -88,13 +88,13 @@ void AstNode::ClearScope() noexcept ir::ClassElement *AstNode::AsClassElement() { - ES2PANDA_ASSERT(IsMethodDefinition() || IsClassProperty() || IsClassStaticBlock()); + ES2PANDA_ASSERT(IsMethodDefinition() || IsClassProperty() || IsClassStaticBlock() || IsOverloadDefinition()); return reinterpret_cast(this); } const ir::ClassElement *AstNode::AsClassElement() const { - ES2PANDA_ASSERT(IsMethodDefinition() || IsClassProperty() || IsClassStaticBlock()); + ES2PANDA_ASSERT(IsMethodDefinition() || IsClassProperty() || IsClassStaticBlock() || IsOverloadDefinition()); return reinterpret_cast(this); } diff --git a/ets2panda/ir/base/methodDefinition.h b/ets2panda/ir/base/methodDefinition.h index 47ac731ce1..0185ea96ed 100644 --- a/ets2panda/ir/base/methodDefinition.h +++ b/ets2panda/ir/base/methodDefinition.h @@ -133,6 +133,11 @@ public: return !overloads_.empty(); } + [[nodiscard]] bool IsTsOverloadSignatrue() const noexcept + { + return (Function()->Flags() & ir::ScriptFunctionFlags::OVERLOAD) != 0 && baseOverloadMethod_ != nullptr; + } + [[nodiscard]] const OverloadsT &Overloads() const noexcept { return GetHistoryNodeAs()->overloads_; diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index 9b8569317c..f6442bda28 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -174,6 +174,7 @@ std::pair MemberExpression::Resolve return {checker->GetTypeOfVariable(resolveRes[0]->Variable()), nullptr}; } case 2U: { + // TODO: It will be abandoned later because the same name is not allowed auto classMethodType = checker->GetTypeOfVariable(resolveRes[1]->Variable()); auto extensionMethodType = checker->GetTypeOfVariable(resolveRes[0]->Variable()); auto *resolvedType = extensionMethodType; diff --git a/ets2panda/test/ast/parser/ets/overload_call.ets b/ets2panda/test/ast/parser/ets/overload_call.ets new file mode 100644 index 0000000000..dbcd061576 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/overload_call.ets @@ -0,0 +1,52 @@ +/* + * 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 A{} +class B{} +class C{} + +class Test1 { + foo110(a: A): A { + return a; + } + foo112(a: B): B { + return a; + } + + foo113(a: C): C { + console.log(a) + return a; + } + overload foo111{foo110,foo112,foo113} +} + +class Test2 { + foo111(a: A): A; + foo111(a: B): B; + foo111(a: C): C; + foo111(...args:Any[]):Any{ + return args[0]; + } +} + +function main() { + let a: Test1 = new Test1(); + let b = new B(); + a.foo111(b); + + let a2:Test2 = new Test2(); + let b2 = new B(); + a2.foo111(b2) +} diff --git a/ets2panda/test/ast/parser/ets/overload_class_method_test.ets b/ets2panda/test/ast/parser/ets/overload_class_method_test.ets index d7c13e94fd..ac5f453801 100644 --- a/ets2panda/test/ast/parser/ets/overload_class_method_test.ets +++ b/ets2panda/test/ast/parser/ets/overload_class_method_test.ets @@ -37,7 +37,7 @@ class Test2 { foo111(a: A): A; foo111(a: B): B; foo111(a: C): C; - foo111(...args:TempAny[]):TempAny{ + foo111(...args:Any[]):Any{ return args[0]; } } diff --git a/ets2panda/test/ast/parser/ets/overload_constructor.ets b/ets2panda/test/ast/parser/ets/overload_constructor.ets index 9bc26d275b..387a7e58f4 100644 --- a/ets2panda/test/ast/parser/ets/overload_constructor.ets +++ b/ets2panda/test/ast/parser/ets/overload_constructor.ets @@ -38,12 +38,12 @@ class Test3 { constructor() constructor(a:A) constructor(a:B) - constructor(...args:any){} + constructor(...args:Any){} } class Test4 { constructor con() constructor con(a:A) constructor con(a:B) - constructor con(...args:any){} + constructor con(...args:Any){} } diff --git a/ets2panda/test/ast/parser/ets/overload_global_function_ts_style_test.ets b/ets2panda/test/ast/parser/ets/overload_global_function_ts_style_test.ets index 8dd9405000..3e79c38e44 100644 --- a/ets2panda/test/ast/parser/ets/overload_global_function_ts_style_test.ets +++ b/ets2panda/test/ast/parser/ets/overload_global_function_ts_style_test.ets @@ -21,6 +21,6 @@ class TempAny{} function foo111(a: A): A; function foo111(a: B): B; function foo111(a: C): C; -function foo111(...args: TempAny[]): TempAny { +function foo111(...args: Any[]): Any { return args[0]; } diff --git a/ets2panda/test/ast/parser/ets/overload_interface_method_test.ets b/ets2panda/test/ast/parser/ets/overload_interface_method_test.ets index 009db76adf..68d695f73e 100644 --- a/ets2panda/test/ast/parser/ets/overload_interface_method_test.ets +++ b/ets2panda/test/ast/parser/ets/overload_interface_method_test.ets @@ -29,6 +29,6 @@ interface Test2 { foo111(a: A): A; foo111(a: B): B; foo111(a: C): C; - foo111(...args:TempAny[]); + foo111(...args:Any[]); } -- Gitee