From 83818ac459ce5a657a4f57fb15951c67b60ba977 Mon Sep 17 00:00:00 2001 From: xuxinjie4 Date: Wed, 28 May 2025 00:08:49 +0800 Subject: [PATCH] interface object literal lowering refactoring Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICALW3?from=project-issue Signed-off-by: xuxinjie4 --- ets2panda/checker/ets/dynamic.cpp | 6 +- .../ets/interfaceObjectLiteralLowering.cpp | 216 ++++++++++++------ .../ets/interfaceObjectLiteralLowering.h | 7 +- .../ets/interfacePropertyDeclarations.cpp | 4 +- .../lowering/ets/objectLiteralLowering.cpp | 2 +- ets2panda/compiler/lowering/phase.cpp | 4 +- .../annotations_for_functional_objects.cpp | 2 +- ets2panda/test/unit/lowerings/CMakeLists.txt | 4 + .../lowerings/interface_object_literal.cpp | 57 +++++ 9 files changed, 227 insertions(+), 75 deletions(-) create mode 100644 ets2panda/test/unit/lowerings/interface_object_literal.cpp diff --git a/ets2panda/checker/ets/dynamic.cpp b/ets2panda/checker/ets/dynamic.cpp index 9fcfc1ce55..90abef0f88 100644 --- a/ets2panda/checker/ets/dynamic.cpp +++ b/ets2panda/checker/ets/dynamic.cpp @@ -368,7 +368,11 @@ ir::ClassDeclaration *ETSChecker::BuildClass(util::StringView name, const ClassB VarBinder()->Program()->Ast()->Statements().push_back(classDecl); classDecl->SetParent(VarBinder()->Program()->Ast()); - varbinder::BoundContext boundCtx(VarBinder()->AsETSBinder()->GetGlobalRecordTable(), classDef); + auto varBinder = VarBinder()->AsETSBinder(); + bool isExternal = VarBinder()->Program() != varBinder->GetGlobalRecordTable()->Program(); + auto recordTable = isExternal ? varBinder->GetExternalRecordTable().at(varBinder->Program()) + : VarBinder()->AsETSBinder()->GetGlobalRecordTable(); + varbinder::BoundContext boundCtx(recordTable, classDef); ArenaVector classBody(ProgramAllocator()->Adapter()); diff --git a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp index f19178ec3e..7b00e071ae 100644 --- a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp @@ -23,6 +23,7 @@ namespace ark::es2panda::compiler { +static constexpr std::string_view OBJECT_LITERAL_SUFFIX = "$ObjectLiteral"; using ReadonlyFieldHolder = std::tuple; // anonClassFieldName, paramName, fieldType @@ -123,23 +124,22 @@ static ir::MethodDefinition *CreateAnonClassFieldGetterSetter(public_lib::Contex } static void FillClassBody(public_lib::Context *ctx, ArenaVector *classBody, - const ArenaVector &ifaceBody, ir::ObjectExpression *objExpr, - ArenaVector &readonlyFields, + const ArenaVector &ifaceBody, ArenaVector &readonlyFields, checker::ETSObjectType *currentType = nullptr) { - auto *checker = ctx->checker->AsETSChecker(); - for (auto *it : ifaceBody) { ES2PANDA_ASSERT(it->IsMethodDefinition()); auto *ifaceMethod = it->AsMethodDefinition(); - if (!ifaceMethod->Function()->IsGetter() && !ifaceMethod->Function()->IsSetter()) { - checker->LogError(diagnostic::INTERFACE_WITH_METHOD, {}, objExpr->Start()); - objExpr->SetTsType(checker->GlobalTypeError()); - return; + if (!ifaceMethod->Function()->IsGetter()) { + continue; } - if (!ifaceMethod->Function()->IsGetter()) { + auto iter = std::find_if(classBody->begin(), classBody->end(), [ifaceMethod](ir::AstNode *ast) -> bool { + return ast->IsMethodDefinition() && ast->AsMethodDefinition()->Function()->IsGetter() && + ast->AsMethodDefinition()->Id()->Name() == ifaceMethod->Id()->Name(); + }); + if (iter != classBody->end()) { continue; } @@ -183,25 +183,24 @@ static void FillClassBody(public_lib::Context *ctx, ArenaVector * // CC-OFFNXT(G.FUN.01-CPP) solid logic static void FillAnonClassBody(public_lib::Context *ctx, ArenaVector *classBody, - ir::TSInterfaceDeclaration *ifaceNode, ir::ObjectExpression *objExpr, - ArenaVector &readonlyFields, + ir::TSInterfaceDeclaration *ifaceNode, ArenaVector &readonlyFields, checker::ETSObjectType *interfaceType = nullptr) { + FillClassBody(ctx, classBody, ifaceNode->Body()->Body(), readonlyFields, interfaceType); for (auto *extendedIface : ifaceNode->TsType()->AsETSObjectType()->Interfaces()) { - FillAnonClassBody(ctx, classBody, extendedIface->GetDeclNode()->AsTSInterfaceDeclaration(), objExpr, - readonlyFields, extendedIface); + FillAnonClassBody(ctx, classBody, extendedIface->GetDeclNode()->AsTSInterfaceDeclaration(), readonlyFields, + extendedIface); } - - FillClassBody(ctx, classBody, ifaceNode->Body()->Body(), objExpr, readonlyFields, interfaceType); } // Annotate synthetic class so we can determite it's origin in a runtime // Now implemented for the anon class generated from an interface only static void AnnotateGeneratedAnonClass(checker::ETSChecker *checker, ir::ClassDefinition *classDef) { - auto *annoId = checker->AllocNode(Signatures::INTERFACE_OBJ_LITERAL, checker->Allocator()); + auto *annoId = + checker->ProgramAllocNode(Signatures::INTERFACE_OBJ_LITERAL, checker->ProgramAllocator()); annoId->SetAnnotationUsage(); - auto *annoUsage = checker->AllocNode(annoId, checker->Allocator()); + auto *annoUsage = checker->ProgramAllocNode(annoId, checker->ProgramAllocator()); annoUsage->AddModifier(ir::ModifierFlags::ANNOTATION_USAGE); annoUsage->SetParent(classDef); annoId->SetParent(annoUsage); @@ -210,27 +209,28 @@ static void AnnotateGeneratedAnonClass(checker::ETSChecker *checker, ir::ClassDe CheckLoweredNode(checker->VarBinder()->AsETSBinder(), checker, annoUsage); } -static checker::Type *GenerateAnonClassTypeFromInterface(public_lib::Context *ctx, - ir::TSInterfaceDeclaration *ifaceNode, - ir::ObjectExpression *objExpr) +static void GenerateAnonClassTypeFromInterface(public_lib::Context *ctx, ir::TSInterfaceDeclaration *ifaceNode) { auto *checker = ctx->checker->AsETSChecker(); if (ifaceNode->GetAnonClass() != nullptr) { - return ifaceNode->GetAnonClass()->Definition()->TsType()->AsETSObjectType(); + return; } - auto classBodyBuilder = [ctx, checker, ifaceNode, objExpr](ArenaVector *classBody) { + auto classBodyBuilder = [ctx, checker, ifaceNode](ArenaVector *classBody) { if (ifaceNode->TsType() == nullptr) { ifaceNode->Check(checker); } ArenaVector readonlyFields(ctx->Allocator()->Adapter()); - FillAnonClassBody(ctx, classBody, ifaceNode, objExpr, readonlyFields); + FillAnonClassBody(ctx, classBody, ifaceNode, readonlyFields); classBody->push_back(CreateAnonClassImplCtor(ctx, readonlyFields)); }; - auto anonClassName = GenName(ctx->Allocator()); + auto originalName = std::string {ifaceNode->InternalName()}; + std::replace(originalName.begin(), originalName.end(), '.', '$'); + auto anonClassName = util::UString(originalName.append(OBJECT_LITERAL_SUFFIX), checker->ProgramAllocator()); auto *classDecl = checker->BuildClass(anonClassName.View(), classBodyBuilder); + RefineSourceRanges(classDecl); auto *classDef = classDecl->Definition(); auto *classType = classDef->TsType()->AsETSObjectType(); classDef->SetAnonymousModifier(); @@ -260,20 +260,17 @@ static checker::Type *GenerateAnonClassTypeFromInterface(public_lib::Context *ct checker->GetInterfacesOfClass(classType); ifaceNode->SetAnonClass(classDecl); - return classType; } -static checker::Type *GenerateAnonClassTypeFromAbstractClass(public_lib::Context *ctx, - ir::ClassDefinition *abstractClassNode, - ir::ObjectExpression *objExpr) +static void GenerateAnonClassTypeFromAbstractClass(public_lib::Context *ctx, ir::ClassDefinition *abstractClassNode) { auto *checker = ctx->checker->AsETSChecker(); if (abstractClassNode->GetAnonClass() != nullptr) { - return abstractClassNode->GetAnonClass()->Definition()->TsType()->AsETSObjectType(); + return; } - auto classBodyBuilder = [checker, abstractClassNode, objExpr](ArenaVector *classBody) { + auto classBodyBuilder = [checker](ArenaVector *classBody) { checker::ETSChecker::ClassInitializerBuilder initBuilder = [checker]([[maybe_unused]] ArenaVector *statements, [[maybe_unused]] ArenaVector *params) { @@ -282,17 +279,13 @@ static checker::Type *GenerateAnonClassTypeFromAbstractClass(public_lib::Context auto ctor = checker->CreateClassInstanceInitializer(initBuilder); classBody->push_back(ctor); - - for (auto *it : abstractClassNode->Body()) { - if (it->IsMethodDefinition() && it->AsMethodDefinition()->IsAbstract()) { - checker->LogError(diagnostic::ABSTRACT_METH_IN_ABSTRACT_CLASS, {it->AsMethodDefinition()->Id()->Name()}, - objExpr->Start()); - } - } }; - auto anonClassName = GenName(ctx->Allocator()); + auto originalName = std::string {abstractClassNode->InternalName()}; + std::replace(originalName.begin(), originalName.end(), '.', '$'); + auto anonClassName = util::UString(originalName.append(OBJECT_LITERAL_SUFFIX), checker->ProgramAllocator()); auto *classDecl = checker->BuildClass(anonClassName.View(), classBodyBuilder); + RefineSourceRanges(classDecl); auto *classDef = classDecl->Definition(); auto *classType = classDef->TsType()->AsETSObjectType(); @@ -312,8 +305,38 @@ static checker::Type *GenerateAnonClassTypeFromAbstractClass(public_lib::Context } abstractClassNode->SetAnonClass(classDecl); - classType->SetSuperType(objExpr->TsType()->AsETSObjectType()); - return classType; + classType->SetSuperType(abstractClassNode->TsType()->AsETSObjectType()); +} + +static checker::Type *ProcessDeclNode(checker::ETSChecker *checker, checker::ETSObjectType *targetType, + ir::ObjectExpression *objExpr) +{ + auto *declNode = targetType->GetDeclNode(); + + if (declNode->IsTSInterfaceDeclaration()) { + auto *ifaceNode = declNode->AsTSInterfaceDeclaration(); + if (ifaceNode->GetAnonClass() == nullptr) { + checker->LogError(diagnostic::INTERFACE_WITH_METHOD, {}, objExpr->Start()); + return checker->GlobalTypeError(); + } + return ifaceNode->GetAnonClass()->Definition()->TsType(); + } + + auto *classDef = declNode->AsClassDefinition(); + ES2PANDA_ASSERT(classDef->IsAbstract()); + + if (classDef->GetAnonClass() == nullptr) { + for (auto it : classDef->Body()) { + if (!it->IsMethodDefinition() || !it->AsMethodDefinition()->IsAbstract()) { + continue; + } + + checker->LogError(diagnostic::ABSTRACT_METH_IN_ABSTRACT_CLASS, {it->AsMethodDefinition()->Id()->Name()}, + objExpr->Start()); + return checker->GlobalTypeError(); + } + } + return classDef->GetAnonClass()->Definition()->TsType(); } static void HandleInterfaceLowering(public_lib::Context *ctx, ir::ObjectExpression *objExpr) @@ -321,22 +344,21 @@ static void HandleInterfaceLowering(public_lib::Context *ctx, ir::ObjectExpressi auto *checker = ctx->checker->AsETSChecker(); auto *targetType = objExpr->TsType(); checker->CheckObjectLiteralKeys(objExpr->Properties()); - checker::Type *resultType; - if (targetType->AsETSObjectType()->GetDeclNode()->IsTSInterfaceDeclaration()) { - auto *ifaceNode = targetType->AsETSObjectType()->GetDeclNode()->AsTSInterfaceDeclaration(); - resultType = GenerateAnonClassTypeFromInterface(ctx, ifaceNode, objExpr); - } else { - ES2PANDA_ASSERT(targetType->AsETSObjectType()->GetDeclNode()->AsClassDefinition()->IsAbstract()); - auto *abstractClassNode = targetType->AsETSObjectType()->GetDeclNode()->AsClassDefinition(); - resultType = GenerateAnonClassTypeFromAbstractClass(ctx, abstractClassNode, objExpr); + + auto *etsTargetType = targetType->AsETSObjectType(); + checker::Type *resultType = ProcessDeclNode(checker, etsTargetType, objExpr); + + if (resultType->IsTypeError()) { + objExpr->SetTsType(resultType); + return; } - if (targetType->AsETSObjectType()->IsPartial()) { - resultType->AsETSObjectType()->SetBaseType(targetType->AsETSObjectType()->GetBaseType()); + if (etsTargetType->IsPartial()) { + resultType->AsETSObjectType()->SetBaseType(etsTargetType->GetBaseType()); } - if (!targetType->AsETSObjectType()->TypeArguments().empty()) { - ArenaVector typeArgTypes(targetType->AsETSObjectType()->TypeArguments()); + if (!etsTargetType->TypeArguments().empty()) { + ArenaVector typeArgTypes(etsTargetType->TypeArguments()); checker::InstantiationContext instantiationCtx(checker, resultType->AsETSObjectType(), std::move(typeArgTypes), objExpr->Start()); resultType = instantiationCtx.Result(); @@ -344,17 +366,58 @@ static void HandleInterfaceLowering(public_lib::Context *ctx, ir::ObjectExpressi if (const auto *const parent = objExpr->Parent(); parent->IsArrayExpression()) { for (auto *elem : parent->AsArrayExpression()->Elements()) { - if (!elem->IsObjectExpression()) { - continue; + if (elem->IsObjectExpression()) { + elem->AsObjectExpression()->SetTsType(resultType); } - // Adjusting ts types of other object literals in array - elem->AsObjectExpression()->SetTsType(resultType); } } objExpr->SetTsType(resultType); } -bool InterfaceObjectLiteralLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) +static bool CheckInterfaceShouldGenerateAnonClass(ir::TSInterfaceDeclaration *interfaceDecl) +{ + for (auto it : interfaceDecl->Body()->Body()) { + ES2PANDA_ASSERT(it->IsMethodDefinition()); + auto methodDef = it->AsMethodDefinition(); + if (!methodDef->Function()->IsGetter() && !methodDef->Function()->IsSetter()) { + return false; + } + } + + return true; +} + +static bool CheckAbstractClassShouldGenerateAnonClass(ir::ClassDefinition *classDef) +{ + auto constructorSigs = classDef->TsType()->AsETSObjectType()->ConstructSignatures(); + if (auto res = std::find_if(constructorSigs.cbegin(), constructorSigs.cend(), + [](checker::Signature *sig) -> bool { return sig->MinArgCount() == 0; }); + res == constructorSigs.cend()) { + return false; + } + for (auto it : classDef->Body()) { + if (it->IsMethodDefinition() && it->AsMethodDefinition()->IsAbstract()) { + return false; + } + } + + return true; +} + +static void TransfromInterfaceDecl(public_lib::Context *ctx, parser::Program *program) +{ + program->Ast()->IterateRecursivelyPostorder([ctx, program](ir::AstNode *ast) -> void { + if (ast->IsTSInterfaceDeclaration() && CheckInterfaceShouldGenerateAnonClass(ast->AsTSInterfaceDeclaration())) { + GenerateAnonClassTypeFromInterface(ctx, ast->AsTSInterfaceDeclaration()); + } else if (ast->IsClassDefinition() && ast != program->GlobalClass() && + ast->AsClassDefinition()->IsAbstract() && + CheckAbstractClassShouldGenerateAnonClass(ast->AsClassDefinition())) { + GenerateAnonClassTypeFromAbstractClass(ctx, ast->AsClassDefinition()); + } + }); +} + +static void TransfromInterfaceLiteral(public_lib::Context *ctx, parser::Program *program) { program->Ast()->IterateRecursivelyPostorder([ctx](ir::AstNode *ast) -> void { if (ast->IsObjectExpression() && (IsInterfaceType(ast->AsObjectExpression()->TsType()) || @@ -362,16 +425,39 @@ bool InterfaceObjectLiteralLowering::PerformForModule(public_lib::Context *ctx, HandleInterfaceLowering(ctx, ast->AsObjectExpression()); } }); - - return true; } -bool InterfaceObjectLiteralLowering::PostconditionForModule([[maybe_unused]] public_lib::Context *ctx, - const parser::Program *program) +bool InterfaceObjectLiteralLowering::Perform(public_lib::Context *ctx, parser::Program *program) { - return !program->Ast()->IsAnyChild([](const ir::AstNode *ast) -> bool { - return ast->IsObjectExpression() && (IsInterfaceType(ast->AsObjectExpression()->TsType()) || - IsAbstractClassType(ast->AsObjectExpression()->TsType())); - }); + auto *varbinder = program->VarBinder()->AsETSBinder(); + for (auto &[_, extPrograms] : program->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + auto *savedProgram = varbinder->Program(); + auto *savedRecordTable = varbinder->GetRecordTable(); + auto *savedTopScope = varbinder->TopScope(); + varbinder->ResetTopScope(extProg->GlobalScope()); + varbinder->SetRecordTable(varbinder->GetExternalRecordTable().at(extProg)); + varbinder->SetProgram(extProg); + TransfromInterfaceDecl(ctx, extProg); + varbinder->SetProgram(savedProgram); + varbinder->SetRecordTable(savedRecordTable); + varbinder->ResetTopScope(savedTopScope); + } + } + + TransfromInterfaceDecl(ctx, program); + + for (auto &[_, extPrograms] : program->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + TransfromInterfaceLiteral(ctx, extProg); + } + } + + TransfromInterfaceLiteral(ctx, program); + + return true; } + } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.h b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.h index b784b365c5..055e3a64b3 100644 --- a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.h +++ b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. + * Copyright (c) 2024-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 @@ -20,11 +20,10 @@ namespace ark::es2panda::compiler { -class InterfaceObjectLiteralLowering : public PhaseForDeclarations { +class InterfaceObjectLiteralLowering : public Phase { public: std::string_view Name() const override; - bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; - bool PostconditionForModule(public_lib::Context *ctx, const parser::Program *program) override; + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp index e2ab2434ff..c997421bf4 100644 --- a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp +++ b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp @@ -287,7 +287,9 @@ void InterfacePropertyDeclarationsPhase::UpdateClassProperties(public_lib::Conte GetPropCollector().InitVisitedInterfaces(); for (const auto &implement : klass->Implements()) { - std::string interId = implement->Expr()->AsETSTypeReference()->Part()->Name()->ToString(); + std::string interId = implement->Expr()->IsOpaqueTypeNode() + ? implement->Expr()->TsType()->AsETSObjectType()->Name().Mutf8() + : implement->Expr()->AsETSTypeReference()->Part()->Name()->ToString(); CollectSuperInterfaceProperties(implInterfaceProperties, interId); } diff --git a/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp index 03f853cf44..e24fe2ea47 100644 --- a/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp @@ -314,7 +314,7 @@ bool ObjectLiteralLowering::PostconditionForModule([[maybe_unused]] public_lib:: { // In all object literal contexts (except dynamic) a substitution should take place return !program->Ast()->IsAnyChild([](const ir::AstNode *ast) -> bool { - return ast->IsObjectExpression() && + return ast->IsObjectExpression() && ast->AsObjectExpression()->TsType()->IsETSObjectType() && !ast->AsObjectExpression()->TsType()->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::DYNAMIC); }); } diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 5d76f8b5f8..41cf70c6af 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -191,11 +191,11 @@ std::vector GetETSPhaseList() &g_unionLowering, &g_expandBracketsPhase, &g_localClassLowering, - &g_interfaceObjectLiteralLowering, + &g_partialExportClassGen, + &g_interfaceObjectLiteralLowering, // this lowering should be put after all classs generated. &g_objectLiteralLowering, &g_stringConstructorLowering, &g_stringComparisonLowering, - &g_partialExportClassGen, &g_optionalArgumentsLowering, // #22952 could be moved to earlier phase &g_genericBridgesLowering, &g_typeFromLowering, diff --git a/ets2panda/test/unit/annotations/annotations_for_functional_objects.cpp b/ets2panda/test/unit/annotations/annotations_for_functional_objects.cpp index c1acdc863e..49fb6a853f 100644 --- a/ets2panda/test/unit/annotations/annotations_for_functional_objects.cpp +++ b/ets2panda/test/unit/annotations/annotations_for_functional_objects.cpp @@ -45,7 +45,7 @@ public: void CheckClassAnnotations(pandasm::Program *program) { - const std::string recordName = "gensym%%_55"; + const std::string recordName = "Iface$ObjectLiteral"; const AnnotationMap expectedClassAnnotations = { {"std.annotations.InterfaceObjectLiteral", {}}, }; diff --git a/ets2panda/test/unit/lowerings/CMakeLists.txt b/ets2panda/test/unit/lowerings/CMakeLists.txt index 64567a9c94..c63c1298fa 100644 --- a/ets2panda/test/unit/lowerings/CMakeLists.txt +++ b/ets2panda/test/unit/lowerings/CMakeLists.txt @@ -34,3 +34,7 @@ ets2panda_add_gtest(node_history_test ets2panda_add_gtest(convert_primitive_cast_method_call CPP_SOURCES convert_primitive_cast_method_call.cpp ) + +ets2panda_add_gtest(interface_object_literal_test + CPP_SOURCES interface_object_literal.cpp +) diff --git a/ets2panda/test/unit/lowerings/interface_object_literal.cpp b/ets2panda/test/unit/lowerings/interface_object_literal.cpp new file mode 100644 index 0000000000..1f7700eacf --- /dev/null +++ b/ets2panda/test/unit/lowerings/interface_object_literal.cpp @@ -0,0 +1,57 @@ +/** + * 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 +#include "lowering_test.h" +#include "compiler/lowering/ets/topLevelStmts/topLevelStmts.h" + +namespace ark::es2panda { + +TEST_F(LoweringTest, TestInterfaceObjectLiteral) +{ + char const *text = R"( + interface I1 { + a: number + } + + interface I2 { + a: string + } + + function foo1(a: I1) { } + function foo2(a: I2) { } + + function main() { + foo1({ a: 1 }) + foo2({ a: "2" }) + })"; + + CONTEXT(ES2PANDA_STATE_LOWERED, text) + { + const auto *const ast = GetAst(); + [[maybe_unused]] auto *classDef1 = ast->FindChild([](ir::AstNode *child) { + return child->IsClassDefinition() && + (child->AsClassDefinition()->InternalName().Mutf8() == "dummy.dummy$I1$ObjectLiteral"); + }); + ASSERT_TRUE(classDef1 != nullptr); + [[maybe_unused]] auto *classDef2 = ast->FindChild([](ir::AstNode *child) { + return child->IsClassDefinition() && + (child->AsClassDefinition()->InternalName().Mutf8() == "dummy.dummy$I2$ObjectLiteral"); + }); + ASSERT_TRUE(classDef1 != nullptr); + } +} + +} // namespace ark::es2panda -- Gitee