From 1b6c4ddce734ea6826d06e2c5424add8294d13b4 Mon Sep 17 00:00:00 2001 From: ekkoruse Date: Wed, 7 May 2025 21:40:45 +0800 Subject: [PATCH] ast-cache Issue: #ICEP24 Change-Id: Ib2c4c9a9f9a061f42a01d5ffad1b5fe1ed5b73c5 Signed-off-by: ekkoruse --- ets2panda/BUILD.gn | 1 + ets2panda/CMakeLists.txt | 1 + ets2panda/checker/ASchecker.cpp | 4 +- ets2panda/checker/ASchecker.h | 5 +- ets2panda/checker/ETSAnalyzer.cpp | 10 +- ets2panda/checker/ETSAnalyzerHelpers.cpp | 4 +- ets2panda/checker/ETSchecker.cpp | 108 ++-- ets2panda/checker/ETSchecker.h | 50 +- ets2panda/checker/JSchecker.cpp | 1 - ets2panda/checker/JSchecker.h | 6 +- ets2panda/checker/TSchecker.cpp | 1 - ets2panda/checker/TSchecker.h | 5 +- ets2panda/checker/checker.cpp | 11 +- ets2panda/checker/checker.h | 28 +- ets2panda/checker/ets/dynamic.cpp | 6 +- ets2panda/checker/ets/function.cpp | 42 +- ets2panda/checker/ets/helpers.cpp | 8 +- ets2panda/checker/ets/object.cpp | 30 +- ets2panda/checker/ets/typeCreation.cpp | 11 +- ets2panda/checker/ets/typeRelationContext.cpp | 2 +- ets2panda/checker/ets/utilityTypeHandlers.cpp | 21 +- .../types/ets/etsAsyncFuncReturnType.h | 2 +- ets2panda/checker/types/ets/etsBigIntType.h | 4 +- ets2panda/checker/types/ets/etsDynamicType.h | 3 +- ets2panda/checker/types/ets/etsEnumType.h | 8 +- .../checker/types/ets/etsFunctionType.cpp | 24 +- ets2panda/checker/types/ets/etsFunctionType.h | 2 - ets2panda/checker/types/ets/etsObjectType.cpp | 185 +++++- ets2panda/checker/types/ets/etsObjectType.h | 42 +- .../checker/types/ets/etsResizableArrayType.h | 6 +- ets2panda/checker/types/ets/etsStringType.h | 6 +- ets2panda/checker/types/type.cpp | 2 + ets2panda/checker/types/type.h | 3 + ets2panda/checker/types/typeRelation.h | 14 +- ets2panda/compiler/core/ETSGen.cpp | 2 +- ets2panda/compiler/core/ETSemitter.cpp | 18 +- ets2panda/compiler/core/compilerImpl.cpp | 37 +- ets2panda/compiler/core/pandagen.cpp | 2 +- ets2panda/compiler/lowering/checkerPhase.cpp | 25 +- ets2panda/compiler/lowering/checkerPhase.h | 5 +- .../compiler/lowering/ets/ambientLowering.cpp | 17 +- .../lowering/ets/arrayLiteralLowering.cpp | 2 +- .../lowering/ets/asyncMethodLowering.cpp | 6 +- .../compiler/lowering/ets/bigintLowering.cpp | 6 +- .../lowering/ets/boxedTypeLowering.cpp | 16 +- .../compiler/lowering/ets/boxedTypeLowering.h | 7 +- .../compiler/lowering/ets/boxingForLocals.cpp | 14 +- .../compiler/lowering/ets/cfgBuilderPhase.cpp | 4 +- .../ets/convertPrimitiveCastMethodCall.cpp | 2 +- .../lowering/ets/declareOverloadLowering.cpp | 8 +- ...defaultParametersInConstructorLowering.cpp | 12 +- .../lowering/ets/dynamicImportLowering.cpp | 2 +- .../compiler/lowering/ets/enumLowering.cpp | 18 +- .../lowering/ets/enumPostCheckLowering.cpp | 4 +- .../compiler/lowering/ets/expandBrackets.cpp | 6 +- .../lowering/ets/exportAnonymousConst.cpp | 28 +- .../lowering/ets/exportAnonymousConst.h | 4 +- .../ets/extensionAccessorLowering.cpp | 2 +- .../lowering/ets/genericBridgesLowering.cpp | 10 +- .../insertOptionalParametersAnnotation.cpp | 2 +- .../ets/interfaceObjectLiteralLowering.cpp | 18 +- .../compiler/lowering/ets/lambdaLowering.cpp | 84 +-- .../lowering/ets/lateInitialization.cpp | 6 +- .../lowering/ets/localClassLowering.cpp | 12 +- .../lowering/ets/objectIndexAccess.cpp | 2 +- .../compiler/lowering/ets/objectIterator.cpp | 6 +- .../lowering/ets/objectLiteralLowering.cpp | 6 +- .../compiler/lowering/ets/opAssignment.cpp | 8 +- .../ets/optionalArgumentsLowering.cpp | 3 +- .../lowering/ets/packageImplicitImport.cpp | 2 +- .../lowering/ets/partialExportClassGen.cpp | 16 +- .../lowering/ets/partialExportClassGen.h | 4 +- .../compiler/lowering/ets/recordLowering.cpp | 12 +- .../lowering/ets/resizableArrayLowering.cpp | 2 +- .../lowering/ets/restArgsLowering.cpp | 13 +- .../lowering/ets/restTupleLowering.cpp | 2 +- .../compiler/lowering/ets/setJumpTarget.cpp | 12 +- .../compiler/lowering/ets/setJumpTarget.h | 5 +- .../compiler/lowering/ets/spreadLowering.cpp | 9 +- .../lowering/ets/stringComparison.cpp | 6 +- .../lowering/ets/stringConstantsLowering.cpp | 14 +- .../lowering/ets/stringConstantsLowering.h | 7 +- .../ets/stringConstructorLowering.cpp | 2 +- .../ets/topLevelStmts/globalClassHandler.cpp | 38 +- .../ets/topLevelStmts/globalClassHandler.h | 4 +- .../topLevelStmts/globalDeclTransformer.cpp | 2 +- .../ets/topLevelStmts/importExportDecls.cpp | 8 +- .../ets/topLevelStmts/topLevelStmts.cpp | 6 +- .../lowering/ets/typeFromLowering.cpp | 2 +- .../compiler/lowering/ets/unionLowering.cpp | 20 +- ets2panda/compiler/lowering/phase.cpp | 282 +++++----- ets2panda/compiler/lowering/phase.h | 90 ++- ets2panda/compiler/lowering/phase_id.h | 56 ++ ets2panda/compiler/lowering/plugin_phase.cpp | 4 +- .../compiler/lowering/resolveIdentifiers.cpp | 37 +- .../compiler/lowering/resolveIdentifiers.h | 6 +- .../lowering/scopesInit/savedBindingsCtx.cpp | 4 +- .../lowering/scopesInit/scopesInitPhase.cpp | 9 +- ets2panda/compiler/lowering/util.cpp | 59 +- ets2panda/declgen_ets2ts/main.cpp | 2 +- .../build_system/src/build/base_mode.ts | 525 +++++++++++++++++- .../build_system/src/build/build_mode.ts | 2 +- .../src/build/compile_thread_worker.ts | 170 ++++++ ets2panda/driver/build_system/src/entry.ts | 3 +- .../build_system/src/plugins/FileManager.ts | 11 +- .../src/plugins/plugins_driver.ts | 25 +- ets2panda/driver/build_system/src/types.ts | 19 +- .../build_system/test/demo_hap/entry/a.ets | 15 + .../build_system/test/demo_hap/entry/c.ets | 4 +- .../build_system/test/demo_hap/entry/d.ets | 7 +- .../dependency_analyzer/dep_analyzer.cpp | 10 +- ets2panda/es2panda.cpp | 8 +- ets2panda/es2panda.h | 2 +- .../debugInfoDeserialization/classBuilder.cpp | 2 +- ets2panda/evaluate/scopedDebugInfoPlugin.cpp | 4 +- ets2panda/ir/annotationAllowed.h | 73 ++- ets2panda/ir/as/namedType.cpp | 7 +- ets2panda/ir/astNode.cpp | 138 ++++- ets2panda/ir/astNode.h | 180 +++--- ets2panda/ir/astNodeFlags.h | 2 + ets2panda/ir/astNodeHistory.cpp | 21 +- ets2panda/ir/astNodeHistory.h | 24 +- ets2panda/ir/base/classDefinition.cpp | 290 +++++++--- ets2panda/ir/base/classDefinition.h | 231 ++++---- ets2panda/ir/base/classElement.cpp | 57 +- ets2panda/ir/base/classElement.h | 58 +- ets2panda/ir/base/classProperty.cpp | 104 ++-- ets2panda/ir/base/classProperty.h | 14 +- ets2panda/ir/base/classStaticBlock.cpp | 16 +- ets2panda/ir/base/classStaticBlock.h | 13 +- ets2panda/ir/base/methodDefinition.cpp | 159 ++++-- ets2panda/ir/base/methodDefinition.h | 103 ++-- ets2panda/ir/base/scriptFunction.cpp | 176 ++++-- ets2panda/ir/base/scriptFunction.h | 151 +++-- ets2panda/ir/base/scriptFunctionSignature.h | 2 + ets2panda/ir/base/spreadElement.cpp | 2 +- ets2panda/ir/base/spreadElement.h | 5 - ets2panda/ir/ets/etsFunctionType.cpp | 49 +- ets2panda/ir/ets/etsFunctionType.h | 40 +- ets2panda/ir/ets/etsImportDeclaration.h | 47 +- ets2panda/ir/ets/etsModule.cpp | 3 +- ets2panda/ir/ets/etsModule.h | 70 ++- ets2panda/ir/ets/etsNeverType.cpp | 7 +- ets2panda/ir/ets/etsNullishTypes.cpp | 14 +- ets2panda/ir/ets/etsParameterExpression.cpp | 149 +++-- ets2panda/ir/ets/etsParameterExpression.h | 43 +- ets2panda/ir/ets/etsPrimitiveType.cpp | 11 +- ets2panda/ir/ets/etsPrimitiveType.h | 19 +- ets2panda/ir/ets/etsReExportDeclaration.cpp | 28 +- ets2panda/ir/ets/etsReExportDeclaration.h | 11 +- ets2panda/ir/ets/etsStringLiteralType.cpp | 7 +- ets2panda/ir/ets/etsStructDeclaration.h | 21 + ets2panda/ir/ets/etsTuple.cpp | 7 +- ets2panda/ir/ets/etsTypeReference.cpp | 38 +- ets2panda/ir/ets/etsTypeReference.h | 17 +- ets2panda/ir/ets/etsTypeReferencePart.cpp | 128 +++-- ets2panda/ir/ets/etsTypeReferencePart.h | 43 +- ets2panda/ir/ets/etsUnionType.cpp | 33 +- ets2panda/ir/ets/etsUnionType.h | 24 +- ets2panda/ir/ets/etsWildcardType.cpp | 8 +- ets2panda/ir/expression.h | 24 +- ets2panda/ir/expressions/arrayExpression.h | 5 - .../expressions/arrowFunctionExpression.cpp | 7 +- ets2panda/ir/expressions/callExpression.h | 18 + ets2panda/ir/expressions/identifier.cpp | 32 +- ets2panda/ir/expressions/identifier.h | 90 ++- ets2panda/ir/expressions/objectExpression.h | 5 - ets2panda/ir/module/importDeclaration.cpp | 69 ++- ets2panda/ir/module/importDeclaration.h | 35 +- ets2panda/ir/opaqueTypeNode.cpp | 7 +- .../ir/statements/annotationDeclaration.cpp | 97 +++- .../ir/statements/annotationDeclaration.h | 56 +- ets2panda/ir/statements/blockStatement.cpp | 32 +- ets2panda/ir/statements/blockStatement.h | 76 ++- ets2panda/ir/statements/classDeclaration.cpp | 65 ++- ets2panda/ir/statements/classDeclaration.h | 34 +- .../ir/statements/functionDeclaration.cpp | 77 ++- ets2panda/ir/statements/functionDeclaration.h | 44 +- .../ir/statements/variableDeclaration.cpp | 142 ++++- ets2panda/ir/statements/variableDeclaration.h | 49 +- ets2panda/ir/ts/tsAnyKeyword.cpp | 7 +- ets2panda/ir/ts/tsArrayType.cpp | 8 +- ets2panda/ir/ts/tsBigintKeyword.cpp | 7 +- ets2panda/ir/ts/tsBooleanKeyword.cpp | 7 +- ets2panda/ir/ts/tsConditionalType.cpp | 8 +- ets2panda/ir/ts/tsConstructorType.cpp | 7 +- ets2panda/ir/ts/tsEnumDeclaration.cpp | 117 +++- ets2panda/ir/ts/tsEnumDeclaration.h | 74 ++- ets2panda/ir/ts/tsFunctionType.cpp | 7 +- ets2panda/ir/ts/tsImportType.cpp | 8 +- ets2panda/ir/ts/tsIndexedAccessType.cpp | 8 +- ets2panda/ir/ts/tsInferType.cpp | 8 +- ets2panda/ir/ts/tsInterfaceDeclaration.cpp | 182 ++++-- ets2panda/ir/ts/tsInterfaceDeclaration.h | 97 ++-- ets2panda/ir/ts/tsIntersectionType.cpp | 8 +- ets2panda/ir/ts/tsLiteralType.cpp | 8 +- ets2panda/ir/ts/tsMappedType.cpp | 8 +- ets2panda/ir/ts/tsNamedTupleMember.cpp | 8 +- ets2panda/ir/ts/tsNeverKeyword.cpp | 7 +- ets2panda/ir/ts/tsNullKeyword.cpp | 7 +- ets2panda/ir/ts/tsNumberKeyword.cpp | 7 +- ets2panda/ir/ts/tsObjectKeyword.cpp | 7 +- ets2panda/ir/ts/tsParenthesizedType.cpp | 8 +- ets2panda/ir/ts/tsStringKeyword.cpp | 7 +- ets2panda/ir/ts/tsThisType.cpp | 7 +- ets2panda/ir/ts/tsTupleType.cpp | 8 +- ets2panda/ir/ts/tsTypeAliasDeclaration.cpp | 148 ++++- ets2panda/ir/ts/tsTypeAliasDeclaration.h | 59 +- ets2panda/ir/ts/tsTypeLiteral.cpp | 8 +- ets2panda/ir/ts/tsTypeOperator.cpp | 8 +- ets2panda/ir/ts/tsTypeParameter.cpp | 80 ++- ets2panda/ir/ts/tsTypeParameter.h | 54 +- .../ir/ts/tsTypeParameterDeclaration.cpp | 28 +- ets2panda/ir/ts/tsTypeParameterDeclaration.h | 45 +- ets2panda/ir/ts/tsTypePredicate.cpp | 8 +- ets2panda/ir/ts/tsTypeQuery.cpp | 8 +- ets2panda/ir/ts/tsTypeReference.cpp | 8 +- ets2panda/ir/ts/tsUndefinedKeyword.cpp | 7 +- ets2panda/ir/ts/tsUnionType.cpp | 8 +- ets2panda/ir/ts/tsUnknownKeyword.cpp | 7 +- ets2panda/ir/ts/tsVoidKeyword.cpp | 7 +- ets2panda/ir/typed.h | 10 +- ets2panda/lexer/token/sourceLocation.h | 10 + ets2panda/lsp/src/rename.cpp | 2 +- ets2panda/parser/ETSFormattedParser.cpp | 4 +- ets2panda/parser/ETSparser.cpp | 44 +- ets2panda/parser/ETSparser.h | 4 +- ets2panda/parser/ETSparserClasses.cpp | 1 - ets2panda/parser/ETSparserNamespaces.cpp | 2 +- ets2panda/parser/ETSparserTypes.cpp | 2 +- ets2panda/parser/parserImpl.h | 15 + ets2panda/parser/program/program.cpp | 81 ++- ets2panda/parser/program/program.h | 59 +- ets2panda/public/cppToCTypes.yaml | 4 +- ets2panda/public/es2panda_lib.cpp | 284 ++++++++-- ets2panda/public/es2panda_lib.h | 13 + ets2panda/public/public.cpp | 31 ++ ets2panda/public/public.h | 60 +- .../annotation_for_array_type01.ets | 4 +- .../ast/parser/ets/re_export/re_export_4.ets | 4 +- .../parser/ets/getterOverride-expected.txt | 6 +- .../ets/re_export/import_10-expected.txt | 2 +- .../ets/re_export/re_export_4-expected.txt | 2 +- .../ets/class_implements_interface_export.ets | 25 + .../ets/class_implements_interface_import.ets | 16 + .../astchecker/astchecker-ets-ignored.txt | 4 + .../srcdumper/srcdumper-ets-ignored.txt | 2 + .../test/unit/lowerings/node_history.cpp | 117 ++-- .../unit/lowerings/scopes_initialization.cpp | 7 +- .../get_type_of_symbol_at_location_test.cpp | 4 +- .../test/unit/lsp/isolated_declaration.cpp | 10 +- ets2panda/test/unit/lsp/lsp_rename_test.cpp | 2 +- .../unit/plugin/plugin_proceed_to_state.cpp | 2 + .../plugin_proceed_to_state_create_import.cpp | 2 +- ...oceed_to_state_find_import_declaration.cpp | 2 +- .../plugin_conversion_rule_part_i.cpp | 2 +- .../plugin_conversion_rule_part_ii.cpp | 2 +- .../plugin_conversion_rule_part_iv.cpp | 7 +- .../ast_verifier_check_abstract_call_test.cpp | 2 +- ...t_verifier_check_const_properties_test.cpp | 2 +- .../ast_verifier_getter_setter_neg_test.cpp | 16 +- .../ast_verifier_getter_setter_test.cpp | 6 +- .../unit/public/ast_verifier_short_test.cpp | 12 +- ets2panda/test/unit/sizeof_node_test.cpp | 4 +- .../test/unit/union_normalisation_test.h | 23 +- ets2panda/test/utils/ast_verifier_test.cpp | 8 +- ets2panda/test/utils/ast_verifier_test.h | 8 +- ets2panda/test/utils/checker_test.h | 22 +- ets2panda/test/utils/scope_init_test.h | 15 +- ets2panda/util/diagnosticEngine.cpp | 4 +- ets2panda/util/diagnosticEngine.h | 9 +- ets2panda/util/enumbitops.h | 18 +- ets2panda/util/es2pandaMacros.h | 1 + ets2panda/util/importPathManager.h | 8 +- ets2panda/varbinder/ETSBinder.cpp | 47 +- ets2panda/varbinder/ETSBinder.h | 32 +- ets2panda/varbinder/recordTable.h | 33 +- ets2panda/varbinder/varbinder.h | 9 + ets2panda/varbinder/variable.h | 2 +- 279 files changed, 5965 insertions(+), 2491 deletions(-) create mode 100644 ets2panda/compiler/lowering/phase_id.h create mode 100644 ets2panda/driver/build_system/src/build/compile_thread_worker.ts create mode 100644 ets2panda/public/public.cpp create mode 100644 ets2panda/test/runtime/ets/class_implements_interface_export.ets create mode 100644 ets2panda/test/runtime/ets/class_implements_interface_import.ets diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index dec0dc9a48..2ef3ae274a 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -478,6 +478,7 @@ libes2panda_sources = [ "parser/program/program.cpp", "parser/statementParser.cpp", "parser/statementTSParser.cpp", + "public/public.cpp", "util/arktsconfig.cpp", "util/bitset.cpp", "util/diagnostic.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 10cf792e94..0857184f54 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -526,6 +526,7 @@ set(ES2PANDA_LIB_SRC parser/program/program.cpp parser/statementParser.cpp parser/statementTSParser.cpp + public/public.cpp checker/checker.cpp checker/checkerContext.cpp checker/ETSAnalyzer.cpp diff --git a/ets2panda/checker/ASchecker.cpp b/ets2panda/checker/ASchecker.cpp index 3a3cb8e691..ee3cd234f8 100644 --- a/ets2panda/checker/ASchecker.cpp +++ b/ets2panda/checker/ASchecker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2024 Huawei Device Co., Ltd. + * Copyright (c) 2021 - 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 @@ -21,8 +21,6 @@ namespace ark::es2panda::checker { bool ASChecker::StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const util::Options &options) { - Initialize(varbinder); - if (options.IsDumpAst()) { std::cout << Program()->Dump() << std::endl; } diff --git a/ets2panda/checker/ASchecker.h b/ets2panda/checker/ASchecker.h index 69a80488ab..84ba809e5b 100644 --- a/ets2panda/checker/ASchecker.h +++ b/ets2panda/checker/ASchecker.h @@ -23,8 +23,9 @@ namespace ark::es2panda::checker { class ASChecker : public Checker { public: // NOLINTNEXTLINE(readability-redundant-member-init) - explicit ASChecker(util::DiagnosticEngine &diagnosticEngine, [[maybe_unused]] ArenaAllocator *allocator) - : Checker(diagnosticEngine) + explicit ASChecker([[maybe_unused]] ThreadSafeArenaAllocator *allocator, util::DiagnosticEngine &diagnosticEngine, + [[maybe_unused]] ArenaAllocator *programAllocator) + : Checker(allocator, diagnosticEngine) { } diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 0f45d11123..cc87b76f34 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1692,7 +1692,7 @@ checker::Type *ETSAnalyzer::Check(ir::Identifier *expr) const } std::pair SearchReExportsType(ETSObjectType *baseType, ir::MemberExpression *expr, - util::StringView &aliasName, ETSChecker *checker) + util::StringView const &aliasName, ETSChecker *checker) { std::pair ret {}; @@ -2753,10 +2753,9 @@ checker::Type *ETSAnalyzer::Check(ir::BlockStatement *st) const stmt->Check(checker); // NOTE! Processing of trailing blocks was moved here so that smart casts could be applied correctly - if (auto const tb = st->trailingBlocks_.find(stmt); tb != st->trailingBlocks_.end()) { - auto *const trailingBlock = tb->second; + if (auto *const trailingBlock = st->SearchStatementInTrailingBlock(stmt); trailingBlock != nullptr) { trailingBlock->Check(checker); - st->Statements().emplace(std::next(st->Statements().begin() + idx), trailingBlock); + st->AddStatement(idx, trailingBlock); ++idx; } } @@ -3092,7 +3091,8 @@ static bool CheckIsValidReturnTypeAnnotation(ir::ReturnStatement *st, ir::Script ir::TypeNode *returnTypeAnnotation, ETSChecker *checker) { // check valid `this` type as return type - if (containingFunc->GetPreferredReturnType() != nullptr || !returnTypeAnnotation->IsTSThisType()) { + if (containingFunc->GetPreferredReturnType() != nullptr || + (returnTypeAnnotation != nullptr && !returnTypeAnnotation->IsTSThisType())) { return true; } diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index f652f68e78..ff4be3487e 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -420,7 +420,7 @@ checker::Signature *GetMostSpecificSigFromExtensionFuncAndClassMethod(checker::E methodCallSig->GetSignatureInfo()->minArgCount++; auto ¶msVar = methodCallSig->Params(); paramsVar.insert(paramsVar.begin(), dummyReceiverVar); - auto ¶ms = methodCallSig->Function()->Params(); + auto ¶ms = methodCallSig->Function()->ParamsForUpdate(); params.insert(params.begin(), dummyReceiver); if (typeParamsNeeded) { auto &typeParams = methodCallSig->TypeParams(); @@ -436,7 +436,7 @@ checker::Signature *GetMostSpecificSigFromExtensionFuncAndClassMethod(checker::E methodCallSig->GetSignatureInfo()->minArgCount--; auto ¶msVar = methodCallSig->Params(); paramsVar.erase(paramsVar.begin()); - auto ¶ms = methodCallSig->Function()->Params(); + auto ¶ms = methodCallSig->Function()->ParamsForUpdate(); params.erase(params.begin()); if (typeParamsNeeded) { auto &typeParams = methodCallSig->TypeParams(); diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index 452cf67b95..01e68b8bac 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -13,6 +13,10 @@ * limitations under the License. */ +#include +#include +#include + #include "ETSchecker.h" #include "es2panda.h" @@ -33,40 +37,57 @@ namespace ark::es2panda::checker { -ETSChecker::ETSChecker(util::DiagnosticEngine &diagnosticEngine) - // NOLINTNEXTLINE(readability-redundant-member-init) - : Checker(diagnosticEngine), - arrayTypes_(Allocator()->Adapter()), - pendingConstraintCheckRecords_(Allocator()->Adapter()), - globalArraySignatures_(Allocator()->Adapter()), - dynamicIntrinsics_ {DynamicCallIntrinsicsMap {Allocator()->Adapter()}, - DynamicCallIntrinsicsMap {Allocator()->Adapter()}}, - dynamicClasses_ {DynamicClassIntrinsicsMap(Allocator()->Adapter()), - DynamicClassIntrinsicsMap(Allocator()->Adapter())}, - dynamicLambdaSignatureCache_(Allocator()->Adapter()), - functionalInterfaceCache_(Allocator()->Adapter()), - apparentTypes_(Allocator()->Adapter()), - dynamicCallNames_ {{DynamicCallNamesMap(Allocator()->Adapter()), DynamicCallNamesMap(Allocator()->Adapter())}}, - overloadSigContainer_(Allocator()->Adapter()) -{ -} - -ETSChecker::ETSChecker(util::DiagnosticEngine &diagnosticEngine, ArenaAllocator *programAllocator) - // NOLINTNEXTLINE(readability-redundant-member-init) - : Checker(diagnosticEngine, programAllocator), - arrayTypes_(Allocator()->Adapter()), - pendingConstraintCheckRecords_(Allocator()->Adapter()), - globalArraySignatures_(Allocator()->Adapter()), - dynamicIntrinsics_ {DynamicCallIntrinsicsMap {Allocator()->Adapter()}, - DynamicCallIntrinsicsMap {Allocator()->Adapter()}}, - dynamicClasses_ {DynamicClassIntrinsicsMap(Allocator()->Adapter()), - DynamicClassIntrinsicsMap(Allocator()->Adapter())}, - dynamicLambdaSignatureCache_(Allocator()->Adapter()), - functionalInterfaceCache_(Allocator()->Adapter()), - apparentTypes_(Allocator()->Adapter()), - dynamicCallNames_ {{DynamicCallNamesMap(Allocator()->Adapter()), DynamicCallNamesMap(Allocator()->Adapter())}}, - overloadSigContainer_(Allocator()->Adapter()) +void ETSChecker::ReputCheckerData() { + readdedChecker_.insert(this); + for (auto &[_, extPrograms] : Program()->ExternalSources()) { + (void)_; + auto *extProg = extPrograms.front(); + if (!extProg->IsASTLowered()) { + continue; + } + auto eChecker = extProg->Checker()->AsETSChecker(); + + if (!HasStatus(CheckerStatus::BUILTINS_INITIALIZED)) { + SetGlobalTypesHolder(eChecker->GetGlobalTypesHolder()); + AddStatus(CheckerStatus::BUILTINS_INITIALIZED); + } + + if (auto it = readdedChecker_.find(eChecker); it != readdedChecker_.end()) { + continue; + } + readdedChecker_.insert(eChecker->readdedChecker_.begin(), eChecker->readdedChecker_.end()); + auto computedAbstractMapToCopy = eChecker->GetCachedComputedAbstracts(); + for (auto &[key, value] : *computedAbstractMapToCopy) { + if (GetCachedComputedAbstracts()->find(key) != GetCachedComputedAbstracts()->end()) { + continue; + } + auto &[v1, v2] = value; + ArenaVector newV1(Allocator()->Adapter()); + ArenaUnorderedSet newV2(Allocator()->Adapter()); + newV1.assign(v1.cbegin(), v1.cend()); + newV2.insert(v2.cbegin(), v2.cend()); + GetCachedComputedAbstracts()->try_emplace(key, newV1, newV2); + } + + auto &globalArraySigs = eChecker->globalArraySignatures_; + globalArraySignatures_.insert(globalArraySigs.cbegin(), globalArraySigs.cend()); + + auto &apparentTypes = eChecker->apparentTypes_; + apparentTypes_.insert(apparentTypes.cbegin(), apparentTypes.cend()); + + auto &objectInstantiationMap = eChecker->objectInstantiationMap_; + for (auto &[key, value] : objectInstantiationMap) { + if (objectInstantiationMap_.find(key) == objectInstantiationMap_.end()) { + objectInstantiationMap_.insert(objectInstantiationMap.cbegin(), objectInstantiationMap.cend()); + } + } + + auto &invokeToArrowSignatures = eChecker->invokeToArrowSignatures_; + invokeToArrowSignatures_.insert(invokeToArrowSignatures.cbegin(), invokeToArrowSignatures.cend()); + auto &arrowToFuncInterfaces = eChecker->arrowToFuncInterfaces_; + arrowToFuncInterfaces_.insert(arrowToFuncInterfaces.cbegin(), arrowToFuncInterfaces.cend()); + } } static util::StringView InitBuiltin(ETSChecker *checker, std::string_view signature) @@ -88,8 +109,7 @@ static util::StringView InitBuiltin(ETSChecker *checker, std::string_view signat void ETSChecker::CheckObjectLiteralKeys(const ArenaVector &properties) { - static std::set names; - names.clear(); + std::set names; for (auto property : properties) { if (!property->IsProperty()) { @@ -291,8 +311,6 @@ void ETSChecker::InitializeBuiltin(varbinder::Variable *var, const util::StringV bool ETSChecker::StartChecker(varbinder::VarBinder *varbinder, const util::Options &options) { - Initialize(varbinder); - if (options.IsParseOnly()) { return false; } @@ -352,23 +370,19 @@ void ETSChecker::SetDebugInfoPlugin(evaluate::ScopedDebugInfoPlugin *debugInfo) void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis) { - if (program->IsASTChecked()) { - return; - } - auto *savedProgram = Program(); SetProgram(program); for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { - if (extProg->IsASTChecked()) { - continue; + if (!extProg->IsASTLowered()) { + extProg->PushChecker(this); + varbinder::RecordTableContext recordTableCtx(VarBinder()->AsETSBinder(), extProg); + checker::SavedCheckerContext savedContext(this, Context().Status(), Context().ContainingClass()); + AddStatus(checker::CheckerStatus::IN_EXTERNAL); + CheckProgram(extProg, VarBinder()->IsGenStdLib()); } - checker::SavedCheckerContext savedContext(this, Context().Status(), Context().ContainingClass()); - AddStatus(checker::CheckerStatus::IN_EXTERNAL); - CheckProgram(extProg, VarBinder()->IsGenStdLib()); - extProg->SetFlag(parser::ProgramFlags::AST_CHECK_PROCESSED); } } diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 06de9f47df..c57c46c019 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -25,7 +25,6 @@ #include "checker/types/ets/etsResizableArrayType.h" #include "checker/types/ets/types.h" #include "checker/resolveResult.h" -#include "ir/ts/tsInterfaceDeclaration.h" #include "ir/visitor/AstVisitor.h" #include "util/helpers.h" @@ -65,8 +64,11 @@ struct PairHash { using ComputedAbstracts = ArenaUnorderedMap, ArenaUnorderedSet>>; using ArrayMap = ArenaUnorderedMap, ETSArrayType *, PairHash>; +using ObjectInstantiationMap = ArenaUnorderedMap>; using GlobalArraySignatureMap = ArenaUnorderedMap; using DynamicCallIntrinsicsMap = ArenaUnorderedMap>; +using FunctionSignatureMap = ArenaUnorderedMap; +using FunctionInterfaceMap = ArenaUnorderedMap; using DynamicClassIntrinsicsMap = ArenaUnorderedMap; using DynamicLambdaObjectSignatureMap = ArenaUnorderedMap; using FunctionalInterfaceMap = ArenaUnorderedMap; @@ -80,8 +82,29 @@ using AstNodePtr = ir::AstNode *; class ETSChecker final : public Checker { public: - explicit ETSChecker(util::DiagnosticEngine &diagnosticEngine); - explicit ETSChecker(util::DiagnosticEngine &diagnosticEngine, ArenaAllocator *programAllocator); + explicit ETSChecker(ThreadSafeArenaAllocator *allocator, util::DiagnosticEngine &diagnosticEngine, + ThreadSafeArenaAllocator *programAllocator = nullptr) + // NOLINTNEXTLINE(readability-redundant-member-init) + : Checker(allocator, diagnosticEngine, programAllocator), + arrayTypes_(Allocator()->Adapter()), + pendingConstraintCheckRecords_(Allocator()->Adapter()), + objectInstantiationMap_(Allocator()->Adapter()), + invokeToArrowSignatures_(Allocator()->Adapter()), + arrowToFuncInterfaces_(Allocator()->Adapter()), + globalArraySignatures_(Allocator()->Adapter()), + dynamicIntrinsics_ {DynamicCallIntrinsicsMap {Allocator()->Adapter()}, + DynamicCallIntrinsicsMap {Allocator()->Adapter()}}, + dynamicClasses_ {DynamicClassIntrinsicsMap(Allocator()->Adapter()), + DynamicClassIntrinsicsMap(Allocator()->Adapter())}, + dynamicLambdaSignatureCache_(Allocator()->Adapter()), + functionalInterfaceCache_(Allocator()->Adapter()), + apparentTypes_(Allocator()->Adapter()), + dynamicCallNames_ { + {DynamicCallNamesMap(Allocator()->Adapter()), DynamicCallNamesMap(Allocator()->Adapter())}}, + overloadSigContainer_(Allocator()->Adapter()), + readdedChecker_(Allocator()->Adapter()) + { + } ~ETSChecker() override = default; @@ -172,6 +195,7 @@ public: Type *GuaranteedTypeForUncheckedCallReturn(Signature *sig); Type *GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable *prop); Type *GuaranteedTypeForUnionFieldAccess(ir::MemberExpression *memberExpression, ETSUnionType *etsUnionType); + void ReputCheckerData(); [[nodiscard]] bool IsETSChecker() const noexcept override { @@ -884,6 +908,21 @@ public: return overloadSigContainer_; } + ObjectInstantiationMap &GetObjectInstantiationMap() + { + return objectInstantiationMap_; + } + + FunctionSignatureMap &GetInvokeToArrowSignatures() + { + return invokeToArrowSignatures_; + } + + FunctionInterfaceMap &GetArrowToFuncInterfaces() + { + return arrowToFuncInterfaces_; + } + void CleanUp() override { Checker::CleanUp(); @@ -1028,6 +1067,7 @@ private: const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags); // Trailing lambda void MoveTrailingBlockToEnclosingBlockStatement(ir::CallExpression *callExpr); + ir::ScriptFunction *CreateLambdaFunction(ir::BlockStatement *trailingBlock, Signature *sig); void TransformTraillingLambda(ir::CallExpression *callExpr, Signature *sig); ArenaVector ExtendArgumentsWithFakeLamda(ir::CallExpression *callExpr); @@ -1053,6 +1093,9 @@ private: ArrayMap arrayTypes_; ArenaVector pendingConstraintCheckRecords_; + ObjectInstantiationMap objectInstantiationMap_; + FunctionSignatureMap invokeToArrowSignatures_; + FunctionInterfaceMap arrowToFuncInterfaces_; size_t constraintCheckScopesCount_ {0}; GlobalArraySignatureMap globalArraySignatures_; ComputedAbstracts *cachedComputedAbstracts_ {nullptr}; @@ -1067,6 +1110,7 @@ private: evaluate::ScopedDebugInfoPlugin *debugInfoPlugin_ {nullptr}; std::unordered_set elementStack_; ArenaVector overloadSigContainer_; + ArenaSet readdedChecker_; }; } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/JSchecker.cpp b/ets2panda/checker/JSchecker.cpp index 3efe6f5b8d..62c02cc206 100644 --- a/ets2panda/checker/JSchecker.cpp +++ b/ets2panda/checker/JSchecker.cpp @@ -23,7 +23,6 @@ namespace ark::es2panda::checker { bool JSChecker::StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const util::Options &options) { - Initialize(varbinder); varbinder->IdentifierAnalysis(); if (options.IsDumpAst()) { diff --git a/ets2panda/checker/JSchecker.h b/ets2panda/checker/JSchecker.h index 0d0a605208..3e261069aa 100644 --- a/ets2panda/checker/JSchecker.h +++ b/ets2panda/checker/JSchecker.h @@ -23,9 +23,9 @@ namespace ark::es2panda::checker { class JSChecker : public Checker { public: // NOLINTNEXTLINE(readability-redundant-member-init) - explicit JSChecker(util::DiagnosticEngine &diagnosticEngine, - [[maybe_unused]] ArenaAllocator *programAllocator = nullptr) - : Checker(diagnosticEngine) + explicit JSChecker([[maybe_unused]] ThreadSafeArenaAllocator *allocator, util::DiagnosticEngine &diagnosticEngine, + [[maybe_unused]] ThreadSafeArenaAllocator *programAllocator = nullptr) + : Checker(allocator, diagnosticEngine, programAllocator) { } diff --git a/ets2panda/checker/TSchecker.cpp b/ets2panda/checker/TSchecker.cpp index 9e820dfc4d..4fe4acde54 100644 --- a/ets2panda/checker/TSchecker.cpp +++ b/ets2panda/checker/TSchecker.cpp @@ -23,7 +23,6 @@ namespace ark::es2panda::checker { bool TSChecker::StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const util::Options &options) { - Initialize(varbinder); varbinder->IdentifierAnalysis(); if (options.IsDumpAst()) { diff --git a/ets2panda/checker/TSchecker.h b/ets2panda/checker/TSchecker.h index 83ecaa50ca..4d360a1f4f 100644 --- a/ets2panda/checker/TSchecker.h +++ b/ets2panda/checker/TSchecker.h @@ -121,8 +121,9 @@ struct TupleTypeInfo { class TSChecker : public Checker { public: // NOLINTNEXTLINE(readability-redundant-member-init) - explicit TSChecker(util::DiagnosticEngine &diagnosticEngine, [[maybe_unused]] ArenaAllocator *programAllocator) - : Checker(diagnosticEngine) + explicit TSChecker([[maybe_unused]] ThreadSafeArenaAllocator *allocator, util::DiagnosticEngine &diagnosticEngine, + [[maybe_unused]] ThreadSafeArenaAllocator *programAllocator) + : Checker(allocator, diagnosticEngine, programAllocator) { } diff --git a/ets2panda/checker/checker.cpp b/ets2panda/checker/checker.cpp index d4adeb07cc..39c4be1b59 100644 --- a/ets2panda/checker/checker.cpp +++ b/ets2panda/checker/checker.cpp @@ -20,8 +20,9 @@ #include "checker/types/ts/unionType.h" namespace ark::es2panda::checker { -Checker::Checker(util::DiagnosticEngine &diagnosticEngine, ArenaAllocator *programAllocator) - : allocator_(SpaceType::SPACE_TYPE_COMPILER, nullptr, true), +Checker::Checker(ThreadSafeArenaAllocator *allocator, util::DiagnosticEngine &diagnosticEngine, + ThreadSafeArenaAllocator *programAllocator) + : allocator_(allocator), programAllocator_(programAllocator), context_(this, CheckerStatus::NO_OPTS), diagnosticEngine_(diagnosticEngine) @@ -177,9 +178,11 @@ ScopeContext::ScopeContext(Checker *checker, varbinder::Scope *newScope) void Checker::CleanUp() { + if (!program_->IsASTLowered()) { + globalTypes_ = allocator_->New(allocator_); + } context_ = CheckerContext(this, CheckerStatus::NO_OPTS); - globalTypes_ = allocator_.New(&allocator_); - relation_ = allocator_.New(this); + relation_ = allocator_->New(this); identicalResults_.cached.clear(); assignableResults_.cached.clear(); comparableResults_.cached.clear(); diff --git a/ets2panda/checker/checker.h b/ets2panda/checker/checker.h index 8c0e0dc583..c41af2dbd8 100644 --- a/ets2panda/checker/checker.h +++ b/ets2panda/checker/checker.h @@ -50,6 +50,7 @@ namespace ark::es2panda::checker { class ETSChecker; class InterfaceType; class GlobalTypesHolder; +class SemanticAnalyzer; using StringLiteralPool = std::unordered_map; using NumberLiteralPool = std::unordered_map; @@ -63,15 +64,16 @@ using ArgRange = std::pair; class Checker { public: - explicit Checker(util::DiagnosticEngine &diagnosticEngine, ArenaAllocator *programAllocator = nullptr); + explicit Checker(ThreadSafeArenaAllocator *allocator, util::DiagnosticEngine &diagnosticEngine, + ThreadSafeArenaAllocator *programAllocator = nullptr); virtual ~Checker() = default; NO_COPY_SEMANTIC(Checker); NO_MOVE_SEMANTIC(Checker); - [[nodiscard]] ArenaAllocator *Allocator() noexcept + [[nodiscard]] ThreadSafeArenaAllocator *Allocator() noexcept { - return &allocator_; + return allocator_; } [[nodiscard]] varbinder::Scope *Scope() const noexcept @@ -114,7 +116,7 @@ public: return globalTypes_; } - void SetGlobalTypes(GlobalTypesHolder *globalTypes) noexcept + void SetGlobalTypesHolder(GlobalTypesHolder *globalTypes) { globalTypes_ = globalTypes; } @@ -232,9 +234,9 @@ public: virtual void CleanUp(); - [[nodiscard]] ArenaAllocator *ProgramAllocator() + [[nodiscard]] ThreadSafeArenaAllocator *ProgramAllocator() { - return programAllocator_ == nullptr ? &allocator_ : programAllocator_; + return programAllocator_ == nullptr ? allocator_ : programAllocator_; } protected: @@ -242,8 +244,8 @@ protected: void SetProgram(parser::Program *program); private: - ArenaAllocator allocator_; - ArenaAllocator *programAllocator_ {nullptr}; + ThreadSafeArenaAllocator *allocator_; + ThreadSafeArenaAllocator *programAllocator_ {nullptr}; CheckerContext context_; GlobalTypesHolder *globalTypes_ {nullptr}; TypeRelation *relation_; @@ -253,11 +255,11 @@ private: varbinder::Scope *scope_ {}; util::DiagnosticEngine &diagnosticEngine_; - RelationHolder identicalResults_ {{}, RelationType::IDENTICAL}; - RelationHolder assignableResults_ {{}, RelationType::ASSIGNABLE}; - RelationHolder comparableResults_ {{}, RelationType::COMPARABLE}; - RelationHolder uncheckedCastableResults_ {{}, RelationType::UNCHECKED_CASTABLE}; - RelationHolder supertypeResults_ {{}, RelationType::SUPERTYPE}; + RelationHolder identicalResults_ {Allocator(), RelationType::IDENTICAL}; + RelationHolder assignableResults_ {Allocator(), RelationType::ASSIGNABLE}; + RelationHolder comparableResults_ {Allocator(), RelationType::COMPARABLE}; + RelationHolder uncheckedCastableResults_ {Allocator(), RelationType::UNCHECKED_CASTABLE}; + RelationHolder supertypeResults_ {Allocator(), RelationType::SUPERTYPE}; std::unordered_map typeStack_; std::unordered_set namedTypeStack_; diff --git a/ets2panda/checker/ets/dynamic.cpp b/ets2panda/checker/ets/dynamic.cpp index 90abef0f88..f5d2544345 100644 --- a/ets2panda/checker/ets/dynamic.cpp +++ b/ets2panda/checker/ets/dynamic.cpp @@ -365,7 +365,7 @@ ir::ClassDeclaration *ETSChecker::BuildClass(util::StringView name, const ClassB // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *classDecl = ProgramAllocNode(classDef, ProgramAllocator()); - VarBinder()->Program()->Ast()->Statements().push_back(classDecl); + VarBinder()->Program()->Ast()->AddStatement(classDecl); classDecl->SetParent(VarBinder()->Program()->Ast()); auto varBinder = VarBinder()->AsETSBinder(); @@ -597,7 +597,7 @@ void ETSChecker::EmitDynamicModuleClassInitCall() // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *const node = ProgramAllocNode(initCall); node->SetParent(cctorBody); - cctorBody->Statements().push_back(node); + cctorBody->AddStatement(node); ProcessScopesNode(this, node); ProcessCheckerNode(this, node); @@ -620,7 +620,7 @@ void ETSChecker::BuildClassBodyFromDynamicImports(const ArenaVectorAssemblerName() = util::UString(assemblyName, ProgramAllocator()).View(); + import->SetAssemblerName(util::UString(assemblyName, ProgramAllocator()).View()); fields.insert(import->AssemblerName()); imports.push_back(import); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 167f9e40b2..d1b97e2378 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -229,7 +229,7 @@ static void ResetInferredNode(ETSChecker *checker) auto resetFuncState = [](ir::ArrowFunctionExpression *expr) { auto *func = expr->Function(); func->SetSignature(nullptr); - func->ReturnStatements().clear(); + func->ClearReturnStatements(); expr->SetTsType(nullptr); }; @@ -1098,7 +1098,7 @@ Signature *ETSChecker::ResolvePotentialTrailingLambdaWithReceiver(ir::CallExpres auto *candidateFunctionType = sig->Function()->Params().back()->AsETSParameterExpression()->TypeAnnotation()->AsETSFunctionType(); auto *currentReceiver = candidateFunctionType->Params()[0]; - trailingLambda->Function()->Params().emplace_back(currentReceiver); + trailingLambda->Function()->EmplaceParams(currentReceiver); sigContainLambdaWithReceiverAsParam.emplace_back(sig); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) signature = ValidateSignatures(sigContainLambdaWithReceiverAsParam, callExpr->TypeParams(), arguments, @@ -1108,7 +1108,7 @@ Signature *ETSChecker::ResolvePotentialTrailingLambdaWithReceiver(ir::CallExpres return signature; } sigContainLambdaWithReceiverAsParam.clear(); - trailingLambda->Function()->Params().clear(); + trailingLambda->Function()->ClearParams(); } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) return ValidateSignatures(normalSig, callExpr->TypeParams(), arguments, callExpr->Start(), "call", @@ -1224,7 +1224,7 @@ void ETSChecker::CheckObjectLiteralArguments(Signature *signature, ArenaVectorGetOverloadInfo(); + ir::OverloadInfo &ldInfo = method->GetOverloadInfoForUpdate(); ArenaVector overloads(checker->ProgramAllocator()->Adapter()); for (ir::MethodDefinition *const currentFunc : method->Overloads()) { @@ -1236,11 +1236,16 @@ static bool CollectOverload(checker::ETSChecker *checker, ir::MethodDefinition * method->Id()->Variable()->SetTsType(checker->GlobalTypeError()); return false; } - auto *const overloadType = checker->BuildMethodType(currentFunc->Function()); + + auto *const overloadType = currentFunc->TsType() != nullptr ? currentFunc->TsType()->AsETSFunctionType() + : checker->BuildMethodType(currentFunc->Function()); ldInfo.needHelperOverload |= checker->CheckIdenticalOverloads(funcType, overloadType, currentFunc, ldInfo.isDeclare); - currentFunc->SetTsType(overloadType); + if (currentFunc->TsType() == nullptr) { + currentFunc->SetTsType(overloadType); + } + auto overloadSig = currentFunc->Function()->Signature(); funcType->AddCallSignature(overloadSig); if (overloadSig->IsExtensionAccessor()) { @@ -1284,7 +1289,7 @@ checker::Type *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method) if (!CollectOverload(this, method, funcType)) { return GlobalTypeError(); } - ir::OverloadInfo &ldInfo = method->GetOverloadInfo(); + ir::OverloadInfo &ldInfo = method->GetOverloadInfoForUpdate(); ldInfo.needHelperOverload &= ldInfo.isDeclare; if (ldInfo.needHelperOverload) { @@ -1474,6 +1479,10 @@ void ETSChecker::ValidateMainSignature(ir::ScriptFunction *func) void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig) { bool isArrow = func->IsArrow(); + // note(Ekko): For extenal function overload, need to not change ast tree, for arrow type, need perferred type. + if (func->Signature() != nullptr && !isArrow) { + return; + } auto *nameVar = isArrow ? nullptr : func->Id()->Variable(); auto funcName = nameVar == nullptr ? util::StringView() : nameVar->Name(); @@ -2127,11 +2136,8 @@ void ETSChecker::MoveTrailingBlockToEnclosingBlockStatement(ir::CallExpression * } using SFunctionData = ir::ScriptFunction::ScriptFunctionData; -void ETSChecker::TransformTraillingLambda(ir::CallExpression *callExpr, Signature *sig) +ir::ScriptFunction *ETSChecker::CreateLambdaFunction(ir::BlockStatement *trailingBlock, Signature *sig) { - auto *trailingBlock = callExpr->TrailingBlock(); - ES2PANDA_ASSERT(trailingBlock != nullptr); - auto *funcParamScope = varbinder::LexicalScope(VarBinder()).GetScope(); auto paramCtx = varbinder::LexicalScope::Enter(VarBinder(), funcParamScope, false); @@ -2178,7 +2184,19 @@ void ETSChecker::TransformTraillingLambda(ir::CallExpression *callExpr, Signatur funcParamScope->BindNode(funcNode); trailingBlock->SetScope(funcScope); - ReplaceScope(funcNode->Body(), trailingBlock, funcScope); + + return funcNode; +} + +void ETSChecker::TransformTraillingLambda(ir::CallExpression *callExpr, Signature *sig) +{ + auto *trailingBlock = callExpr->TrailingBlock(); + ES2PANDA_ASSERT(trailingBlock != nullptr); + + // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + auto *funcNode = CreateLambdaFunction(trailingBlock, sig); + funcNode->AddFlag(ir::ScriptFunctionFlags::TRAILING_LAMBDA); + ReplaceScope(funcNode->Body(), trailingBlock, funcNode->Scope()); callExpr->SetTrailingBlock(nullptr); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index c799944902..82a6fdb2c2 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1669,6 +1669,9 @@ void ETSChecker::BindingsModuleObjectAddProperty(checker::ETSObjectType *moduleO for (auto [_, var] : bindings) { (void)_; auto [found, aliasedName] = FindSpecifierForModuleObject(importDecl, var->AsLocalVariable()->Name()); + if (!var->AsLocalVariable()->Declaration()->Node()->IsValidInCurrentPhase()) { + continue; + } if ((var->AsLocalVariable()->Declaration()->Node()->IsExported()) && found) { if (!aliasedName.Empty()) { moduleObjType->AddReExportAlias(var->Declaration()->Name(), aliasedName); @@ -2818,6 +2821,7 @@ ir::MethodDefinition *ETSChecker::GenerateDefaultGetterSetter(ir::ClassProperty auto classCtx = varbinder::LexicalScope::Enter(checker->VarBinder(), classScope); checker->VarBinder()->AsETSBinder()->ResolveMethodDefinition(method); + method->Function()->ClearFlag(ir::ScriptFunctionFlags::EXTERNAL); functionScope->BindName(classScope->Node()->AsClassDefinition()->InternalName()); method->Check(checker); @@ -2836,7 +2840,7 @@ ir::ClassProperty *GetImplementationClassProp(ETSChecker *checker, ir::ClassProp auto *const classProp = checker->ClassPropToImplementationProp( interfaceProp->Clone(checker->ProgramAllocator(), originalProp->Parent()), scope); classType->AddProperty(classProp->Key()->Variable()->AsLocalVariable()); - classDef->Body().push_back(classProp); + classDef->EmplaceBody(classProp); return classProp; } @@ -2903,7 +2907,7 @@ void ETSChecker::GenerateGetterSetterPropertyAndMethod(ir::ClassProperty *origin // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) ir::MethodDefinition *getter = GenerateDefaultGetterSetter(interfaceProp, classProp, scope, false, this); - classDef->Body().push_back(getter); + classDef->EmplaceBody(getter); const auto &name = getter->Key()->AsIdentifier()->Name(); diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index c5724a9d7e..cbf729d09f 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -13,12 +13,14 @@ * limitations under the License. */ +#include #include "checker/ETSchecker.h" #include "checker/ets/typeRelationContext.h" #include "checker/types/ets/etsDynamicType.h" #include "checker/types/ets/etsObjectType.h" #include "checker/types/ets/etsTupleType.h" #include "checker/types/ets/etsPartialTypeParameter.h" +#include "compiler/lowering/phase.h" #include "ir/base/classDefinition.h" #include "ir/base/classElement.h" #include "ir/base/classProperty.h" @@ -2411,10 +2413,16 @@ void ETSChecker::TransformProperties(ETSObjectType *classType) GenerateGetterSetterPropertyAndMethod(originalProp, classType); } - auto it = classDef->Body().begin(); - while (it != classDef->Body().end()) { + auto &body = classDef->Body(); + if (!std::any_of(body.cbegin(), body.cend(), [](const ir::AstNode *node) { + return node->IsClassProperty() && (node->Modifiers() & ir::ModifierFlags::GETTER_SETTER) != 0U; + })) { + return; + } + auto it = classDef->BodyForUpdate().begin(); + while (it != classDef->BodyForUpdate().end()) { if ((*it)->IsClassProperty() && ((*it)->Modifiers() & ir::ModifierFlags::GETTER_SETTER) != 0U) { - it = classDef->Body().erase(it); + it = classDef->BodyForUpdate().erase(it); } else { ++it; } @@ -2478,14 +2486,18 @@ void ETSChecker::AddElementsToModuleObject(ETSObjectType *moduleObj, const util: // This function computes effective runtime view of type Type *ETSChecker::GetApparentType(Type *type) { - if (auto it = apparentTypes_.find(type); LIKELY(it != apparentTypes_.end())) { + auto currChecker = compiler::GetPhaseManager()->Context()->GetChecker()->AsETSChecker(); + auto &apparentTypes = currChecker->apparentTypes_; + + if (auto it = apparentTypes.find(type); LIKELY(it != apparentTypes.end())) { return it->second; } - auto cached = [this, type](Type *res) { + + auto cached = [&apparentTypes, type](Type *res) { if (type != res) { - apparentTypes_.insert({type, res}); + apparentTypes.insert({type, res}); } - apparentTypes_.insert({res, res}); + apparentTypes.insert({res, res}); return res; }; @@ -2526,7 +2538,9 @@ Type *ETSChecker::GetApparentType(Type *type) Type const *ETSChecker::GetApparentType(Type const *type) const { - if (auto it = apparentTypes_.find(type); LIKELY(it != apparentTypes_.end())) { + auto currChecker = compiler::GetPhaseManager()->Context()->GetChecker()->AsETSChecker(); + auto &apparentTypes = currChecker->apparentTypes_; + if (auto it = apparentTypes.find(type); LIKELY(it != apparentTypes.end())) { return it->second; } // Relaxed for some types diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index 4c35d829af..53b6838523 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -23,6 +23,8 @@ #include "checker/types/type.h" #include "ir/statements/annotationDeclaration.h" +#include + namespace ark::es2panda::checker { ByteType *ETSChecker::CreateByteType(int8_t value) @@ -448,15 +450,18 @@ std::tuple ETSChecker::CreateBuiltinArraySign Signature *ETSChecker::CreateBuiltinArraySignature(const ETSArrayType *arrayType, size_t dim) { - auto res = globalArraySignatures_.find(arrayType); - if (res != globalArraySignatures_.end()) { + auto currentChecker = + compiler::GetPhaseManager()->Context() != nullptr ? compiler::GetPhaseManager()->Context()->GetChecker() : this; + auto &globalArraySignatures = currentChecker->AsETSChecker()->globalArraySignatures_; + auto res = globalArraySignatures.find(arrayType); + if (res != globalArraySignatures.end()) { return res->second; } auto [internalName, info] = CreateBuiltinArraySignatureInfo(arrayType, dim); auto *signature = CreateSignature(info, GlobalVoidType(), ir::ScriptFunctionFlags::NONE, false); signature->SetInternalName(internalName); - globalArraySignatures_.insert({arrayType, signature}); + globalArraySignatures.insert({arrayType, signature}); return signature; } diff --git a/ets2panda/checker/ets/typeRelationContext.cpp b/ets2panda/checker/ets/typeRelationContext.cpp index 00dcde0ae4..f8a63c3124 100644 --- a/ets2panda/checker/ets/typeRelationContext.cpp +++ b/ets2panda/checker/ets/typeRelationContext.cpp @@ -179,7 +179,7 @@ void InstantiationContext::InstantiateType(ETSObjectType *type, ArenaVectorSubstitute(checker_->Relation(), substitution)->AsETSObjectType(); - type->GetInstantiationMap().try_emplace(hash, result_->AsETSObjectType()); + type->InsertInstantiationMap(hash, result_->AsETSObjectType()); result_->AddTypeFlag(TypeFlag::GENERIC); ctScope.TryCheckConstraints(); diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index b2d95bd91d..c77f536455 100644 --- a/ets2panda/checker/ets/utilityTypeHandlers.cpp +++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp @@ -98,7 +98,7 @@ static std::pair GetPartialClassPro ir::AstNode *typeNode) { auto classDefProgram = typeNode->GetTopStatement()->AsETSModule()->Program(); - if (classDefProgram == checker->VarBinder()->Program()) { + if (classDefProgram == checker->VarBinder()->AsETSBinder()->GetGlobalRecordTable()->Program()) { return {classDefProgram, checker->VarBinder()->AsETSBinder()->GetGlobalRecordTable()}; } return {classDefProgram, checker->VarBinder()->AsETSBinder()->GetExternalRecordTable().at(classDefProgram)}; @@ -204,8 +204,11 @@ Type *ETSChecker::HandlePartialInterface(ir::TSInterfaceDeclaration *interfaceDe partialInterDecl->Variable()); } + auto savedScope = VarBinder()->TopScope(); + VarBinder()->ResetTopScope(partialProgram->GlobalScope()); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *partialType = CreatePartialTypeInterfaceDecl(interfaceDecl, typeToBePartial, partialInterDecl); + VarBinder()->ResetTopScope(savedScope); ES2PANDA_ASSERT(partialType != nullptr); NamedTypeStackElement ntse(this, partialType); @@ -465,7 +468,7 @@ void ETSChecker::CreatePartialClassDeclaration(ir::ClassDefinition *const newCla auto *const newProp = CreateNullishProperty(prop->AsClassProperty(), newClassDefinition); // Put the new property into the class declaration - newClassDefinition->Body().emplace_back(newProp); + newClassDefinition->EmplaceBody(newProp); } if (prop->IsMethodDefinition() && (prop->AsMethodDefinition()->Function()->IsGetter() || @@ -476,7 +479,7 @@ void ETSChecker::CreatePartialClassDeclaration(ir::ClassDefinition *const newCla continue; } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - newClassDefinition->Body().emplace_back(CreateNullishPropertyFromAccessor(method, newClassDefinition)); + newClassDefinition->EmplaceBody(CreateNullishPropertyFromAccessor(method, newClassDefinition)); } } if (classDef->IsDeclare()) { @@ -599,10 +602,12 @@ ir::TSInterfaceDeclaration *ETSChecker::CreateInterfaceProto(util::StringView na // Put class declaration in global scope, and in program AST partialInterface->SetParent(interfaceDeclProgram->Ast()); - interfaceDeclProgram->Ast()->Statements().push_back(partialInterface); + interfaceDeclProgram->Ast()->AddStatement(partialInterface); interfaceDeclProgram->GlobalScope()->InsertBinding(name, var); partialInterface->AddModifier(flags); + partialInterface->ClearModifier(ir::ModifierFlags::EXPORTED); + partialInterface->ClearModifier(ir::ModifierFlags::DEFAULT_EXPORT); return partialInterface; } @@ -701,7 +706,7 @@ Type *ETSChecker::CreatePartialTypeInterfaceDecl(ir::TSInterfaceDeclaration *con // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) BuildSuperPartialTypeReference(superPartialType, superPartialRefTypeParams); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - partialInterface->Extends().push_back(ProgramAllocNode(superPartialRef)); + partialInterface->EmplaceExtends(ProgramAllocNode(superPartialRef)); partialInterface->Extends().back()->SetParent(partialInterface); } } @@ -739,7 +744,7 @@ void ETSChecker::CreateConstructorForPartialType(ir::ClassDefinition *const part ctor->Id()->SetVariable(ctorId->Variable()); // Put ctor in partial class body - partialClassDef->Body().emplace_back(ctor); + partialClassDef->EmplaceBody(ctor); } ir::ClassDefinition *ETSChecker::CreateClassPrototype(util::StringView name, parser::Program *const classDeclProgram) @@ -772,7 +777,7 @@ ir::ClassDefinition *ETSChecker::CreateClassPrototype(util::StringView name, par decl->BindNode(classDef); // Put class declaration in global scope, and in program AST - classDeclProgram->Ast()->Statements().push_back(classDecl); + classDeclProgram->Ast()->AddStatement(classDecl); classDeclProgram->GlobalScope()->InsertBinding(name, var); return classDef; @@ -964,7 +969,7 @@ Type *ETSChecker::GetReadonlyType(Type *type) void ETSChecker::MakePropertiesReadonly(ETSObjectType *const classType) { - classType->UpdateTypeProperties(this, [this](auto *property, auto *propType) { + classType->UpdateTypeProperties([this](auto *property, auto *propType) { auto *newDecl = ProgramAllocator()->New(property->Name(), property->Declaration()->Node()); auto *const propCopy = property->Copy(ProgramAllocator(), newDecl); diff --git a/ets2panda/checker/types/ets/etsAsyncFuncReturnType.h b/ets2panda/checker/types/ets/etsAsyncFuncReturnType.h index e1ede4842b..e079ff71a6 100644 --- a/ets2panda/checker/types/ets/etsAsyncFuncReturnType.h +++ b/ets2panda/checker/types/ets/etsAsyncFuncReturnType.h @@ -23,7 +23,7 @@ class GlobalTypesHolder; class ETSAsyncFuncReturnType : public ETSObjectType { public: - ETSAsyncFuncReturnType(ArenaAllocator *allocator, TypeRelation *relation, ETSObjectType *promiseType) + ETSAsyncFuncReturnType(ThreadSafeArenaAllocator *allocator, TypeRelation *relation, ETSObjectType *promiseType) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_OBJECT, std::make_tuple(nullptr, ETSObjectFlags::ASYNC_FUNC_RETURN_TYPE, relation)), promiseType_(promiseType) diff --git a/ets2panda/checker/types/ets/etsBigIntType.h b/ets2panda/checker/types/ets/etsBigIntType.h index 279c5d0817..8ed5f40ccb 100644 --- a/ets2panda/checker/types/ets/etsBigIntType.h +++ b/ets2panda/checker/types/ets/etsBigIntType.h @@ -21,14 +21,14 @@ namespace ark::es2panda::checker { class ETSBigIntType : public ETSObjectType { public: - explicit ETSBigIntType(ArenaAllocator *allocator, [[maybe_unused]] ETSObjectType *super) + explicit ETSBigIntType(ThreadSafeArenaAllocator *allocator, [[maybe_unused]] ETSObjectType *super) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_BIGINT, nullptr, ETSObjectFlags::CLASS | ETSObjectFlags::BUILTIN_BIGINT | ETSObjectFlags::RESOLVED_SUPER) { SetSuperType(super); } - explicit ETSBigIntType(ArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, + explicit ETSBigIntType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, util::StringView value) : ETSObjectType( allocator, "", compiler::Signatures::BUILTIN_BIGINT, diff --git a/ets2panda/checker/types/ets/etsDynamicType.h b/ets2panda/checker/types/ets/etsDynamicType.h index eea79b4fb9..9506417407 100644 --- a/ets2panda/checker/types/ets/etsDynamicType.h +++ b/ets2panda/checker/types/ets/etsDynamicType.h @@ -28,7 +28,8 @@ class ETSDynamicType : public ETSObjectType { static constexpr auto RELATION = 2; public: - explicit ETSDynamicType(ArenaAllocator *allocator, std::tuple label, + explicit ETSDynamicType(ThreadSafeArenaAllocator *allocator, + std::tuple label, std::tuple info, bool hasDecl) : ETSObjectType(allocator, std::get(label), std::get(label), std::make_tuple(std::get(info), std::get(info) | ETSObjectFlags::DYNAMIC, diff --git a/ets2panda/checker/types/ets/etsEnumType.h b/ets2panda/checker/types/ets/etsEnumType.h index a5c6bdf33d..99e5b34528 100644 --- a/ets2panda/checker/types/ets/etsEnumType.h +++ b/ets2panda/checker/types/ets/etsEnumType.h @@ -24,7 +24,7 @@ namespace ark::es2panda::checker { class ETSEnumType : public ETSObjectType { public: - explicit ETSEnumType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, + explicit ETSEnumType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, ir::AstNode *declNode, TypeRelation *relation) : ETSObjectType(allocator, name, internalName, std::make_tuple(declNode, ETSObjectFlags::CLASS | ETSObjectFlags::ENUM_OBJECT, relation)) @@ -49,7 +49,7 @@ public: class ETSIntEnumType : public ETSEnumType { public: - explicit ETSIntEnumType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, + explicit ETSIntEnumType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, ir::AstNode *declNode, TypeRelation *relation) : ETSEnumType(allocator, name, internalName, declNode, relation) { @@ -70,8 +70,8 @@ public: class ETSStringEnumType : public ETSEnumType { public: - explicit ETSStringEnumType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, - ir::AstNode *declNode, TypeRelation *relation) + explicit ETSStringEnumType(ThreadSafeArenaAllocator *allocator, util::StringView name, + util::StringView internalName, ir::AstNode *declNode, TypeRelation *relation) : ETSEnumType(allocator, name, internalName, declNode, relation) { AddTypeFlag(checker::TypeFlag::ETS_STRING_ENUM); diff --git a/ets2panda/checker/types/ets/etsFunctionType.cpp b/ets2panda/checker/types/ets/etsFunctionType.cpp index 1df9fd28ea..6ee38c6662 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -15,6 +15,7 @@ #include "checker/ETSchecker.h" #include "checker/types/globalTypesHolder.h" +#include "compiler/lowering/phase.h" namespace ark::es2panda::checker { @@ -104,11 +105,16 @@ static ETSObjectType *FunctionTypeToFunctionalInterfaceType(ETSChecker *checker, ETSObjectType *ETSFunctionType::ArrowToFunctionalInterface(ETSChecker *checker) { - auto &cached = arrowToFuncInterface_; - if (LIKELY(cached != nullptr)) { - return cached; + auto &cached = compiler::GetPhaseManager()->Context()->GetChecker()->AsETSChecker()->GetArrowToFuncInterfaces(); + + auto found = cached.find(this); + if (LIKELY(found != cached.end())) { + return found->second; } - return cached = FunctionTypeToFunctionalInterfaceType(checker, ArrowSignature(), ArrowSignature()->MinArgCount()); + return cached + .emplace(this, + FunctionTypeToFunctionalInterfaceType(checker, ArrowSignature(), ArrowSignature()->MinArgCount())) + .first->second; } ETSObjectType *ETSFunctionType::ArrowToFunctionalInterfaceDesiredArity(ETSChecker *checker, size_t arity) @@ -121,13 +127,15 @@ ETSObjectType *ETSFunctionType::ArrowToFunctionalInterfaceDesiredArity(ETSChecke ETSFunctionType *ETSFunctionType::MethodToArrow(ETSChecker *checker) { - auto &cached = invokeToArrowSignature_; - if (LIKELY(cached != nullptr)) { - return cached; + auto &cached = compiler::GetPhaseManager()->Context()->GetChecker()->AsETSChecker()->GetInvokeToArrowSignatures(); + + auto found = cached.find(this); + if (LIKELY(found != cached.end())) { + return found->second; } ES2PANDA_ASSERT(!IsETSArrowType() && CallSignatures().size() == 1); - return cached = checker->CreateETSArrowType(CallSignatures()[0]); + return cached.emplace(this, checker->CreateETSArrowType(CallSignatures()[0])).first->second; } void ETSFunctionType::AddCallSignature(Signature *signature) diff --git a/ets2panda/checker/types/ets/etsFunctionType.h b/ets2panda/checker/types/ets/etsFunctionType.h index f59b65c709..14eea128aa 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.h +++ b/ets2panda/checker/types/ets/etsFunctionType.h @@ -165,8 +165,6 @@ private: ArenaVector extensionAccessorSigs_; util::StringView const name_; util::StringView const assemblerName_; - ETSFunctionType *invokeToArrowSignature_ {}; - ETSObjectType *arrowToFuncInterface_ {}; Signature *helperSignature_ {}; }; } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 733f658a53..61a6db0141 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -18,6 +18,11 @@ #include "checker/ETSchecker.h" #include "checker/ets/conversion.h" #include "checker/types/globalTypesHolder.h" +#include "checker/types/ets/etsAsyncFuncReturnType.h" +#include "checker/types/ets/etsEnumType.h" +#include "checker/types/ets/etsDynamicFunctionType.h" +#include "compiler/lowering/phase.h" +#include "ir/statements/annotationDeclaration.h" namespace ark::es2panda::checker { @@ -199,9 +204,8 @@ varbinder::LocalVariable *ETSObjectType::CreateSyntheticVarFromEverySignature(co ETSFunctionType *ETSObjectType::CreateMethodTypeForProp(const util::StringView &name) const { - ES2PANDA_ASSERT(GetRelation() != nullptr && GetRelation()->GetChecker() != nullptr); - auto *checker = GetRelation()->GetChecker()->AsETSChecker(); - return checker->CreateETSMethodType(name, {{}, Allocator()->Adapter()}); + ES2PANDA_ASSERT(GetRelation() != nullptr); + return GetRelation()->GetChecker()->AsETSChecker()->CreateETSMethodType(name, {{}, Allocator()->Adapter()}); } static void AddSignature(std::vector &signatures, PropertySearchFlags flags, ETSChecker *checker, @@ -856,6 +860,7 @@ void ETSObjectType::IsGenericSupertypeOf(TypeRelation *relation, ETSObjectType * Type *ETSObjectType::AsSuper(Checker *checker, varbinder::Variable *sourceVar) { + checker = GetETSChecker(); if (sourceVar == nullptr) { return nullptr; } @@ -919,9 +924,10 @@ varbinder::LocalVariable *ETSObjectType::CopyProperty(varbinder::LocalVariable * return copiedProp; } -Type *ETSObjectType::Instantiate(ArenaAllocator *const allocator, TypeRelation *const relation, +Type *ETSObjectType::Instantiate(ArenaAllocator *const allocator, TypeRelation *relation, GlobalTypesHolder *const globalTypes) { + relation = relation_; auto *const checker = relation->GetChecker()->AsETSChecker(); std::lock_guard guard {*checker->Mutex()}; auto *const base = GetOriginalBaseType(); @@ -976,7 +982,7 @@ static varbinder::LocalVariable *CopyPropertyWithTypeArguments(varbinder::LocalV auto *const checker = relation->GetChecker()->AsETSChecker(); auto *const varType = ETSChecker::IsVariableGetterSetter(prop) ? prop->TsType() : checker->GetTypeOfVariable(prop); auto *const copiedPropType = SubstituteVariableType(relation, substitution, varType); - auto *const copiedProp = prop->Copy(checker->ProgramAllocator(), prop->Declaration()); + auto *const copiedProp = prop->Copy(checker->Allocator(), prop->Declaration()); // NOTE: some situation copiedPropType we get here are types cached in Checker, // uncontrolled SetVariable will pollute the cache. if (copiedPropType->Variable() == prop || copiedPropType->Variable() == nullptr) { @@ -1036,19 +1042,26 @@ void ETSObjectType::SetCopiedTypeProperties(TypeRelation *const relation, ETSObj copiedType->RemoveObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS | ETSObjectFlags::INCOMPLETE_INSTANTIATION | ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY); copiedType->SetVariable(variable_); - copiedType->SetBaseType(base); + + // #25295 Need to do some refactor on baseType for partial + if (IsPartial() && HasObjectFlag(ETSObjectFlags::INTERFACE)) { + copiedType->SetBaseType(this); + } else { + copiedType->SetBaseType(base); + } auto const &baseTypeParams = base->TypeArguments(); copiedType->effectiveSubstitution_ = ComputeEffectiveSubstitution(relation, baseTypeParams, newTypeArgs); copiedType->SetTypeArguments(std::move(newTypeArgs)); + ES2PANDA_ASSERT(relation); copiedType->relation_ = relation; } -void ETSObjectType::UpdateTypeProperty(checker::ETSChecker *checker, varbinder::LocalVariable *const prop, - PropertyType fieldType, PropertyProcesser const &func) +void ETSObjectType::UpdateTypeProperty(varbinder::LocalVariable *const prop, PropertyType fieldType, + PropertyProcesser const &func) { - auto const propType = prop->Declaration()->Node()->Check(checker); + auto const propType = prop->Declaration()->Node()->Check(GetETSChecker()); auto *const propCopy = func(prop, propType); if (fieldType == PropertyType::INSTANCE_FIELD) { @@ -1060,36 +1073,128 @@ void ETSObjectType::UpdateTypeProperty(checker::ETSChecker *checker, varbinder:: } } -void ETSObjectType::UpdateTypeProperties(checker::ETSChecker *checker, PropertyProcesser const &func) +void ETSObjectType::UpdateTypeProperties(PropertyProcesser const &func) { AddTypeFlag(TypeFlag::READONLY); for (auto const &prop : InstanceFields()) { - UpdateTypeProperty(checker, prop.second, PropertyType::INSTANCE_FIELD, func); + UpdateTypeProperty(prop.second, PropertyType::INSTANCE_FIELD, func); } for (auto const &prop : StaticFields()) { - UpdateTypeProperty(checker, prop.second, PropertyType::STATIC_FIELD, func); + UpdateTypeProperty(prop.second, PropertyType::STATIC_FIELD, func); } if (SuperType() != nullptr) { - auto *const superProp = SuperType()->Clone(checker)->AsETSObjectType(); - superProp->UpdateTypeProperties(checker, func); + auto *const superProp = + SuperType() + ->Instantiate(allocator_, relation_, relation_->GetChecker()->GetGlobalTypesHolder()) + ->AsETSObjectType(); + superProp->UpdateTypeProperties(func); SetSuperType(superProp); } } +static util::StringView GetHashFromSubstitution(const Substitution *substitution, const bool extensionFuncFlag, + ArenaAllocator *allocator) +{ + std::vector fields; + for (auto [k, v] : *substitution) { + std::stringstream ss; + k->ToString(ss, true); + ss << ":"; + v->ToString(ss, true); + // NOTE (mmartin): change bare address to something more appropriate unique representation + ss << ":" << k << ":" << v; + fields.push_back(ss.str()); + } + std::sort(fields.begin(), fields.end()); + + std::stringstream ss; + for (auto &fstr : fields) { + ss << fstr; + ss << ";"; + } + + if (extensionFuncFlag) { + ss << "extensionFunctionType;"; + } + return util::UString(ss.str(), allocator).View(); +} + +static std::pair GetObjectTypeDeclNames(ir::AstNode *node) +{ + if (node->IsClassDefinition()) { + return {node->AsClassDefinition()->Ident()->Name(), node->AsClassDefinition()->InternalName()}; + } + if (node->IsTSInterfaceDeclaration()) { + return {node->AsTSInterfaceDeclaration()->Id()->Name(), node->AsTSInterfaceDeclaration()->InternalName()}; + } + return {node->AsAnnotationDeclaration()->GetBaseName()->Name(), node->AsAnnotationDeclaration()->InternalName()}; +} + +static std::tuple CheckForDynamicLang(ir::AstNode *declNode, util::StringView assemblerName) +{ + Language lang(Language::Id::ETS); + bool hasDecl = false; + + if (declNode->IsClassDefinition()) { + auto *clsDef = declNode->AsClassDefinition(); + lang = clsDef->Language(); + hasDecl = clsDef->IsDeclare(); + } + + if (declNode->IsTSInterfaceDeclaration()) { + auto *ifaceDecl = declNode->AsTSInterfaceDeclaration(); + lang = ifaceDecl->Language(); + hasDecl = ifaceDecl->IsDeclare(); + } + + auto res = compiler::Signatures::Dynamic::LanguageFromType(assemblerName.Utf8()); + if (res) { + lang = *res; + } + + return std::make_tuple(lang, hasDecl); +} + +ETSObjectType *ETSObjectType::CreateETSObjectType(ir::AstNode *declNode, ETSObjectFlags flags) +{ + auto const [name, internalName] = GetObjectTypeDeclNames(declNode); + + if (declNode->IsClassDefinition() && (declNode->AsClassDefinition()->IsEnumTransformed())) { + if (declNode->AsClassDefinition()->IsIntEnumTransformed()) { + return Allocator()->New(Allocator(), name, internalName, declNode, GetRelation()); + } + ES2PANDA_ASSERT(declNode->AsClassDefinition()->IsStringEnumTransformed()); + return Allocator()->New(Allocator(), name, internalName, declNode, GetRelation()); + } + + if (auto [lang, hasDecl] = CheckForDynamicLang(declNode, internalName); lang.IsDynamic()) { + return Allocator()->New(Allocator(), std::make_tuple(name, internalName, lang), + std::make_tuple(declNode, flags, GetRelation()), hasDecl); + } + + if (internalName == compiler::Signatures::BUILTIN_ARRAY) { + return Allocator()->New(Allocator(), name, + std::make_tuple(declNode, flags, GetRelation())); + } + + return Allocator()->New(Allocator(), name, internalName, + std::make_tuple(declNode, flags, GetRelation())); +} + // #22951: remove isExtensionFunctionType flag ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitution *substitution, bool cache, bool isExtensionFunctionType) { + relation = relation_; if (substitution == nullptr || substitution->empty()) { return this; } - auto *const checker = relation->GetChecker()->AsETSChecker(); auto *base = GetOriginalBaseType(); - ArenaVector newTypeArgs {Allocator()->Adapter()}; + ArenaVector newTypeArgs {allocator_->Adapter()}; const bool anyChange = SubstituteTypeArgs(relation, newTypeArgs, substitution); // Lambda types can capture type params in their bodies, normal classes cannot. // NOTE: gogabr. determine precise conditions where we do not need to copy. @@ -1098,7 +1203,7 @@ ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitut return this; } - const util::StringView hash = checker->GetHashFromSubstitution(substitution, isExtensionFunctionType); + const util::StringView hash = GetHashFromSubstitution(substitution, isExtensionFunctionType, allocator_); if (cache) { if (auto *inst = GetInstantiatedType(hash); inst != nullptr) { return inst; @@ -1110,14 +1215,15 @@ ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitut } relation->IncreaseTypeRecursionCount(base); - auto *const copiedType = checker->CreateETSObjectType(declNode_, flags_); + auto *const copiedType = CreateETSObjectType(declNode_, flags_); SetCopiedTypeProperties(relation, copiedType, std::move(newTypeArgs), base); if (isExtensionFunctionType) { copiedType->AddObjectFlag(checker::ETSObjectFlags::EXTENSION_FUNCTION); } if (cache) { - GetInstantiationMap().try_emplace(hash, copiedType); + ES2PANDA_ASSERT(copiedType->GetRelation()); + InsertInstantiationMap(hash, copiedType); } if (superType_ != nullptr) { @@ -1157,6 +1263,11 @@ ETSObjectType *ETSObjectType::SubstituteArguments(TypeRelation *relation, ArenaV return Substitute(relation, substitution); } +ETSChecker *ETSObjectType::GetETSChecker() +{ + return relation_->GetChecker()->AsETSChecker(); +} + void ETSObjectType::InstantiateProperties() const { ES2PANDA_ASSERT(relation_ != nullptr); @@ -1355,4 +1466,40 @@ void ETSObjectType::CheckVarianceRecursively(TypeRelation *relation, VarianceFla } } +ETSObjectType *ETSObjectType::GetInstantiatedType(util::StringView hash) +{ + auto &instantiationMap = + compiler::GetPhaseManager()->Context()->GetChecker()->AsETSChecker()->GetObjectInstantiationMap(); + auto found = instantiationMap.find(this); + if (found == instantiationMap.end()) { + return nullptr; + } + + auto found2 = instantiationMap.at(this).find(hash); + if (found2 == instantiationMap.at(this).end()) { + return nullptr; + } + + return found2->second; +} + +void ETSObjectType::InsertInstantiationMap(const util::StringView &key, ETSObjectType *value) +{ + auto &instantiationMap = + compiler::GetPhaseManager()->Context()->GetChecker()->AsETSChecker()->GetObjectInstantiationMap(); + if (instantiationMap.find(this) == instantiationMap.end()) { + ArenaUnorderedMap instantiation( + compiler::GetPhaseManager()->Context()->GetChecker()->AsETSChecker()->Allocator()->Adapter()); + instantiation.emplace(key, value); + instantiationMap.emplace(this, instantiation); + } + compiler::GetPhaseManager() + ->Context() + ->GetChecker() + ->AsETSChecker() + ->GetObjectInstantiationMap() + .at(this) + .try_emplace(key, value); +} + } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsObjectType.h b/ets2panda/checker/types/ets/etsObjectType.h index 9a174689dd..20e5811f3d 100644 --- a/ets2panda/checker/types/ets/etsObjectType.h +++ b/ets2panda/checker/types/ets/etsObjectType.h @@ -16,6 +16,10 @@ #ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_OBJECT_TYPE_H #define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_OBJECT_TYPE_H +#include +#include + +#include "checker/checker.h" #include "checker/types/type.h" #include "checker/types/ets/etsObjectTypeConstants.h" #include "checker/types/signature.h" @@ -37,14 +41,14 @@ public: using PropertyTraverser = std::function; using PropertyHolder = std::array(PropertyType::COUNT)>; - explicit ETSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, + explicit ETSObjectType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, ir::AstNode *declNode, ETSObjectFlags flags) : ETSObjectType(allocator, name, internalName, std::make_tuple(declNode, flags, nullptr), std::make_index_sequence(PropertyType::COUNT)> {}) { } - explicit ETSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, + explicit ETSObjectType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, std::tuple info) : ETSObjectType(allocator, name, internalName, info, std::make_index_sequence(PropertyType::COUNT)> {}) @@ -70,6 +74,8 @@ public: } } + ETSChecker *GetETSChecker(); + void SetSuperType(ETSObjectType *super) { superType_ = super; @@ -92,6 +98,7 @@ public: void SetRelation(TypeRelation *relation) { + ES2PANDA_ASSERT(relation); relation_ = relation; } @@ -158,7 +165,7 @@ public: return interfaces_; } - ArenaVector &Interfaces() + const ArenaVector &Interfaces() { return interfaces_; } @@ -276,15 +283,7 @@ public: return static_cast(flags_ & ETSObjectFlags::UNBOXABLE_TYPE); } - ETSObjectType *GetInstantiatedType(util::StringView hash) - { - auto found = instantiationMap_.find(hash); - if (found != instantiationMap_.end()) { - return found->second; - } - - return nullptr; - } + ETSObjectType *GetInstantiatedType(util::StringView hash); varbinder::Scope *GetTypeArgumentScope() const { @@ -295,10 +294,7 @@ public: return typeParams->Scope(); } - InstantiationMap &GetInstantiationMap() - { - return instantiationMap_; - } + void InsertInstantiationMap(const util::StringView &key, ETSObjectType *value); template varbinder::LocalVariable *GetOwnProperty(const util::StringView &name) const @@ -361,7 +357,7 @@ public: const util::StringView &name, PropertySearchFlags flags) const; bool CheckIdenticalFlags(ETSObjectType *other) const; - + ETSObjectType *CreateETSObjectType(ir::AstNode *declNode, ETSObjectFlags flags); void Iterate(const PropertyTraverser &cb) const; void ToString(std::stringstream &ss, bool precise) const override; void Identical(TypeRelation *relation, Type *other) override; @@ -369,7 +365,7 @@ public: void AssignmentTarget(TypeRelation *relation, Type *source) override; bool IsBoxedPrimitive() const; Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; - void UpdateTypeProperties(checker::ETSChecker *checker, PropertyProcesser const &func); + void UpdateTypeProperties(PropertyProcesser const &func); ETSObjectType *Substitute(TypeRelation *relation, const Substitution *substitution) override; ETSObjectType *Substitute(TypeRelation *relation, const Substitution *substitution, bool cache, bool isExtensionFunctionType = false); @@ -392,7 +388,7 @@ public: const ArenaVector &ReExports() const; bool IsSameBasedGeneric(TypeRelation *relation, Type const *other) const; - ArenaAllocator *Allocator() const + ThreadSafeArenaAllocator *Allocator() const { return allocator_; } @@ -414,7 +410,7 @@ protected: private: template - explicit ETSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView assemblerName, + explicit ETSObjectType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView assemblerName, std::tuple info, [[maybe_unused]] std::index_sequence s) : Type(TypeFlag::ETS_OBJECT), @@ -426,7 +422,6 @@ private: reExports_(allocator->Adapter()), reExportAlias_(allocator->Adapter()), flags_(std::get(info)), - instantiationMap_(allocator->Adapter()), typeArguments_(allocator->Adapter()), relation_(std::get(info)), constructSignatures_(allocator->Adapter()), @@ -448,7 +443,7 @@ private: void IdenticalUptoTypeArguments(TypeRelation *relation, Type *other); void SubstitutePartialTypes(TypeRelation *relation, Type *other); void IsGenericSupertypeOf(TypeRelation *relation, ETSObjectType *source); - void UpdateTypeProperty(checker::ETSChecker *checker, varbinder::LocalVariable *const prop, PropertyType fieldType, + void UpdateTypeProperty(varbinder::LocalVariable *const prop, PropertyType fieldType, PropertyProcesser const &func); varbinder::LocalVariable *SearchFieldsDecls(const util::StringView &name, PropertySearchFlags flags) const; @@ -464,7 +459,7 @@ private: ir::TSTypeParameterDeclaration *GetTypeParams() const; - ArenaAllocator *const allocator_; + ThreadSafeArenaAllocator *const allocator_; util::StringView const name_; util::StringView const internalName_; ir::AstNode *const declNode_; @@ -472,7 +467,6 @@ private: ArenaVector reExports_; ArenaMap reExportAlias_; ETSObjectFlags flags_; - InstantiationMap instantiationMap_; ArenaVector typeArguments_; ETSObjectType *superType_ {}; ETSObjectType *enclosingType_ {}; diff --git a/ets2panda/checker/types/ets/etsResizableArrayType.h b/ets2panda/checker/types/ets/etsResizableArrayType.h index 43babf404a..1301e72693 100644 --- a/ets2panda/checker/types/ets/etsResizableArrayType.h +++ b/ets2panda/checker/types/ets/etsResizableArrayType.h @@ -23,7 +23,7 @@ namespace ark::es2panda::checker { class ETSResizableArrayType : public ETSObjectType { public: - explicit ETSResizableArrayType(ArenaAllocator *allocator, ETSObjectType *super) + explicit ETSResizableArrayType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_ARRAY, nullptr, ETSObjectFlags::CLASS | ETSObjectFlags::BUILTIN_ARRAY | ETSObjectFlags::RESOLVED_SUPER), element_(nullptr) @@ -31,13 +31,13 @@ public: SetSuperType(super); } - explicit ETSResizableArrayType(ArenaAllocator *allocator, util::StringView name, + explicit ETSResizableArrayType(ThreadSafeArenaAllocator *allocator, util::StringView name, std::tuple info) : ETSObjectType(allocator, name, compiler::Signatures::BUILTIN_ARRAY, info), element_(nullptr) { } - explicit ETSResizableArrayType(ArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, + explicit ETSResizableArrayType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, Type *element) : ETSObjectType( allocator, "", compiler::Signatures::BUILTIN_ARRAY, diff --git a/ets2panda/checker/types/ets/etsStringType.h b/ets2panda/checker/types/ets/etsStringType.h index 09d15090cc..513f4deb52 100644 --- a/ets2panda/checker/types/ets/etsStringType.h +++ b/ets2panda/checker/types/ets/etsStringType.h @@ -21,14 +21,14 @@ namespace ark::es2panda::checker { class ETSStringType : public ETSObjectType { public: - explicit ETSStringType(ArenaAllocator *allocator, ETSObjectType *super) + explicit ETSStringType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_STRING, nullptr, ETSObjectFlags::CLASS | ETSObjectFlags::STRING | ETSObjectFlags::RESOLVED_SUPER) { SetSuperType(super); } - explicit ETSStringType(ArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation) + explicit ETSStringType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_STRING, std::make_tuple(nullptr, ETSObjectFlags::CLASS | ETSObjectFlags::STRING | ETSObjectFlags::RESOLVED_SUPER, @@ -37,7 +37,7 @@ public: SetSuperType(super); } - explicit ETSStringType(ArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, + explicit ETSStringType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, util::StringView value) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_STRING, std::make_tuple(nullptr, diff --git a/ets2panda/checker/types/type.cpp b/ets2panda/checker/types/type.cpp index 92368135f3..e03343c7f1 100644 --- a/ets2panda/checker/types/type.cpp +++ b/ets2panda/checker/types/type.cpp @@ -22,6 +22,8 @@ namespace ark::es2panda::checker { +std::mutex Type::idLock_ {}; + bool Type::IsETSResizableArrayType() const { return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_ARRAY); diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index 1a0895b37a..1104cada5f 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -16,6 +16,7 @@ #ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_H #define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_H +#include #include "generated/signatures.h" #include "checker/types/typeMapping.h" #include "checker/types/typeRelation.h" @@ -50,6 +51,7 @@ class Type { public: explicit Type(TypeFlag flag) : typeFlags_(flag) { + std::lock_guard lock(idLock_); static uint64_t typeId = 0; id_ = ++typeId; } @@ -58,6 +60,7 @@ public: NO_MOVE_SEMANTIC(Type); virtual ~Type() = default; + static std::mutex idLock_; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define TYPE_IS_CHECKS(typeFlag, typeName) \ diff --git a/ets2panda/checker/types/typeRelation.h b/ets2panda/checker/types/typeRelation.h index a2fa218eed..6e1ad8cb6d 100644 --- a/ets2panda/checker/types/typeRelation.h +++ b/ets2panda/checker/types/typeRelation.h @@ -16,6 +16,7 @@ #ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_RELATION_H #define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_RELATION_H +#include #include "lexer/token/sourceLocation.h" #include "generated/tokenType.h" #include "util/ustring.h" @@ -110,11 +111,18 @@ public: RelationType type; }; -using RelationMap = std::unordered_map; +using RelationMap = ArenaUnorderedMap; class RelationHolder { public: + RelationHolder(ThreadSafeArenaAllocator *allocator, RelationType relationType) + : cached(allocator->Adapter()), type(relationType) + { + } + + // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) RelationMap cached; + // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) RelationType type {}; }; @@ -245,6 +253,7 @@ public: void IncreaseTypeRecursionCount(Type *const type) { + std::lock_guard lock(mtx_); if (const auto foundType = instantiationRecursionMap_.find(type); foundType != instantiationRecursionMap_.end()) { foundType->second += 1; @@ -261,12 +270,14 @@ public: // possible to reference the correct types of it's members and methods. 2 is possibly enough, because if we // chain expressions, every one of them will be rechecked separately, thus allowing another 2 recursion. constexpr auto MAX_RECURSIVE_TYPE_INST = 2; + std::lock_guard lock(mtx_); const auto foundType = instantiationRecursionMap_.find(type); return foundType == instantiationRecursionMap_.end() ? true : (foundType->second < MAX_RECURSIVE_TYPE_INST); } void DecreaseTypeRecursionCount(Type *const type) { + std::lock_guard lock(mtx_); const auto foundType = instantiationRecursionMap_.find(type); if (foundType == instantiationRecursionMap_.end()) { return; @@ -342,6 +353,7 @@ private: RelationResult CacheLookup(const Type *source, const Type *target, const RelationHolder &holder, RelationType type) const; + std::mutex mtx_; Checker *checker_; RelationResult result_ {}; TypeRelationFlag flags_ {}; diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index e539dffc83..004427936c 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -97,7 +97,7 @@ void ETSGen::CompileAndCheck(const ir::Expression *expr) const checker::ETSChecker *ETSGen::Checker() const noexcept { - return Context()->checker->AsETSChecker(); + return Context()->GetChecker()->AsETSChecker(); } const varbinder::ETSBinder *ETSGen::VarBinder() const noexcept diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index 98dd37c7b5..8f0b822ef9 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -240,7 +240,7 @@ static std::vector> StoreExportNodes( std::vector> result; for (auto &pair : declGen) { - auto declString = pair.first; + auto declString = std::string {pair.first}; auto *node = pair.second; if (node->IsClassProperty() && node->IsConst()) { StoreEntity(literals, parser::EntityType::CLASS_PROPERTY); @@ -291,7 +291,7 @@ void ETSEmitter::GenAnnotation() if (scriptFunc->IsAsyncFunc()) { std::vector annotations; annotations.push_back(GenAnnotationAsync(scriptFunc)); - func.metadata->SetAnnotations(std::move(annotations)); + func.metadata->AddAnnotations(annotations); } Program()->AddToFunctionTable(std::move(func)); } @@ -303,7 +303,7 @@ void ETSEmitter::GenAnnotation() GenExternalRecord(recordTable, extProg); } - const auto *checker = static_cast(Context()->checker); + const auto *checker = static_cast(Context()->GetChecker()); for (auto [arrType, signature] : checker->GlobalArrayTypes()) { GenGlobalArrayRecord(arrType, signature); @@ -340,7 +340,7 @@ void ETSEmitter::GenExternalRecord(varbinder::RecordTable *recordTable, const pa GenInterfaceRecord(interfaceDecl, !isGenStdLib); } - for (auto *signature : recordTable->Signatures()) { + for (auto const *signature : recordTable->Signatures()) { auto func = GenScriptFunction(signature->Node()->AsScriptFunction(), this); if (!isGenStdLib) { @@ -348,7 +348,7 @@ void ETSEmitter::GenExternalRecord(varbinder::RecordTable *recordTable, const pa } if (func.metadata->IsForeign() && IsFromSelfHeadFile(func.name, Context()->parserProgram, extProg)) { - return; + continue; } if (Program()->functionStaticTable.find(func.name) == Program()->functionStaticTable.cend()) { @@ -547,7 +547,7 @@ std::vector ETSEmitter::GenAnnotations(const ir::ClassD auto classIdent = classDef->Ident()->Name().Mutf8(); bool isConstruct = classIdent == Signatures::JSNEW_CLASS; if (isConstruct || classIdent == Signatures::JSCALL_CLASS) { - auto *callNames = Context()->checker->AsETSChecker()->DynamicCallNames(isConstruct); + auto *callNames = Context()->GetChecker()->AsETSChecker()->DynamicCallNames(isConstruct); annotations.push_back(GenAnnotationDynamicCall(*callNames)); } @@ -756,7 +756,7 @@ LiteralArrayVector ETSEmitter::CreateLiteralArray(std::string &baseName, const i void ETSEmitter::CreateLiteralArrayProp(const ir::ClassProperty *prop, std::string &baseName, pandasm::Field &field) { - auto *checker = Context()->checker->AsETSChecker(); + auto *checker = Context()->GetChecker()->AsETSChecker(); uint8_t rank = 1; auto *elemType = checker->GetElementTypeOfArray(prop->TsType()); while (elemType->IsETSArrayType() || elemType->IsETSResizableArrayType()) { @@ -874,7 +874,7 @@ pandasm::AnnotationElement ETSEmitter::GenCustomAnnotationElement(const ir::Clas return ProcessETSEnumType(baseName, init, type); } switch (checker::ETSChecker::TypeKind( - Context()->checker->AsETSChecker()->MaybeUnboxType(const_cast(type)))) { + Context()->GetChecker()->AsETSChecker()->MaybeUnboxType(const_cast(type)))) { case checker::TypeFlag::BYTE: case checker::TypeFlag::SHORT: case checker::TypeFlag::INT: @@ -1066,7 +1066,7 @@ ir::MethodDefinition *ETSEmitter::FindAsyncImpl(ir::ScriptFunction *asyncFunc) } ir::MethodDefinition *method = (*it)->AsMethodDefinition(); - auto *checker = static_cast(Context()->checker); + auto *checker = static_cast(Context()->GetChecker()); checker::TypeRelation *typeRel = checker->Relation(); checker::SavedTypeRelationFlagsContext savedFlagsCtx(typeRel, checker::TypeRelationFlag::NO_RETURN_TYPE_CHECK); method->Function()->Signature()->IsSubtypeOf(typeRel, asyncFunc->Signature()); diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index af038f7485..1e5e752ae7 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -88,6 +88,7 @@ static public_lib::Context::CodeGenCb MakeCompileJob() RegSpiller regSpiller; ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); AstCompiler astcompiler; + compiler::SetPhaseManager(context->phaseManager); CodeGen cg(&allocator, ®Spiller, context, std::make_tuple(scope, programElement, &astcompiler)); FunctionEmitter funcEmitter(&cg, programElement); funcEmitter.Generate(); @@ -299,7 +300,18 @@ static void AddExternalPrograms(public_lib::Context *ctx, const CompilationUnit if (gt != nullptr && gt->IsETSObjectType()) { auto *relation = gt->AsETSObjectType()->GetRelation(); if (relation != nullptr) { - relation->SetChecker(ctx->checker); + relation->SetChecker(ctx->GetChecker()); + } + } + } +} + +[[maybe_unused]] static void MarkAsLowered(parser::Program &program) +{ + for (auto &[name, extPrograms] : program.ExternalSources()) { + for (auto &extProgram : extPrograms) { + if (!extProgram->IsASTLowered()) { + extProgram->MarkASTAsLowered(); } } } @@ -373,8 +385,9 @@ static void SavePermanents(public_lib::Context *ctx, parser::Program *program) varbinder->GetGlobalRecordTable()->CleanUp(); varbinder->Functions().clear(); - ctx->transitionMemory->SetGlobalTypes(ctx->checker->GetGlobalTypesHolder()); - ctx->transitionMemory->SetCachechedComputedAbstracts(ctx->checker->AsETSChecker()->GetCachedComputedAbstracts()); + ctx->transitionMemory->SetGlobalTypes(ctx->GetChecker()->GetGlobalTypesHolder()); + ctx->transitionMemory->SetCachechedComputedAbstracts( + ctx->GetChecker()->AsETSChecker()->GetCachedComputedAbstracts()); ctx->transitionMemory->AddCompiledProgram(ctx->parserProgram); } @@ -422,7 +435,9 @@ template allocator); context->config = &config; context->config->options = &unit.options; context->sourceFile = &unit.input; @@ -435,13 +450,13 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp auto parser = Parser(&program, unit.options, unit.diagnosticEngine, static_cast(unit.rawParserStatus)); context->parser = &parser; - auto checker = Checker(unit.diagnosticEngine, context->allocator); - context->checker = &checker; + parser.SetContext(context); + auto checker = Checker(context->allocator, unit.diagnosticEngine, context->allocator); + context->parserProgram = &program; + context->PushChecker(&checker); auto analyzer = Analyzer(&checker); - auto phaseManager = compiler::PhaseManager(unit.ext, context->allocator); checker.SetAnalyzer(&analyzer); - context->analyzer = checker.GetAnalyzer(); - context->parserProgram = &program; + context->PushAnalyzer(checker.GetAnalyzer()); context->codeGenCb = MakeCompileJob(); context->diagnosticEngine = &unit.diagnosticEngine; context->phaseManager = &phaseManager; @@ -450,7 +465,7 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp CreateDebuggerEvaluationPlugin(checker, *context->allocator, &program, unit.options); if (context->compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW) { checker.SetCachedComputedAbstracts(context->transitionMemory->CachedComputedAbstracts()); - checker.SetGlobalTypes(context->transitionMemory->GlobalTypes()); + checker.SetGlobalTypesHolder(context->transitionMemory->GlobalTypes()); checker.AddStatus(ark::es2panda::checker::CheckerStatus::BUILTINS_INITIALIZED); } else { checker.InitCachedComputedAbstracts(); @@ -461,11 +476,13 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp auto *varbinder = program.VarBinder(); varbinder->SetProgram(&program); varbinder->SetContext(context); - context->checker->Initialize(varbinder); + context->GetChecker()->Initialize(varbinder); if (!ExecuteParsingAndCompiling(unit, context)) { return nullptr; } + + MarkAsLowered(program); return EmitProgram(compilerImpl, context, unit); } diff --git a/ets2panda/compiler/core/pandagen.cpp b/ets2panda/compiler/core/pandagen.cpp index 85ab16b545..3438850966 100644 --- a/ets2panda/compiler/core/pandagen.cpp +++ b/ets2panda/compiler/core/pandagen.cpp @@ -1825,7 +1825,7 @@ const checker::Type *PandaGen::GetVRegType(VReg vreg) const { // We assume that all used regs have any type if (vreg.GetIndex() > NextReg().GetIndex()) { - return Context()->checker->GetGlobalTypesHolder()->GlobalAnyType(); + return Context()->GetChecker()->GetGlobalTypesHolder()->GlobalAnyType(); } return nullptr; diff --git a/ets2panda/compiler/lowering/checkerPhase.cpp b/ets2panda/compiler/lowering/checkerPhase.cpp index 019a5ce570..7f820e8168 100644 --- a/ets2panda/compiler/lowering/checkerPhase.cpp +++ b/ets2panda/compiler/lowering/checkerPhase.cpp @@ -15,21 +15,40 @@ #include "checkerPhase.h" #include "checker/checker.h" +#include "checker/ETSchecker.h" namespace ark::es2panda::compiler { +void CheckerPhase::FetchCache(public_lib::Context *ctx, parser::Program *program) +{ + // for ast-cache using + if (program->VarBinder()->Extension() != ScriptExtension::ETS) { + return; + } + ctx->GetChecker()->AsETSChecker()->ReputCheckerData(); +} + +void CheckerPhase::MarkStatementsNoCleanup(parser::Program *program) +{ + for (auto stmt : program->Ast()->Statements()) { + stmt->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP); + } +} + bool CheckerPhase::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) { + ctx->GetChecker()->Initialize(program->VarBinder()); + FetchCache(ctx, program); for (auto [_, programList] : program->ExternalSources()) { for (auto prog : programList) { - for (auto stmt : prog->Ast()->Statements()) { - stmt->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP); + if (!prog->IsASTLowered()) { + MarkStatementsNoCleanup(prog); } } } for (auto stmt : program->Ast()->Statements()) { stmt->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP); } - auto checkerResult = ctx->checker->StartChecker(ctx->parserProgram->VarBinder(), *ctx->config->options); + auto checkerResult = ctx->GetChecker()->StartChecker(ctx->parserProgram->VarBinder(), *ctx->config->options); return checkerResult; } diff --git a/ets2panda/compiler/lowering/checkerPhase.h b/ets2panda/compiler/lowering/checkerPhase.h index 03b9e6979b..f9a915da10 100644 --- a/ets2panda/compiler/lowering/checkerPhase.h +++ b/ets2panda/compiler/lowering/checkerPhase.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-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 @@ -26,8 +26,11 @@ public: { return NAME; } + void FetchCache(public_lib::Context *ctx, parser::Program *program) override; bool Perform(public_lib::Context *ctx, parser::Program *program) override; + + void MarkStatementsNoCleanup(parser::Program *program); }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/ambientLowering.cpp b/ets2panda/compiler/lowering/ets/ambientLowering.cpp index b07f25dc9b..3a52acabc8 100644 --- a/ets2panda/compiler/lowering/ets/ambientLowering.cpp +++ b/ets2panda/compiler/lowering/ets/ambientLowering.cpp @@ -92,13 +92,22 @@ ir::AstNode *AmbientLowering::CreateIndexerMethodIfNeeded(ir::AstNode *ast, publ return ast; } - ArenaVector &classBody = + const ArenaVector &classBodyConst = ast->IsClassDefinition() ? ast->AsClassDefinition()->Body() : ast->AsTSInterfaceBody()->Body(); - auto it = classBody.begin(); // Only one DummyNode is allowed in classBody for now - ES2PANDA_ASSERT( - std::count_if(classBody.begin(), classBody.end(), [](ir::AstNode *node) { return node->IsDummyNode(); }) <= 1); + ES2PANDA_ASSERT(std::count_if(classBodyConst.cbegin(), classBodyConst.cend(), + [](const ir::AstNode *node) { return node->IsDummyNode(); }) <= 1); + if (!std::any_of(classBodyConst.cbegin(), classBodyConst.cend(), [](const ir::AstNode *node) { + return node->IsDummyNode() && node->AsDummyNode()->IsDeclareIndexer(); + })) { + return ast; + } + + ArenaVector &classBody = + ast->IsClassDefinition() ? ast->AsClassDefinition()->BodyForUpdate() : ast->AsTSInterfaceBody()->Body(); + + auto it = classBody.begin(); while (it != classBody.end()) { if ((*it)->IsDummyNode() && (*it)->AsDummyNode()->IsDeclareIndexer()) { auto setDefinition = diff --git a/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp index a9aa187de8..bf9fea2cc5 100644 --- a/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp @@ -231,7 +231,7 @@ bool ArrayLiteralLowering::PerformForModule(public_lib::Context *ctx, parser::Pr { parser_ = ctx->parser->AsETSParser(); varbinder_ = ctx->parserProgram->VarBinder()->AsETSBinder(); - checker_ = ctx->checker->AsETSChecker(); + checker_ = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( [this](ir::AstNode *ast) -> AstNodePtr { if (ast->IsArrayExpression()) { diff --git a/ets2panda/compiler/lowering/ets/asyncMethodLowering.cpp b/ets2panda/compiler/lowering/ets/asyncMethodLowering.cpp index d801b5526c..9645a5ff5d 100644 --- a/ets2panda/compiler/lowering/ets/asyncMethodLowering.cpp +++ b/ets2panda/compiler/lowering/ets/asyncMethodLowering.cpp @@ -126,7 +126,7 @@ ir::MethodDefinition *CreateAsyncProxy(checker::ETSChecker *checker, ir::MethodD { ir::ScriptFunction *asyncFunc = asyncMethod->Function(); if (!asyncFunc->IsExternal()) { - checker->VarBinder()->AsETSBinder()->GetRecordTable()->Signatures().push_back(asyncFunc->Scope()); + checker->VarBinder()->AsETSBinder()->GetRecordTable()->EmplaceSignatures(asyncFunc->Scope(), asyncFunc); } ir::MethodDefinition *implMethod = CreateAsyncImplMethod(checker, asyncMethod, classDef); @@ -170,7 +170,7 @@ void ComposeAsyncImplMethod(checker::ETSChecker *checker, ir::MethodDefinition * implMethod->Function()->Id()->SetVariable(baseOverloadImplMethod->Function()->Id()->Variable()); baseOverloadImplMethod->AddOverload(implMethod); } else { - classDef->Body().push_back(implMethod); + classDef->EmplaceBody(implMethod); } } @@ -199,7 +199,7 @@ void UpdateClassDefintion(checker::ETSChecker *checker, ir::ClassDefinition *cla bool AsyncMethodLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); ir::NodeTransformer handleClassAsyncMethod = [checker](ir::AstNode *const ast) { if (ast->IsClassDefinition()) { diff --git a/ets2panda/compiler/lowering/ets/bigintLowering.cpp b/ets2panda/compiler/lowering/ets/bigintLowering.cpp index 132656ee5c..6d40b4592f 100644 --- a/ets2panda/compiler/lowering/ets/bigintLowering.cpp +++ b/ets2panda/compiler/lowering/ets/bigintLowering.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Copyright (c) 2023-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 @@ -28,7 +28,7 @@ std::string_view BigIntLowering::Name() const ir::Expression *CreateBigInt(public_lib::Context *ctx, ir::BigIntLiteral *literal) { auto parser = ctx->parser->AsETSParser(); - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); // This will change the bigint literal node into the new class instance expression: // 123456n => new BigInt("123456") @@ -90,7 +90,7 @@ bool RemoveConst(ir::BinaryExpression *expr) bool BigIntLowering::PerformForModule(public_lib::Context *const ctx, parser::Program *const program) { - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( // CC-OFFNXT(G.FMT.14-CPP) project code style diff --git a/ets2panda/compiler/lowering/ets/boxedTypeLowering.cpp b/ets2panda/compiler/lowering/ets/boxedTypeLowering.cpp index 4c51f695dd..5ad356570b 100644 --- a/ets2panda/compiler/lowering/ets/boxedTypeLowering.cpp +++ b/ets2panda/compiler/lowering/ets/boxedTypeLowering.cpp @@ -60,20 +60,9 @@ void BoxNumberLiteralArguments(ir::CallExpression *callExpr, PhaseManager *phase } } -bool BoxedTypeLowering::Perform(public_lib::Context *const ctx, parser::Program *const program) +bool BoxedTypeLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - for (const auto &[_, extPrograms] : program->ExternalSources()) { - (void)_; - for (auto *const extProg : extPrograms) { - if (extProg->GetFlag(parser::ProgramFlags::AST_BOXED_TYPE_LOWERED)) { - continue; - } - Perform(ctx, extProg); - extProg->SetFlag(parser::ProgramFlags::AST_BOXED_TYPE_LOWERED); - } - } - - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); auto parser = ctx->parser->AsETSParser(); auto phaseManager = ctx->phaseManager; program->Ast()->TransformChildrenRecursively( @@ -95,7 +84,6 @@ bool BoxedTypeLowering::Perform(public_lib::Context *const ctx, parser::Program return ast; }, Name()); - return true; } diff --git a/ets2panda/compiler/lowering/ets/boxedTypeLowering.h b/ets2panda/compiler/lowering/ets/boxedTypeLowering.h index cf124f55bb..c7d21d52b0 100644 --- a/ets2panda/compiler/lowering/ets/boxedTypeLowering.h +++ b/ets2panda/compiler/lowering/ets/boxedTypeLowering.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,10 +20,11 @@ namespace ark::es2panda::compiler { -class BoxedTypeLowering : public Phase { +class BoxedTypeLowering : public PhaseForDeclarations { public: std::string_view Name() const override; - bool Perform(public_lib::Context *ctx, parser::Program *program) override; + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/boxingForLocals.cpp b/ets2panda/compiler/lowering/ets/boxingForLocals.cpp index 2f63e74222..a0a8c9534c 100644 --- a/ets2panda/compiler/lowering/ets/boxingForLocals.cpp +++ b/ets2panda/compiler/lowering/ets/boxingForLocals.cpp @@ -119,7 +119,7 @@ static void HandleFunctionParam(public_lib::Context *ctx, ir::ETSParameterExpres ArenaMap *varsMap) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *varBinder = checker->VarBinder(); auto *id = param->Ident()->AsIdentifier(); @@ -128,7 +128,7 @@ static void HandleFunctionParam(public_lib::Context *ctx, ir::ETSParameterExpres auto *func = param->Parent()->AsScriptFunction(); ES2PANDA_ASSERT(func->Body()->IsBlockStatement()); // guaranteed after expressionLambdaLowering auto *body = func->Body()->AsBlockStatement(); - auto &bodyStmts = body->Statements(); + auto &bodyStmts = body->StatementsForUpdates(); auto *scope = body->Scope(); auto *initId = allocator->New(id->Name(), allocator); @@ -177,7 +177,7 @@ static ir::AstNode *HandleVariableDeclarator(public_lib::Context *ctx, ir::Varia ArenaMap *varsMap) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *varBinder = checker->VarBinder(); auto *id = declarator->Id()->AsIdentifier(); @@ -231,7 +231,7 @@ static bool IsBeingDeclared(ir::AstNode *ast) static bool IsPartOfBoxInitializer(public_lib::Context *ctx, ir::AstNode *ast) { ES2PANDA_ASSERT(ast->IsIdentifier()); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *id = ast->AsIdentifier(); // NOTE(gogabr): rely on caching for type instantiations, so we can use pointer comparison. @@ -248,7 +248,7 @@ static bool OnLeftSideOfAssignment(ir::AstNode *ast) static ir::AstNode *HandleReference(public_lib::Context *ctx, ir::Identifier *id, varbinder::Variable *var) { auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); // `as` is needed to account for smart types auto *res = parser->CreateFormattedExpression("@@I1.get() as @@T2", var->Name(), id->TsType()); @@ -279,8 +279,8 @@ static ir::AstNode *HandleAssignment(public_lib::Context *ctx, ir::AssignmentExp ES2PANDA_ASSERT(ass->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION); auto *parser = ctx->parser->AsETSParser(); - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); - auto *checker = ctx->checker->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *oldVar = ass->Left()->Variable(); auto *newVar = varsMap.find(oldVar)->second; diff --git a/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp b/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp index 823859d681..0a3374acc2 100644 --- a/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp +++ b/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp @@ -28,7 +28,9 @@ bool CFGBuilderPhase::Perform(public_lib::Context *ctx, parser::Program *program for (auto &[_, ext_programs] : program->ExternalSources()) { (void)_; for (auto *extProg : ext_programs) { - Perform(ctx, extProg); + if (!extProg->IsASTLowered()) { + Perform(ctx, extProg); + } } } diff --git a/ets2panda/compiler/lowering/ets/convertPrimitiveCastMethodCall.cpp b/ets2panda/compiler/lowering/ets/convertPrimitiveCastMethodCall.cpp index 9d232d1db0..3f5c3219af 100644 --- a/ets2panda/compiler/lowering/ets/convertPrimitiveCastMethodCall.cpp +++ b/ets2panda/compiler/lowering/ets/convertPrimitiveCastMethodCall.cpp @@ -47,7 +47,7 @@ static ir::AstNode *ConvertMemberExpressionToAsExpression(ir::CallExpression *ca bool ConvertPrimitiveCastMethodCall::PerformForModule(public_lib::Context *const ctx, parser::Program *const program) { - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( // CC-OFFNXT(G.FMT.14-CPP) project code style [checker](checker::AstNodePtr ast) -> checker::AstNodePtr { diff --git a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp index 613fcf10d2..c1e53dd59b 100644 --- a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp +++ b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp @@ -24,7 +24,7 @@ namespace ark::es2panda::compiler { void GenerateOverloadHelperParams(public_lib::Context *ctx, uint32_t minArg, size_t maxArg, bool hasRestVar, ArenaVector ¶ms) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; if (!hasRestVar) { @@ -58,9 +58,9 @@ void GenerateOverloadHelperParams(public_lib::Context *ctx, uint32_t minArg, siz void BuildOverloadHelperFunction(public_lib::Context *ctx, ir::MethodDefinition *method) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); auto const &[minArg, maxArg, needHelperOverload, isDeclare, hasRestVar, returnVoid] = method->GetOverloadInfo(); ES2PANDA_ASSERT(needHelperOverload); @@ -107,7 +107,7 @@ void UpdateCallSignature(public_lib::Context *ctx, ir::CallExpression *expr) { ES2PANDA_ASSERT(expr->Signature()->HasSignatureFlag(checker::SignatureFlags::DUPLICATE_ASM)); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); expr->SetTsType(nullptr); expr->Check(checker); } diff --git a/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp b/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp index d9ede70dc7..bf69507850 100644 --- a/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp +++ b/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp @@ -185,7 +185,7 @@ static void CreateFunctionOverload(ir::MethodDefinition *method, ArenaVectorSetRange(funcExpression->Range()); if (!method->IsDeclare() && method->Parent()->IsTSInterfaceBody()) { - overloadMethod->Function()->Body()->AsBlockStatement()->Statements().clear(); + overloadMethod->Function()->Body()->AsBlockStatement()->ClearStatements(); } method->AddOverload(overloadMethod); @@ -214,7 +214,15 @@ static void ClearOptionalParameters(public_lib::Context *ctx, ir::ScriptFunction { auto allocator = ctx->allocator; - for (auto *¶m : function->Params()) { + auto const ¶ms = function->Params(); + bool hasOptional = std::any_of(params.cbegin(), params.cend(), + [](ir::Expression *p) { return p->AsETSParameterExpression()->IsOptional(); }); + if (!hasOptional) { + return; + } + + auto ¶msToChange = function->ParamsForUpdate(); + for (auto *¶m : paramsToChange) { auto oldParam = param->AsETSParameterExpression(); if (oldParam->IsOptional()) { param = util::NodeAllocator::ForceSetParent(allocator, oldParam->Ident(), false, diff --git a/ets2panda/compiler/lowering/ets/dynamicImportLowering.cpp b/ets2panda/compiler/lowering/ets/dynamicImportLowering.cpp index 8cf9e00c33..b4d6f19d1b 100644 --- a/ets2panda/compiler/lowering/ets/dynamicImportLowering.cpp +++ b/ets2panda/compiler/lowering/ets/dynamicImportLowering.cpp @@ -21,7 +21,7 @@ namespace ark::es2panda::compiler { bool DynamicImportLowering::PerformForModule(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) { - ctx->checker->AsETSChecker()->BuildDynamicImportClass(); + ctx->GetChecker()->AsETSChecker()->BuildDynamicImportClass(); return true; } diff --git a/ets2panda/compiler/lowering/ets/enumLowering.cpp b/ets2panda/compiler/lowering/ets/enumLowering.cpp index f13666933d..8a503952b4 100644 --- a/ets2panda/compiler/lowering/ets/enumLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumLowering.cpp @@ -60,7 +60,7 @@ ir::MethodDefinition *MakeMethodDef(public_lib::Context *ctx, ir::ClassDefinitio auto *const methodDef = ctx->AllocNode( ir::MethodDefinitionKind::METHOD, identClone, functionExpr, function->Modifiers(), ctx->Allocator(), false); methodDef->SetParent(enumClass); - enumClass->Body().push_back(methodDef); + enumClass->EmplaceBody(methodDef); return methodDef; } @@ -152,7 +152,7 @@ template arrayIdent, arrayExpr, typeAnnotation, ir::ModifierFlags::STATIC | ir::ModifierFlags::PRIVATE | ir::ModifierFlags::READONLY, Allocator(), false); arrayClassProp->SetParent(enumClass); - enumClass->Body().push_back(arrayClassProp); + enumClass->EmplaceBody(arrayClassProp); return arrayIdent; } @@ -208,7 +208,7 @@ void EnumLoweringPhase::CreateEnumItemFields(const ir::TSEnumDeclaration *const return field; }; for (auto *const member : enumDecl->Members()) { - enumClass->Body().push_back(createEnumItemField(member->AsTSEnumMember())); + enumClass->EmplaceBody(createEnumItemField(member->AsTSEnumMember())); } } @@ -316,7 +316,7 @@ void EnumLoweringPhase::CreateCCtorForEnumClass(ir::ClassDefinition *const enumC AllocNode(ir::MethodDefinitionKind::METHOD, identClone, funcExpr, ir::ModifierFlags::PRIVATE | ir::ModifierFlags::STATIC, Allocator(), false); methodDef->SetParent(enumClass); - enumClass->Body().push_back(methodDef); + enumClass->EmplaceBody(methodDef); } ir::ClassProperty *EnumLoweringPhase::CreateOrdinalField(ir::ClassDefinition *const enumClass) @@ -327,7 +327,7 @@ ir::ClassProperty *EnumLoweringPhase::CreateOrdinalField(ir::ClassDefinition *co AllocNode(fieldIdent, nullptr, intTypeAnnotation, ir::ModifierFlags::PRIVATE | ir::ModifierFlags::READONLY, Allocator(), false); - enumClass->Body().push_back(field); + enumClass->EmplaceBody(field); field->SetParent(enumClass); return field; } @@ -377,7 +377,7 @@ ir::ScriptFunction *EnumLoweringPhase::CreateFunctionForCtorOfEnumClass(ir::Clas auto *superConstructorCall = AllocNode(callee, std::move(callArguments), nullptr, false); auto *superCallStatement = AllocNode(superConstructorCall); superCallStatement->SetParent(body); - body->Statements().push_back(superCallStatement); + body->AddStatement(superCallStatement); auto *thisExpr = Allocator()->New(); auto *fieldIdentifier = Allocator()->New(ORDINAL_NAME, Allocator()); @@ -389,7 +389,7 @@ ir::ScriptFunction *EnumLoweringPhase::CreateFunctionForCtorOfEnumClass(ir::Clas AllocNode(leftHandSide, rightHandSide, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); auto initStatement = AllocNode(initializer); initStatement->SetParent(body); - body->Statements().push_back(initStatement); + body->AddStatement(initStatement); return func; } @@ -403,7 +403,7 @@ void EnumLoweringPhase::CreateCtorForEnumClass(ir::ClassDefinition *const enumCl auto *const methodDef = AllocNode(ir::MethodDefinitionKind::CONSTRUCTOR, identClone, funcExpr, ir::ModifierFlags::PUBLIC, Allocator(), false); methodDef->SetParent(enumClass); - enumClass->Body().push_back(methodDef); + enumClass->EmplaceBody(methodDef); } void EnumLoweringPhase::ProcessEnumClassDeclaration(ir::TSEnumDeclaration *const enumDecl, @@ -539,7 +539,7 @@ bool EnumLoweringPhase::PerformForModule(public_lib::Context *ctx, parser::Progr } context_ = ctx; - checker_ = ctx->checker->AsETSChecker(); + checker_ = ctx->GetChecker()->AsETSChecker(); varbinder_ = ctx->parserProgram->VarBinder()->AsETSBinder(); program_ = program; diff --git a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp index 6e555c258c..a46a63ea5e 100644 --- a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp @@ -150,7 +150,7 @@ static ir::CallExpression *CreateCallInstanceEnumExpression(public_lib::Context auto *calleeClass = FindEnclosingClass(expr); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *varBinder = checker->VarBinder()->AsETSBinder(); auto *nearestScope = NearestScope(parent); @@ -370,7 +370,7 @@ bool EnumPostCheckLoweringPhase::PerformForModule(public_lib::Context *ctx, pars context_ = ctx; parser_ = ctx->parser->AsETSParser(); - checker_ = ctx->checker->AsETSChecker(); + checker_ = ctx->GetChecker()->AsETSChecker(); varbinder_ = ctx->parserProgram->VarBinder()->AsETSBinder(); program->Ast()->TransformChildrenRecursivelyPostorder( diff --git a/ets2panda/compiler/lowering/ets/expandBrackets.cpp b/ets2panda/compiler/lowering/ets/expandBrackets.cpp index dbe2fd35b1..1dccd5d05d 100644 --- a/ets2panda/compiler/lowering/ets/expandBrackets.cpp +++ b/ets2panda/compiler/lowering/ets/expandBrackets.cpp @@ -42,7 +42,7 @@ ir::Expression *ExpandBracketsPhase::ProcessNewArrayInstanceExpression( { auto *const parser = ctx->parser->AsETSParser(); ES2PANDA_ASSERT(parser != nullptr); - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); ES2PANDA_ASSERT(checker != nullptr); auto *dimension = newInstanceExpression->Dimension(); auto *dimType = dimension->TsType(); @@ -84,7 +84,7 @@ ir::Expression *ExpandBracketsPhase::ProcessNewMultiDimArrayInstanceExpression( { auto *const parser = ctx->parser->AsETSParser(); ES2PANDA_ASSERT(parser != nullptr); - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); ES2PANDA_ASSERT(checker != nullptr); ir::BlockExpression *returnExpression = nullptr; @@ -146,7 +146,7 @@ ir::Expression *ExpandBracketsPhase::CreateNewMultiDimArrayInstanceExpression( newInstanceExpression->SetTsType(nullptr); blockExpression->AddStatement(ctx->AllocNode(newInstanceExpression)); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); InitScopesPhaseETS::RunExternalNode(blockExpression, checker->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(blockExpression, NearestScope(blockExpression)); blockExpression->Check(checker); diff --git a/ets2panda/compiler/lowering/ets/exportAnonymousConst.cpp b/ets2panda/compiler/lowering/ets/exportAnonymousConst.cpp index 3cb3fd1c24..d67d756dec 100644 --- a/ets2panda/compiler/lowering/ets/exportAnonymousConst.cpp +++ b/ets2panda/compiler/lowering/ets/exportAnonymousConst.cpp @@ -57,14 +57,17 @@ static void HandleAnonymousConst(public_lib::Context *const ctx, parser::Program [](auto *specific) { return specific->IsDefault() && specific->GetConstantExpression() != nullptr; }); }; auto module = program->Ast(); - auto iterator = std::find_if(module->Statements().begin(), module->Statements().end(), isExportAnonymousConst); - if (iterator == module->Statements().end()) { + auto iteratorForFind = + std::find_if(module->Statements().begin(), module->Statements().end(), isExportAnonymousConst); + if (iteratorForFind == module->Statements().end()) { return; } + auto &stmt = module->StatementsForUpdates(); + auto iterator = std::find_if(stmt.begin(), stmt.end(), isExportAnonymousConst); auto *anonymousVariableDecl = CreateAnonymousVariableDecl(ctx, (*iterator)->AsExportNamedDeclaration())->AsStatement(); - module->Statements().insert(iterator, anonymousVariableDecl); + stmt.insert(iterator, anonymousVariableDecl); } static void HandleExportDefaultInExportNamedDecl(public_lib::Context *const ctx, parser::Program *const program) @@ -85,12 +88,16 @@ static void HandleExportDefaultInExportNamedDecl(public_lib::Context *const ctx, }; auto module = program->Ast(); - auto iterator = + auto iteratorConst = std::find_if(module->Statements().begin(), module->Statements().end(), exportNamedDeclarationhasDefault); - if (iterator == module->Statements().end()) { + if (iteratorConst == module->Statements().end()) { return; } + auto &stmt = module->StatementsForUpdates(); + + auto iterator = std::find_if(stmt.begin(), stmt.end(), exportNamedDeclarationhasDefault); + auto *allocator = ctx->allocator; auto *exportNamedDeclaration = (*iterator)->AsExportNamedDeclaration(); auto oldSpecifiers = exportNamedDeclaration->Specifiers(); @@ -110,20 +117,13 @@ static void HandleExportDefaultInExportNamedDecl(public_lib::Context *const ctx, newSpecifiers.push_back(specifier); } - module->Statements().insert(iterator, exportDefaulNamedDeclarations.front()); + stmt.insert(iterator, exportDefaulNamedDeclarations.front()); exportNamedDeclaration->ReplaceSpecifiers(newSpecifiers); exportNamedDeclaration->ClearModifier(ir::ModifierFlags::DEFAULT_EXPORT); } -bool ExportAnonymousConstPhase::Perform(public_lib::Context *const ctx, parser::Program *const program) +bool ExportAnonymousConstPhase::PerformForModule(public_lib::Context *const ctx, parser::Program *const program) { - for (auto &[_, ext_programs] : program->ExternalSources()) { - (void)_; - for (auto *extProg : ext_programs) { - Perform(ctx, extProg); - } - } - HandleExportDefaultInExportNamedDecl(ctx, program); HandleAnonymousConst(ctx, program); return true; diff --git a/ets2panda/compiler/lowering/ets/exportAnonymousConst.h b/ets2panda/compiler/lowering/ets/exportAnonymousConst.h index ba1b37d491..13c3e56bc2 100644 --- a/ets2panda/compiler/lowering/ets/exportAnonymousConst.h +++ b/ets2panda/compiler/lowering/ets/exportAnonymousConst.h @@ -20,14 +20,14 @@ namespace ark::es2panda::compiler { -class ExportAnonymousConstPhase : public Phase { +class ExportAnonymousConstPhase : public PhaseForDeclarations { public: std::string_view Name() const override { return "ExportAnonymousConstPhase"; } - bool Perform(public_lib::Context *ctx, parser::Program *program) override; + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/extensionAccessorLowering.cpp b/ets2panda/compiler/lowering/ets/extensionAccessorLowering.cpp index ab70ff5880..bb3fcbff99 100644 --- a/ets2panda/compiler/lowering/ets/extensionAccessorLowering.cpp +++ b/ets2panda/compiler/lowering/ets/extensionAccessorLowering.cpp @@ -133,7 +133,7 @@ bool ExtensionAccessorPhase::PerformForModule(public_lib::Context *ctx, parser:: return true; } - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( [&checker](ir::AstNode *const node) -> AstNodePtr { return CheckAndReturnNode(checker, node); }, Name()); return true; diff --git a/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp b/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp index 36ce44662c..1aa0c072ea 100644 --- a/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp +++ b/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp @@ -91,7 +91,7 @@ void GenericBridgesPhase::AddGenericBridge(ir::ClassDefinition const *const clas bridgeMethod->AddAstNodeFlags(methodDefinition->GetAstNodeFlags()); bridgeMethod->SetParent(const_cast(classDefinition)); - auto *varBinder = context_->checker->VarBinder()->AsETSBinder(); + auto *varBinder = context_->GetChecker()->VarBinder()->AsETSBinder(); auto *scope = NearestScope(methodDefinition); auto scopeGuard = varbinder::LexicalScope::Enter(varBinder, scope); InitScopesPhaseETS::RunExternalNode(bridgeMethod, varBinder); @@ -100,7 +100,7 @@ void GenericBridgesPhase::AddGenericBridge(ir::ClassDefinition const *const clas true}; varBinder->AsETSBinder()->ResolveReferencesForScopeWithContext(bridgeMethod, scope); - auto *checker = context_->checker->AsETSChecker(); + auto *checker = context_->GetChecker()->AsETSChecker(); auto const checkerCtx = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_CLASS | checker::CheckerStatus::IGNORE_VISIBILITY | @@ -128,7 +128,7 @@ void GenericBridgesPhase::ProcessScriptFunction(ir::ClassDefinition const *const ir::MethodDefinition *const derivedMethod, Substitutions const &substitutions) const { - auto *const checker = context_->checker->AsETSChecker(); + auto *const checker = context_->GetChecker()->AsETSChecker(); auto *const relation = checker->Relation(); auto const overrides = [checker, relation, classDefinition](checker::Signature const *source, @@ -199,7 +199,7 @@ void GenericBridgesPhase::CreateGenericBridges(ir::ClassDefinition const *const auto const &classBody = classDefinition->Body(); // Collect type parameters defaults/constraints in the derived class - auto *checker = context_->checker->AsETSChecker(); + auto *checker = context_->GetChecker()->AsETSChecker(); substitutions.derivedConstraints = checker->NewSubstitution(); auto const *const classType = classDefinition->TsType()->AsETSObjectType(); @@ -239,7 +239,7 @@ GenericBridgesPhase::Substitutions GenericBridgesPhase::GetSubstitutions( auto const parameterNumber = typeParameters.size(); ES2PANDA_ASSERT(parameterNumber == typeArguments.size()); - auto *checker = context_->checker->AsETSChecker(); + auto *checker = context_->GetChecker()->AsETSChecker(); Substitutions substitutions {}; substitutions.derivedSubstitutions = checker->NewSubstitution(); substitutions.baseConstraints = checker->NewSubstitution(); diff --git a/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.cpp b/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.cpp index d8bd398120..44d8ae95b5 100644 --- a/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.cpp +++ b/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.cpp @@ -98,7 +98,7 @@ static void TryInsertDefaultAnnotation(public_lib::Context *ctx, ir::AstNode *no auto methodFunc = methodDef->Function(); auto defaultAnno = CreateDefaultAnnotationUsageForFunction(ctx, methodFunc); if (defaultAnno != nullptr) { - methodFunc->Annotations().emplace_back(defaultAnno->AsAnnotationUsage()); + methodFunc->EmplaceAnnotations(defaultAnno->AsAnnotationUsage()); defaultAnno->SetParent(methodFunc); RefineSourceRanges(defaultAnno); } diff --git a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp index 7b00e071ae..c88ab3572b 100644 --- a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp @@ -48,7 +48,7 @@ static inline bool IsAbstractClassType(const checker::Type *type) static ir::AstNode *CreateAnonClassImplCtor(public_lib::Context *ctx, ArenaVector &readonlyFields) { - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); auto *const parser = ctx->parser->AsETSParser(); checker::ETSChecker::ClassInitializerBuilder initBuilder = [ctx, checker, parser, readonlyFields](ArenaVector *statements, @@ -204,14 +204,14 @@ static void AnnotateGeneratedAnonClass(checker::ETSChecker *checker, ir::ClassDe annoUsage->AddModifier(ir::ModifierFlags::ANNOTATION_USAGE); annoUsage->SetParent(classDef); annoId->SetParent(annoUsage); - classDef->Annotations().emplace_back(annoUsage); + classDef->AddAnnotations(annoUsage); RefineSourceRanges(annoUsage); CheckLoweredNode(checker->VarBinder()->AsETSBinder(), checker, annoUsage); } static void GenerateAnonClassTypeFromInterface(public_lib::Context *ctx, ir::TSInterfaceDeclaration *ifaceNode) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); if (ifaceNode->GetAnonClass() != nullptr) { return; @@ -255,7 +255,7 @@ static void GenerateAnonClassTypeFromInterface(public_lib::Context *ctx, ir::TSI auto *classImplements = ctx->AllocNode( ctx->AllocNode(ifaceNode->TsType(), ctx->Allocator())); classImplements->SetParent(classDef); - classDef->Implements().emplace_back(classImplements); + classDef->EmplaceImplements(classImplements); classType->RemoveObjectFlag(checker::ETSObjectFlags::RESOLVED_INTERFACES); checker->GetInterfacesOfClass(classType); @@ -264,7 +264,7 @@ static void GenerateAnonClassTypeFromInterface(public_lib::Context *ctx, ir::TSI static void GenerateAnonClassTypeFromAbstractClass(public_lib::Context *ctx, ir::ClassDefinition *abstractClassNode) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); if (abstractClassNode->GetAnonClass() != nullptr) { return; @@ -341,7 +341,7 @@ static checker::Type *ProcessDeclNode(checker::ETSChecker *checker, checker::ETS static void HandleInterfaceLowering(public_lib::Context *ctx, ir::ObjectExpression *objExpr) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *targetType = objExpr->TsType(); checker->CheckObjectLiteralKeys(objExpr->Properties()); @@ -433,6 +433,9 @@ bool InterfaceObjectLiteralLowering::Perform(public_lib::Context *ctx, parser::P for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { + if (extProg->IsASTLowered()) { + continue; + } auto *savedProgram = varbinder->Program(); auto *savedRecordTable = varbinder->GetRecordTable(); auto *savedTopScope = varbinder->TopScope(); @@ -451,6 +454,9 @@ bool InterfaceObjectLiteralLowering::Perform(public_lib::Context *ctx, parser::P for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { + if (extProg->IsASTLowered()) { + continue; + } TransfromInterfaceLiteral(ctx, extProg); } } diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index 15f279ea37..782f6e5c10 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -75,16 +75,19 @@ static bool CheckIfNeedThis(ir::ArrowFunctionExpression *lambda, checker::ETSChe } static size_t g_calleeCount = 0; +static std::mutex g_calleeCountMutex {}; // Make calleeCount behaviour predictable static void ResetCalleeCount() { + std::lock_guard lock(g_calleeCountMutex); g_calleeCount = 0; } static util::StringView CreateCalleeName(ArenaAllocator *allocator) { auto name = util::UString(util::StringView("lambda$invoke$"), allocator); + std::lock_guard lock(g_calleeCountMutex); name.Append(std::to_string(g_calleeCount++)); return name.View(); } @@ -98,7 +101,7 @@ static std::pair Clon } auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *newScope = allocator->New(allocator, enclosingScope); auto newTypeParams = ArenaVector(allocator->Adapter()); @@ -160,8 +163,8 @@ ParamsAndVarMap CreateLambdaCalleeParameters(public_lib::Context *ctx, ir::Arrow varbinder::ParamScope *paramScope, checker::Substitution *substitution) { auto allocator = ctx->allocator; - auto checker = ctx->checker->AsETSChecker(); - auto varBinder = ctx->checker->VarBinder(); + auto checker = ctx->GetChecker()->AsETSChecker(); + auto varBinder = ctx->GetChecker()->VarBinder(); auto resParams = ArenaVector(allocator->Adapter()); auto varMap = ArenaMap(allocator->Adapter()); @@ -261,7 +264,7 @@ static ir::MethodDefinition *SetUpCalleeMethod(public_lib::Context *ctx, LambdaI varbinder::Scope *scopeForMethod) { auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); auto *calleeClass = info->calleeClass; auto *funcScope = func->Scope(); @@ -278,7 +281,7 @@ static ir::MethodDefinition *SetUpCalleeMethod(public_lib::Context *ctx, LambdaI auto *funcExpr = util::NodeAllocator::ForceSetParent(allocator, func); auto *method = util::NodeAllocator::ForceSetParent( allocator, ir::MethodDefinitionKind::METHOD, calleeNameClone, funcExpr, modifierFlags, allocator, false); - calleeClass->Definition()->Body().push_back(method); + calleeClass->Definition()->EmplaceBody(method); method->SetParent(calleeClass->Definition()); auto *var = @@ -300,9 +303,9 @@ static ir::MethodDefinition *SetUpCalleeMethod(public_lib::Context *ctx, LambdaI varbinder::BoundContext bctx {varBinder->GetRecordTable(), calleeClass->Definition(), true}; varBinder->ResolveReferencesForScopeWithContext(func, funcScope); - auto checkerCtx = checker::SavedCheckerContext(ctx->checker, checker::CheckerStatus::IN_CLASS, + auto checkerCtx = checker::SavedCheckerContext(ctx->GetChecker(), checker::CheckerStatus::IN_CLASS, calleeClass->Definition()->TsType()->AsETSObjectType()); - method->Check(ctx->checker->AsETSChecker()); + method->Check(ctx->GetChecker()->AsETSChecker()); return method; } @@ -312,8 +315,8 @@ static ir::MethodDefinition *CreateCalleeMethod(public_lib::Context *ctx, ir::Ar LambdaInfo const *info, CalleeMethodInfo const *cmInfo) { auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); - auto *checker = ctx->checker->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *classScope = info->calleeClass->Definition()->Scope()->AsClassScope(); @@ -381,7 +384,7 @@ static ir::MethodDefinition *CreateCallee(public_lib::Context *ctx, ir::ArrowFun LambdaInfo const *info) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *body = lambda->Function()->Body()->AsBlockStatement(); auto calleeName = lambda->Function()->IsAsyncFunc() ? (util::UString {checker::ETSChecker::GetAsyncImplName(info->name), allocator}).View() @@ -420,7 +423,7 @@ static void CreateLambdaClassFields(public_lib::Context *ctx, ir::ClassDefinitio { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto props = ArenaVector(allocator->Adapter()); if (info->callReceiver != nullptr) { @@ -445,7 +448,7 @@ static void CreateLambdaClassConstructor(public_lib::Context *ctx, ir::ClassDefi { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto params = ArenaVector(allocator->Adapter()); auto makeParam = [checker, allocator, substitution, ¶ms](util::StringView name, checker::Type *type) { @@ -491,7 +494,7 @@ static void CreateLambdaClassConstructor(public_lib::Context *ctx, ir::ClassDefi allocator, ir::MethodDefinitionKind::CONSTRUCTOR, constructorId->Clone(allocator, nullptr), funcExpr, ir::ModifierFlags::NONE, allocator, false); - classDefinition->Body().push_back(ctor); + classDefinition->EmplaceBody(ctor); ctor->SetParent(classDefinition); } @@ -506,7 +509,7 @@ static ArenaVector CreateRestArgumentsArrayReall auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *restParameterType = lciInfo->lambdaSignature->RestVar()->TsType(); auto *restParameterSubstituteType = restParameterType->Substitute(checker->Relation(), lciInfo->substitution); @@ -560,14 +563,14 @@ static ArenaVector CreateRestArgumentsArrayReall checker->MaybeBoxType(elementType), restParameterIndex, restParameterIndex); } - return ArenaVector(std::move(args->AsBlockStatement()->Statements())); + return ArenaVector(args->AsBlockStatement()->Statements()); } static void CreateInvokeMethodRestParameter(public_lib::Context *ctx, LambdaClassInvokeInfo *lciInfo, ArenaVector *params) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *anyType = checker->GlobalETSNullishObjectType(); auto *restIdent = Gensym(allocator); @@ -595,7 +598,7 @@ static ArenaVector CreateCallArgumentsForLambdaClassInvoke(pub { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto callArguments = ArenaVector(allocator->Adapter()); for (auto *captured : *info->capturedVars) { @@ -670,7 +673,7 @@ static ir::BlockStatement *CreateLambdaClassInvokeBody(public_lib::Context *ctx, { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *anyType = checker->GlobalETSNullishObjectType(); auto *call = CreateCallForLambdaClassInvoke(ctx, info, lciInfo, wrapToObject); @@ -698,7 +701,7 @@ static void CreateLambdaClassInvokeMethod(public_lib::Context *ctx, LambdaInfo c bool wrapToObject) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *anyType = checker->GlobalETSNullishObjectType(); auto params = ArenaVector(allocator->Adapter()); @@ -738,7 +741,7 @@ static void CreateLambdaClassInvokeMethod(public_lib::Context *ctx, LambdaInfo c false); ES2PANDA_ASSERT(!invokeMethod->IsStatic()); - lciInfo->classDefinition->Body().push_back(invokeMethod); + lciInfo->classDefinition->EmplaceBody(invokeMethod); invokeMethod->SetParent(lciInfo->classDefinition); } @@ -800,8 +803,8 @@ static ir::ClassDeclaration *CreateEmptyLambdaClassDeclaration(public_lib::Conte { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); auto lambdaClassName = util::UString {std::string_view {"LambdaObject-"}, allocator}; lambdaClassName.Append(info->calleeClass->Definition()->Ident()->Name()).Append("$").Append(info->name); @@ -822,7 +825,7 @@ static ir::ClassDeclaration *CreateEmptyLambdaClassDeclaration(public_lib::Conte auto *classDefinition = classDeclaration->Definition(); // Adjust the class definition compared to what the parser gives. - classDefinition->Body().clear(); // remove the default empty constructor + classDefinition->ClearBody(); // remove the default empty constructor classDefinition->AddModifier(ir::ModifierFlags::PUBLIC | ir::ModifierFlags::FUNCTIONAL); if (newTypeParams != nullptr) { classDefinition->SetTypeParams(newTypeParams); @@ -830,7 +833,7 @@ static ir::ClassDeclaration *CreateEmptyLambdaClassDeclaration(public_lib::Conte } auto *program = varBinder->GetRecordTable()->Program(); - program->Ast()->Statements().push_back(classDeclaration); + program->Ast()->AddStatement(classDeclaration); classDeclaration->SetParent(program->Ast()); return classDeclaration; @@ -839,8 +842,8 @@ static ir::ClassDeclaration *CreateEmptyLambdaClassDeclaration(public_lib::Conte static ir::ClassDeclaration *CreateLambdaClass(public_lib::Context *ctx, checker::ETSFunctionType *fntype, ir::MethodDefinition *callee, LambdaInfo const *info) { - auto *checker = ctx->checker->AsETSChecker(); - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); auto *oldTypeParams = (info->enclosingFunction != nullptr) ? info->enclosingFunction->TypeParams() : nullptr; auto [newTypeParams, subst0] = @@ -895,8 +898,8 @@ static ir::ETSNewClassInstanceExpression *CreateConstructorCall(public_lib::Cont LambdaInfo const *info) { auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); - auto *checker = ctx->checker->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto args = ArenaVector(allocator->Adapter()); if (info->callReceiver != nullptr) { @@ -923,9 +926,9 @@ static ir::ETSNewClassInstanceExpression *CreateConstructorCall(public_lib::Cont auto lexScope = varbinder::LexicalScope::Enter(varBinder, nearestScope); varBinder->ResolveReferencesForScopeWithContext(newExpr, nearestScope); - auto checkerCtx = checker::SavedCheckerContext(ctx->checker, checker::CheckerStatus::IN_CLASS, + auto checkerCtx = checker::SavedCheckerContext(ctx->GetChecker(), checker::CheckerStatus::IN_CLASS, info->calleeClass->Definition()->TsType()->AsETSObjectType()); - auto scopeCtx = checker::ScopeContext(ctx->checker, nearestScope); + auto scopeCtx = checker::ScopeContext(ctx->GetChecker(), nearestScope); newExpr->Check(checker); return newExpr; @@ -934,7 +937,7 @@ static ir::ETSNewClassInstanceExpression *CreateConstructorCall(public_lib::Cont static ir::AstNode *ConvertLambda(public_lib::Context *ctx, ir::ArrowFunctionExpression *lambda) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); lambda->Check(checker); ES2PANDA_ASSERT(lambda->TsType()->IsETSFunctionType()); @@ -994,7 +997,7 @@ static ir::ScriptFunction *GetWrappingLambdaParentFunction(public_lib::Context * auto *callExpr = util::NodeAllocator::ForceSetParent(allocator, funcRef, std::move(callArgs), nullptr, false); ir::Statement *stmt; - if (signature->ReturnType() == ctx->checker->AsETSChecker()->GlobalVoidType()) { + if (signature->ReturnType() == ctx->GetChecker()->AsETSChecker()->GlobalVoidType()) { stmt = util::NodeAllocator::ForceSetParent(allocator, callExpr); } else { stmt = util::NodeAllocator::ForceSetParent(allocator, callExpr); @@ -1008,7 +1011,7 @@ static ir::ScriptFunction *GetWrappingLambdaParentFunction(public_lib::Context * static ir::ArrowFunctionExpression *CreateWrappingLambda(public_lib::Context *ctx, ir::Expression *funcRef) { auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); ES2PANDA_ASSERT(funcRef->TsType()->IsETSArrowType()); auto signature = funcRef->TsType()->AsETSFunctionType()->ArrowSignature(); @@ -1025,10 +1028,10 @@ static ir::ArrowFunctionExpression *CreateWrappingLambda(public_lib::Context *ct auto [enclosingClass, _] = FindEnclosingClassAndFunction(parent); - auto checkerCtx = checker::SavedCheckerContext(ctx->checker, checker::CheckerStatus::IN_CLASS, + auto checkerCtx = checker::SavedCheckerContext(ctx->GetChecker(), checker::CheckerStatus::IN_CLASS, enclosingClass->Definition()->TsType()->AsETSObjectType()); - auto scopeCtx = checker::ScopeContext(ctx->checker, nearestScope); - lambda->Check(ctx->checker->AsETSChecker()); + auto scopeCtx = checker::ScopeContext(ctx->GetChecker(), nearestScope); + lambda->Check(ctx->GetChecker()->AsETSChecker()); return lambda; } @@ -1126,7 +1129,7 @@ static bool IsFunctionOrMethodCall(checker::ETSChecker *checker, ir::CallExpress static ir::AstNode *InsertInvokeCall(public_lib::Context *ctx, ir::CallExpression *call) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *varBinder = checker->VarBinder()->AsETSBinder(); auto *oldCallee = call->Callee(); @@ -1142,6 +1145,7 @@ static ir::AstNode *InsertInvokeCall(public_lib::Context *ctx, ir::CallExpressio oldType->IsETSFunctionType() && oldType->AsETSFunctionType()->ArrowSignature()->HasRestParameter(); util::StringView invokeMethodName = util::UString {checker::FunctionalInterfaceInvokeName(arity, hasRestParam), allocator}.View(); + auto *prop = ifaceType->GetProperty(invokeMethodName, checker::PropertySearchFlags::SEARCH_INSTANCE_METHOD | checker::PropertySearchFlags::SEARCH_IN_INTERFACES); ES2PANDA_ASSERT(prop != nullptr); @@ -1245,7 +1249,7 @@ static ir::AstNode *LowerTypeNodeIfNeeded(public_lib::Context *ctx, ir::AstNode } auto allocator = ctx->allocator; - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); auto newTypeNode = allocator->New(type->AsETSFunctionType()->ArrowToFunctionalInterface(checker), allocator); @@ -1255,7 +1259,7 @@ static ir::AstNode *LowerTypeNodeIfNeeded(public_lib::Context *ctx, ir::AstNode bool LambdaConversionPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); varbinder::RecordTableContext bctx {varBinder, program == ctx->parserProgram ? nullptr : program}; parser::SavedFormattingFileName savedFormattingName(ctx->parser->AsETSParser(), "lambda-conversion"); @@ -1273,7 +1277,7 @@ bool LambdaConversionPhase::PerformForModule(public_lib::Context *ctx, parser::P auto insertInvokeIfNeeded = [ctx](ir::AstNode *node) { if (node->IsCallExpression() && - !IsFunctionOrMethodCall(ctx->checker->AsETSChecker(), node->AsCallExpression()) && + !IsFunctionOrMethodCall(ctx->GetChecker()->AsETSChecker(), node->AsCallExpression()) && !IsRedirectingConstructorCall(node->AsCallExpression())) { return InsertInvokeCall(ctx, node->AsCallExpression()); } diff --git a/ets2panda/compiler/lowering/ets/lateInitialization.cpp b/ets2panda/compiler/lowering/ets/lateInitialization.cpp index a6e6b95098..108d21c318 100644 --- a/ets2panda/compiler/lowering/ets/lateInitialization.cpp +++ b/ets2panda/compiler/lowering/ets/lateInitialization.cpp @@ -27,7 +27,7 @@ using AstNodePtr = ir::AstNode *; ir::ClassProperty *TransformerClassProperty(public_lib::Context *ctx, ir::ClassProperty *property) { - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); auto allocator = ctx->allocator; // Note: This code will be excluded after primitive type refactoring if (property->TsType()->IsETSPrimitiveType()) { @@ -46,9 +46,9 @@ ir::ClassProperty *TransformerClassProperty(public_lib::Context *ctx, ir::ClassP static ir::AstNode *TransformerMemberExpression(ir::MemberExpression *memberExpr, public_lib::Context *ctx) { - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); auto parser = ctx->parser->AsETSParser(); - auto varbinder = ctx->checker->VarBinder()->AsETSBinder(); + auto varbinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); auto allocator = ctx->Allocator(); auto originalType = memberExpr->TsType(); // Note: This code will be excluded after primitive type refactoring diff --git a/ets2panda/compiler/lowering/ets/localClassLowering.cpp b/ets2panda/compiler/lowering/ets/localClassLowering.cpp index a9b4095219..febb95ab47 100644 --- a/ets2panda/compiler/lowering/ets/localClassLowering.cpp +++ b/ets2panda/compiler/lowering/ets/localClassLowering.cpp @@ -29,7 +29,7 @@ static ir::ClassProperty *CreateCapturedField(public_lib::Context *ctx, const va varbinder::ClassScope *scope, size_t &idx) { auto *allocator = ctx->Allocator(); - auto *varBinder = ctx->checker->AsETSChecker()->VarBinder(); + auto *varBinder = ctx->GetChecker()->AsETSChecker()->VarBinder(); // Enter the lambda class instance field scope, every property will be bound to the lambda instance itself auto fieldCtx = varbinder::LexicalScope::Enter(varBinder, scope->InstanceFieldScope()); @@ -103,7 +103,7 @@ ir::ETSParameterExpression *LocalClassConstructionPhase::CreateParam(public_lib: varbinder::FunctionParamScope *scope, util::StringView name, checker::Type *type) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto newParam = checker->AddParam(name, nullptr); newParam->SetTsType(type); newParam->Ident()->SetTsType(type); @@ -126,8 +126,8 @@ void LocalClassConstructionPhase::ModifyConstructorParameters( for (auto *signature : classType->ConstructSignatures()) { LOG(DEBUG, ES2PANDA) << " - Modifying Constructor: " << signature->InternalName(); auto constructor = signature->Function(); - auto ¶meters = constructor->Params(); auto &sigParams = signature->Params(); + auto ¶meters = constructor->ParamsForUpdate(); signature->GetSignatureInfo()->minArgCount += capturedVars.size(); ES2PANDA_ASSERT(signature == constructor->Signature()); @@ -146,7 +146,7 @@ void LocalClassConstructionPhase::ModifyConstructorParameters( sigParams.insert(sigParams.begin(), newParam->Ident()->Variable()->AsLocalVariable()); parameterMap[var] = newParam->Ident()->Variable()->AsLocalVariable(); } - reinterpret_cast(ctx->checker->AsETSChecker()->VarBinder()) + reinterpret_cast(ctx->GetChecker()->AsETSChecker()->VarBinder()) ->BuildFunctionName(constructor); LOG(DEBUG, ES2PANDA) << " Transformed Constructor: " << signature->InternalName(); @@ -170,7 +170,7 @@ void LocalClassConstructionPhase::ModifyConstructorParameters( initStatements.push_back(initStatement); } if (body != nullptr && body->IsBlockStatement()) { - auto &statements = body->AsBlockStatement()->Statements(); + auto &statements = body->AsBlockStatement()->StatementsForUpdates(); statements.insert(statements.begin(), initStatements.begin(), initStatements.end()); } } @@ -235,7 +235,7 @@ void LocalClassConstructionPhase::HandleLocalClass( bool LocalClassConstructionPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); ArenaUnorderedMap> capturedVarsMap { ctx->allocator->Adapter()}; diff --git a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp index deefde6145..1f35c823d6 100644 --- a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp +++ b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp @@ -107,7 +107,7 @@ bool ObjectIndexLowering::PerformForModule(public_lib::Context *ctx, parser::Pro { auto *const parser = ctx->parser->AsETSParser(); ES2PANDA_ASSERT(parser != nullptr); - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); ES2PANDA_ASSERT(checker != nullptr); program->Ast()->TransformChildrenRecursively( diff --git a/ets2panda/compiler/lowering/ets/objectIterator.cpp b/ets2panda/compiler/lowering/ets/objectIterator.cpp index cf43ac31d1..c3136f256e 100644 --- a/ets2panda/compiler/lowering/ets/objectIterator.cpp +++ b/ets2panda/compiler/lowering/ets/objectIterator.cpp @@ -54,7 +54,7 @@ void ObjectIteratorLowering::TransferForOfLoopBody(ir::Statement *const forBody, ir::BlockStatement *const whileBody) const noexcept { ES2PANDA_ASSERT(forBody != nullptr && whileBody != nullptr); - auto &whileStatements = whileBody->Statements(); + auto &whileStatements = whileBody->StatementsForUpdates(); // Currently while loop body consists of 2 statements: 'x = it.value!' and 'it = ci.next()' // We need to insert the body of original for-of-loop between them, change their parent and @@ -128,7 +128,7 @@ ir::Statement *ObjectIteratorLowering::ProcessObjectIterator(public_lib::Context // class has required accessible iterator method and all the types and scopes are properly resolved. auto *const allocator = ctx->Allocator(); - auto *const varbinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *const varbinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); ES2PANDA_ASSERT(varbinder != nullptr); auto statementScope = varbinder::LexicalScope::Enter(varbinder, NearestScope(forOfStatement)); @@ -179,7 +179,7 @@ ir::Statement *ObjectIteratorLowering::ProcessObjectIterator(public_lib::Context ->Body() ->AsBlockStatement()); - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); ES2PANDA_ASSERT(checker != nullptr); CheckLoweredNode(varbinder, checker, loweringResult); diff --git a/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp index e24fe2ea47..d0f415917d 100644 --- a/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp @@ -193,7 +193,7 @@ static void GenerateNewStatements(public_lib::Context *ctx, ir::ObjectExpression for (auto *propExpr : objExpr->Properties()) { // Skip possibly invalid properties: if (!propExpr->IsProperty()) { - ES2PANDA_ASSERT(ctx->checker->AsETSChecker()->IsAnyError()); + ES2PANDA_ASSERT(ctx->GetChecker()->AsETSChecker()->IsAnyError()); continue; } @@ -250,9 +250,9 @@ static ir::AstNode *HandleObjectLiteralLowering(public_lib::Context *ctx, ir::Ob return objExpr; } - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); auto *const parser = ctx->parser->AsETSParser(); - auto *const varbinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *const varbinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); checker->CheckObjectLiteralKeys(objExpr->Properties()); diff --git a/ets2panda/compiler/lowering/ets/opAssignment.cpp b/ets2panda/compiler/lowering/ets/opAssignment.cpp index 62e38b69c3..2f6c22e715 100644 --- a/ets2panda/compiler/lowering/ets/opAssignment.cpp +++ b/ets2panda/compiler/lowering/ets/opAssignment.cpp @@ -105,7 +105,7 @@ void AdjustBoxingUnboxingFlags(ir::Expression *loweringResult, const ir::Express static ir::OpaqueTypeNode *CreateProxyTypeNode(public_lib::Context *ctx, ir::Expression *expr) { auto *lcType = expr->TsType(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); if (checker->IsExtensionETSFunctionType(lcType) && expr->IsMemberExpression() && expr->AsMemberExpression()->HasMemberKind(ir::MemberExpressionKind::EXTENSION_ACCESSOR)) { lcType = expr->AsMemberExpression()->ExtensionAccessorType(); @@ -285,7 +285,7 @@ static ir::Expression *ConstructOpAssignmentResult(public_lib::Context *ctx, ir: ir::AstNode *HandleOpAssignment(public_lib::Context *ctx, ir::AssignmentExpression *assignment) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); if (assignment->TsType() == nullptr) { // hasn't been through checker return assignment; @@ -367,7 +367,7 @@ static ir::Expression *ConstructUpdateResult(public_lib::Context *ctx, ir::Updat auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); auto *argument = upd->Argument(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); ArgumentInfo argInfo {}; argInfo.objType = checker->GlobalVoidType(); @@ -412,7 +412,7 @@ static ir::AstNode *HandleUpdate(public_lib::Context *ctx, ir::UpdateExpression ir::Expression *loweringResult = ConstructUpdateResult(ctx, upd); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto expressionCtx = varbinder::LexicalScope::Enter(checker->VarBinder(), scope); checker::SavedCheckerContext scc {checker, checker::CheckerStatus::IGNORE_VISIBILITY, ContainingClass(upd)}; diff --git a/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp b/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp index 701623fc52..94ce179427 100644 --- a/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp +++ b/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp @@ -19,6 +19,7 @@ #include "checker/ETSchecker.h" namespace ark::es2panda::compiler { + static void TransformArguments(public_lib::Context *ctx, ir::Expression *callLike, checker::Signature *signature, ArenaVector &arguments); @@ -52,7 +53,7 @@ static void TransformArguments(public_lib::Context *ctx, ir::Expression *callLik ES2PANDA_ASSERT((callLike->IsCallExpression() && callLike->AsCallExpression()->IsTrailingCall()) || arguments.size() >= signature->MinArgCount()); - auto const checker = ctx->checker->AsETSChecker(); + auto const checker = ctx->GetChecker()->AsETSChecker(); auto const allocator = ctx->allocator; size_t missing = signature->ArgCount() - arguments.size(); diff --git a/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp b/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp index fae3b44254..550acfe703 100644 --- a/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp +++ b/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp @@ -32,7 +32,7 @@ static void MergeExternalFilesIntoCompiledProgram(parser::Program *const program // Because same package files must be in one folder, relative path references in an external // source's import declaration certainly will be the same (and can be resolved) from the global program too - program->Ast()->Statements().emplace_back(stmt); + program->Ast()->AddStatement(stmt); } } } diff --git a/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp b/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp index 19f0157be7..a0814250f8 100644 --- a/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp +++ b/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp @@ -24,19 +24,23 @@ static void GeneratePartialDeclForExported(const public_lib::Context *const ctx, { // NOTE (mmartin): handle interfaces if (node->IsClassDeclaration()) { - ctx->checker->AsETSChecker()->CreatePartialType(node->AsClassDeclaration()->Definition()->TsType()); + ctx->GetChecker()->AsETSChecker()->CreatePartialType(node->AsClassDeclaration()->Definition()->TsType()); + } + if (node->IsTSInterfaceDeclaration()) { + ctx->GetChecker()->AsETSChecker()->CreatePartialType(node->AsTSInterfaceDeclaration()->TsType()); } } bool PartialExportClassGen::PerformForModule(public_lib::Context *const ctx, parser::Program *const program) { program->Ast()->TransformChildrenRecursively( - [ctx, &program](ir::AstNode *const ast) { - if ((ast->IsClassDeclaration() || ast->IsTSInterfaceDeclaration()) && ast->IsExported()) { - auto *const savedProg = ctx->checker->VarBinder()->AsETSBinder()->Program(); - ctx->checker->VarBinder()->AsETSBinder()->SetProgram(program); + [ctx, program](ir::AstNode *const ast) { + if ((ast->IsClassDeclaration() || ast->IsTSInterfaceDeclaration()) && + (ast->IsExported() || ast->IsDefaultExported())) { + auto *const savedProg = ctx->GetChecker()->VarBinder()->AsETSBinder()->Program(); + ctx->GetChecker()->VarBinder()->AsETSBinder()->SetProgram(program); GeneratePartialDeclForExported(ctx, ast); - ctx->checker->VarBinder()->AsETSBinder()->SetProgram(savedProg); + ctx->GetChecker()->VarBinder()->AsETSBinder()->SetProgram(savedProg); } return ast; diff --git a/ets2panda/compiler/lowering/ets/partialExportClassGen.h b/ets2panda/compiler/lowering/ets/partialExportClassGen.h index dbe558e0e6..1c8114a448 100644 --- a/ets2panda/compiler/lowering/ets/partialExportClassGen.h +++ b/ets2panda/compiler/lowering/ets/partialExportClassGen.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,7 +20,7 @@ namespace ark::es2panda::compiler { -class PartialExportClassGen : public PhaseForBodies { +class PartialExportClassGen : public PhaseForDeclarations { public: std::string_view Name() const override { diff --git a/ets2panda/compiler/lowering/ets/recordLowering.cpp b/ets2panda/compiler/lowering/ets/recordLowering.cpp index 8897cd7ddb..870a9c2aed 100644 --- a/ets2panda/compiler/lowering/ets/recordLowering.cpp +++ b/ets2panda/compiler/lowering/ets/recordLowering.cpp @@ -92,18 +92,18 @@ void RecordLowering::CheckDuplicateKey(KeySetType &keySet, ir::ObjectExpression (number.IsDouble() && keySet.insert(number.GetDouble()).second)) { continue; } - ctx->checker->AsETSChecker()->LogError(diagnostic::OBJ_LIT_PROP_NAME_COLLISION, {}, expr->Start()); + ctx->GetChecker()->AsETSChecker()->LogError(diagnostic::OBJ_LIT_PROP_NAME_COLLISION, {}, expr->Start()); break; } case ir::AstNodeType::STRING_LITERAL: { if (keySet.insert(prop->Key()->AsStringLiteral()->Str()).second) { continue; } - ctx->checker->AsETSChecker()->LogError(diagnostic::OBJ_LIT_PROP_NAME_COLLISION, {}, expr->Start()); + ctx->GetChecker()->AsETSChecker()->LogError(diagnostic::OBJ_LIT_PROP_NAME_COLLISION, {}, expr->Start()); break; } case ir::AstNodeType::IDENTIFIER: { - ctx->checker->AsETSChecker()->LogError(diagnostic::OBJ_LIT_UNKNOWN_PROP, {}, expr->Start()); + ctx->GetChecker()->AsETSChecker()->LogError(diagnostic::OBJ_LIT_UNKNOWN_PROP, {}, expr->Start()); break; } default: { @@ -122,7 +122,7 @@ void RecordLowering::CheckLiteralsCompleteness(KeySetType &keySet, ir::ObjectExp } for (auto &ct : keyType->AsETSUnionType()->ConstituentTypes()) { if (ct->IsConstantType() && keySet.find(TypeToKey(ct)) == keySet.end()) { - ctx->checker->AsETSChecker()->LogError(diagnostic::OBJ_LIT_NOT_COVERING_UNION, {}, expr->Start()); + ctx->GetChecker()->AsETSChecker()->LogError(diagnostic::OBJ_LIT_NOT_COVERING_UNION, {}, expr->Start()); } } } @@ -154,7 +154,7 @@ ir::Statement *RecordLowering::CreateStatement(const std::string &src, ir::Expre ir::Expression *RecordLowering::UpdateObjectExpression(ir::ObjectExpression *expr, public_lib::Context *ctx) { - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); if (!expr->PreferredType()->IsETSObjectType()) { // Unexpected preferred type @@ -188,7 +188,7 @@ ir::Expression *RecordLowering::UpdateObjectExpression(ir::ObjectExpression *exp block->SetParent(expr->Parent()); // Run checks - InitScopesPhaseETS::RunExternalNode(block, ctx->checker->VarBinder()); + InitScopesPhaseETS::RunExternalNode(block, ctx->GetChecker()->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(block, NearestScope(block)); block->Check(checker); diff --git a/ets2panda/compiler/lowering/ets/resizableArrayLowering.cpp b/ets2panda/compiler/lowering/ets/resizableArrayLowering.cpp index 12d58293e3..804519f911 100644 --- a/ets2panda/compiler/lowering/ets/resizableArrayLowering.cpp +++ b/ets2panda/compiler/lowering/ets/resizableArrayLowering.cpp @@ -27,7 +27,7 @@ static ir::AstNode *ConvertToResizableArrayType(ir::TSArrayType *node, public_li auto *parser = ctx->parser->AsETSParser(); ir::TypeNode *typeAnnotation = parser->CreateFormattedTypeAnnotation("Array<" + node->ElementType()->DumpEtsSrc() + ">"); - typeAnnotation->SetAnnotations(std::move(node->Annotations())); + typeAnnotation->SetAnnotations(node->Annotations()); typeAnnotation->SetParent(node->Parent()); typeAnnotation->SetRange(node->Range()); RefineSourceRanges(node); diff --git a/ets2panda/compiler/lowering/ets/restArgsLowering.cpp b/ets2panda/compiler/lowering/ets/restArgsLowering.cpp index 224e980335..a34c623cf9 100644 --- a/ets2panda/compiler/lowering/ets/restArgsLowering.cpp +++ b/ets2panda/compiler/lowering/ets/restArgsLowering.cpp @@ -30,7 +30,7 @@ static ir::BlockExpression *CreateRestArgsBlockExpression(public_lib::Context *c { auto *allocator = context->allocator; auto *parser = context->parser->AsETSParser(); - auto *checker = context->checker->AsETSChecker(); + auto *checker = context->GetChecker()->AsETSChecker(); ArenaVector blockStatements(allocator->Adapter()); const auto arraySymbol = Gensym(allocator); @@ -89,7 +89,7 @@ static ir::Expression *CreateRestArgsArray(public_lib::Context *context, ArenaVe { auto *allocator = context->allocator; auto *parser = context->parser->AsETSParser(); - auto *checker = context->checker->AsETSChecker(); + auto *checker = context->GetChecker()->AsETSChecker(); // Handle single spread element case const size_t extraArgs = arguments.size() - signature->Params().size(); @@ -121,7 +121,7 @@ static ir::CallExpression *RebuildCallExpression(public_lib::Context *context, i checker::Signature *signature, ir::Expression *restArgsArray) { auto *allocator = context->allocator; - auto *varbinder = context->checker->VarBinder()->AsETSBinder(); + auto *varbinder = context->GetChecker()->VarBinder()->AsETSBinder(); ArenaVector newArgs(allocator->Adapter()); for (size_t i = 0; i < signature->Params().size(); ++i) { @@ -143,7 +143,7 @@ static ir::CallExpression *RebuildCallExpression(public_lib::Context *context, i auto *scope = NearestScope(newCall->Parent()); auto bscope = varbinder::LexicalScope::Enter(varbinder, scope); - CheckLoweredNode(context->checker->VarBinder()->AsETSBinder(), context->checker->AsETSChecker(), newCall); + CheckLoweredNode(context->GetChecker()->VarBinder()->AsETSBinder(), context->GetChecker()->AsETSChecker(), newCall); newCall->RemoveAstNodeFlags(ir::AstNodeFlags::RESIZABLE_REST); return newCall; } @@ -169,8 +169,9 @@ static ir::ETSNewClassInstanceExpression *RebuildNewClassInstanceExpression( newCall->AddModifier(originalCall->Modifiers()); newCall->AddBoxingUnboxingFlags(originalCall->GetBoxingUnboxingFlags()); auto *scope = NearestScope(newCall->Parent()); - auto bscope = varbinder::LexicalScope::Enter(context->checker->VarBinder()->AsETSBinder(), scope); - CheckLoweredNode(context->checker->VarBinder()->AsETSBinder(), context->checker->AsETSChecker(), newCall); + auto bscope = + varbinder::LexicalScope::Enter(context->GetChecker()->VarBinder()->AsETSBinder(), scope); + CheckLoweredNode(context->GetChecker()->VarBinder()->AsETSBinder(), context->GetChecker()->AsETSChecker(), newCall); return newCall; } diff --git a/ets2panda/compiler/lowering/ets/restTupleLowering.cpp b/ets2panda/compiler/lowering/ets/restTupleLowering.cpp index 7e9724a1bf..36554fe955 100644 --- a/ets2panda/compiler/lowering/ets/restTupleLowering.cpp +++ b/ets2panda/compiler/lowering/ets/restTupleLowering.cpp @@ -368,7 +368,7 @@ void CreateNewMethod(public_lib::Context *ctx, ir::AstNode *node) // Build new methodDefinition auto *const methodDef = CreateNewMethodDefinition(ctx, definition->AsMethodDefinition(), function); - node->AsClassDefinition()->Body().push_back(methodDef); + node->AsClassDefinition()->EmplaceBody(methodDef); } } } diff --git a/ets2panda/compiler/lowering/ets/setJumpTarget.cpp b/ets2panda/compiler/lowering/ets/setJumpTarget.cpp index 95b29ec11e..46b9c961e7 100644 --- a/ets2panda/compiler/lowering/ets/setJumpTarget.cpp +++ b/ets2panda/compiler/lowering/ets/setJumpTarget.cpp @@ -51,7 +51,7 @@ void SetJumpTargetPhase::FindJumpTarget(const public_lib::Context *ctx, ir::AstN var->SetScope(varbinder->GetScope()); label->SetVariable(var); decl->BindNode(label); - label->SetTsType(var->SetTsType(ctx->checker->GetGlobalTypesHolder()->GlobalTypeError())); + label->SetTsType(var->SetTsType(ctx->GetChecker()->GetGlobalTypesHolder()->GlobalTypeError())); } else if (var->Declaration()->IsLabelDecl()) { SetTarget(node, var->Declaration()->Node()); return; @@ -95,21 +95,13 @@ void SetJumpTargetPhase::FindJumpTarget(const public_lib::Context *ctx, ir::AstN SetTarget(node, nullptr); } -bool SetJumpTargetPhase::Perform(public_lib::Context *ctx, parser::Program *program) +bool SetJumpTargetPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - for (auto &[_, ext_programs] : program->ExternalSources()) { - (void)_; - for (auto *extProg : ext_programs) { - Perform(ctx, extProg); - } - } - program->Ast()->IterateRecursivelyPostorder([&](ir::AstNode *const node) -> void { if (node->IsBreakStatement() || node->IsContinueStatement()) { FindJumpTarget(ctx, node); } }); - return true; } diff --git a/ets2panda/compiler/lowering/ets/setJumpTarget.h b/ets2panda/compiler/lowering/ets/setJumpTarget.h index 79eb75efe4..ddef1ff51b 100644 --- a/ets2panda/compiler/lowering/ets/setJumpTarget.h +++ b/ets2panda/compiler/lowering/ets/setJumpTarget.h @@ -20,7 +20,7 @@ namespace ark::es2panda::compiler { -class SetJumpTargetPhase : public Phase { +class SetJumpTargetPhase : public PhaseForDeclarations { public: std::string_view Name() const override { @@ -28,7 +28,8 @@ public: } void FindJumpTarget(const public_lib::Context *ctx, ir::AstNode *const node); - bool Perform(public_lib::Context *ctx, parser::Program *program) override; + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; private: void LogError(const public_lib::Context *ctx, const diagnostic::DiagnosticKind &diagnostic, diff --git a/ets2panda/compiler/lowering/ets/spreadLowering.cpp b/ets2panda/compiler/lowering/ets/spreadLowering.cpp index 1c2f4241cf..8c0c488a32 100644 --- a/ets2panda/compiler/lowering/ets/spreadLowering.cpp +++ b/ets2panda/compiler/lowering/ets/spreadLowering.cpp @@ -82,7 +82,7 @@ static ir::Identifier *CreateNewArrayDeclareStatement(public_lib::Context *ctx, ArenaVector &statements, ir::Identifier *newArrayLengthId) { - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); auto *const allocator = ctx->allocator; auto *const parser = ctx->parser->AsETSParser(); ir::Identifier *newArrayId = Gensym(allocator); @@ -286,7 +286,8 @@ static void CreateNewArrayElementsAssignStatement(public_lib::Context *ctx, ir:: newTupleAssignmentStatements.cend()); } else { ir::Identifier *spreadArrIterator = Gensym(allocator); - checker::Type *arrayElementType = ctx->checker->AsETSChecker()->GetElementTypeOfArray(array->TsType()); + checker::Type *arrayElementType = + ctx->GetChecker()->AsETSChecker()->GetElementTypeOfArray(array->TsType()); statements.emplace_back(CreateElementsAssignStatementBySpreadArr( ctx, spArrIds[spArrIdx++], newArrayAndIndex, spreadArrIterator, arrayElementType)); } @@ -343,7 +344,7 @@ static ir::BlockExpression *CreateLoweredExpressionForArray(public_lib::Context */ static ir::BlockExpression *CreateLoweredExpressionForTuple(public_lib::Context *ctx, ir::ArrayExpression *array) { - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); auto *const parser = ctx->parser->AsETSParser(); auto *const allocator = ctx->allocator; @@ -356,7 +357,7 @@ static ir::BlockExpression *CreateLoweredExpressionForTuple(public_lib::Context bool SpreadConstructionPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); varbinder::ETSBinder *const varbinder = checker->VarBinder()->AsETSBinder(); program->Ast()->TransformChildrenRecursively( diff --git a/ets2panda/compiler/lowering/ets/stringComparison.cpp b/ets2panda/compiler/lowering/ets/stringComparison.cpp index e7f0cb4f16..d10fdb7b50 100644 --- a/ets2panda/compiler/lowering/ets/stringComparison.cpp +++ b/ets2panda/compiler/lowering/ets/stringComparison.cpp @@ -78,7 +78,7 @@ void StringComparisonLowering::ProcessBinaryExpression(ir::BinaryExpression *exp // reset types is any, will re-run checker to set them once again properly expr->SetTsType(nullptr); - checker::ETSChecker *checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *checker = ctx->GetChecker()->AsETSChecker(); ArenaVector callArgs(checker->Allocator()->Adapter()); ir::Expression *accessor = nullptr; auto *zeroExpr = checker->AllocNode(util::StringView("0")); @@ -95,7 +95,7 @@ void StringComparisonLowering::ProcessBinaryExpression(ir::BinaryExpression *exp expr->SetRight(zeroExpr); auto *parent = expr->Parent(); - InitScopesPhaseETS::RunExternalNode(expr, ctx->checker->VarBinder()); + InitScopesPhaseETS::RunExternalNode(expr, ctx->GetChecker()->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(parent, NearestScope(parent)); if (parent->IsBinaryExpression() || parent->IsConditionalExpression()) { @@ -108,7 +108,7 @@ void StringComparisonLowering::ProcessBinaryExpression(ir::BinaryExpression *exp bool StringComparisonLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *checker = ctx->GetChecker()->AsETSChecker(); [[maybe_unused]] ArenaVector foundNodes(checker->Allocator()->Adapter()); // CC-OFFNXT(G.FMT.14-CPP) project code style program->Ast()->IterateRecursively([&foundNodes, this](ir::AstNode *ast) -> ir::AstNode * { diff --git a/ets2panda/compiler/lowering/ets/stringConstantsLowering.cpp b/ets2panda/compiler/lowering/ets/stringConstantsLowering.cpp index e2bae0b0e6..8f255cb457 100644 --- a/ets2panda/compiler/lowering/ets/stringConstantsLowering.cpp +++ b/ets2panda/compiler/lowering/ets/stringConstantsLowering.cpp @@ -35,19 +35,8 @@ static ir::AstNode *FoldConcat(public_lib::Context *ctx, ir::BinaryExpression *c return resNode; } -bool StringConstantsLowering::Perform(public_lib::Context *ctx, parser::Program *program) +bool StringConstantsLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - for (auto &[_, ext_programs] : program->ExternalSources()) { - (void)_; - for (auto *extProg : ext_programs) { - if (program->GetFlag(parser::ProgramFlags::AST_STRING_CONSTANT_LOWERED)) { - continue; - } - Perform(ctx, extProg); - program->SetFlag(parser::ProgramFlags::AST_STRING_CONSTANT_LOWERED); - } - } - program->Ast()->TransformChildrenRecursivelyPostorder( [ctx](checker::AstNodePtr const node) -> checker::AstNodePtr { if (node->IsBinaryExpression()) { @@ -60,7 +49,6 @@ bool StringConstantsLowering::Perform(public_lib::Context *ctx, parser::Program return node; }, Name()); - return true; } diff --git a/ets2panda/compiler/lowering/ets/stringConstantsLowering.h b/ets2panda/compiler/lowering/ets/stringConstantsLowering.h index d69fcb5339..4b0ce4e6ea 100644 --- a/ets2panda/compiler/lowering/ets/stringConstantsLowering.h +++ b/ets2panda/compiler/lowering/ets/stringConstantsLowering.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,10 +20,11 @@ namespace ark::es2panda::compiler { -class StringConstantsLowering : public Phase { +class StringConstantsLowering : public PhaseForDeclarations { public: std::string_view Name() const override; - bool Perform(public_lib::Context *ctx, parser::Program *program) override; + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/stringConstructorLowering.cpp b/ets2panda/compiler/lowering/ets/stringConstructorLowering.cpp index 1e4060b5ea..e3c4f2e73f 100644 --- a/ets2panda/compiler/lowering/ets/stringConstructorLowering.cpp +++ b/ets2panda/compiler/lowering/ets/stringConstructorLowering.cpp @@ -48,7 +48,7 @@ static constexpr char const FORMAT_TO_STRING_EXPRESSION[] = "((@@E1 as Object).t ir::Expression *ReplaceStringConstructor(public_lib::Context *const ctx, ir::ETSNewClassInstanceExpression *newClassInstExpr) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *parser = ctx->parser->AsETSParser(); // Skip missing signatures diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index a914f8ad66..c30b85b05f 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -42,7 +42,7 @@ void GlobalClassHandler::AddStaticBlockToClass(ir::AstNode *node) if (node->IsClassDefinition() && !node->AsClassDefinition()->IsDeclare()) { auto classDef = node->AsClassDefinition(); if (auto staticBlock = CreateStaticBlock(classDef); staticBlock != nullptr) { - classDef->Body().emplace_back(staticBlock); // NOTE(vpukhov): inserted to end for some reason + classDef->EmplaceBody(staticBlock); // NOTE(vpukhov): inserted to end for some reason staticBlock->SetParent(classDef); } } @@ -103,7 +103,7 @@ ir::ClassDeclaration *GlobalClassHandler::CreateTransformedClass(ir::ETSModule * static void InsertInGlobal(ir::ClassDefinition *globalClass, ir::AstNode *node) { - globalClass->Body().insert(globalClass->Body().begin(), node); + globalClass->BodyForUpdate().insert(globalClass->Body().begin(), node); node->SetParent(globalClass); } @@ -165,11 +165,9 @@ void GlobalClassHandler::MergeNamespace(ArenaVector &namespaces parser->LogError(diagnostic::NAMESPACE_ANNOTATION_CONFLICT, {ns->Ident()->Name().Mutf8()}, ns->Start()); } else if (!ns->Annotations().empty()) { ES2PANDA_ASSERT(res->second->Annotations().empty()); - res->second->SetAnnotations(std::move(ns->Annotations())); - } - for (auto *statement : ns->Statements()) { - res->second->Statements().emplace_back(statement); + res->second->SetAnnotations(std::move(ns->AnnotationsForUpdate())); } + res->second->AddStatements(ns->Statements()); namespaces.erase(it); } else { nsMap.insert({ns->Ident()->Name(), ns}); @@ -178,10 +176,10 @@ void GlobalClassHandler::MergeNamespace(ArenaVector &namespaces } } -ArenaVector GlobalClassHandler::TransformNamespaces(ArenaVector &namespaces, - parser::Program *program) +ArenaVector GlobalClassHandler::TransformNamespaces(ArenaVector &namespaces, + parser::Program *program) { - ArenaVector classDecls {allocator_->Adapter()}; + ArenaVector classDecls {allocator_->Adapter()}; MergeNamespace(namespaces, program); for (auto ns : namespaces) { classDecls.emplace_back(TransformNamespace(ns, program)); @@ -197,7 +195,7 @@ ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns, ArenaVector immediateInitializers(allocator_->Adapter()); ArenaVector initializerBlock(allocator_->Adapter()); ArenaVector namespaces(allocator_->Adapter()); - auto &body = ns->Statements(); + auto &body = ns->StatementsForUpdates(); for (auto *statement : body) { statement->Iterate([this](ir::AstNode *node) { AddStaticBlockToClass(node); }); } @@ -224,14 +222,14 @@ ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns, body.erase(end, body.end()); auto globalClasses = TransformNamespaces(namespaces, program); for (auto *cls : globalClasses) { - globalClass->Body().emplace_back(cls); + globalClass->EmplaceBody(cls); cls->SetParent(globalClass); - CollectNamespaceExportedClasses(cls->Definition()); + CollectNamespaceExportedClasses(cls->AsClassDeclaration()->Definition()); } // Add rest statement, such as type declaration for (auto *statement : body) { - globalClass->Body().emplace_back(statement); + globalClass->EmplaceBody(statement); statement->SetParent(globalClass); } body.clear(); @@ -241,10 +239,10 @@ ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns, void GlobalClassHandler::CollectProgramGlobalClasses(parser::Program *program, ArenaVector namespaces) { auto classDecls = TransformNamespaces(namespaces, program); + program->Ast()->AddStatements(classDecls); for (auto cls : classDecls) { - program->Ast()->Statements().push_back(cls); cls->SetParent(program->Ast()); - CollectNamespaceExportedClasses(cls->Definition()); + CollectNamespaceExportedClasses(cls->AsClassDeclaration()->Definition()); } } @@ -286,9 +284,9 @@ void GlobalClassHandler::SetupGlobalClass(const ArenaVector & ArenaVector initializerBlock(allocator_->Adapter()); ArenaVector namespaces(allocator_->Adapter()); - for (auto program : programs) { + for (auto const program : programs) { program->Ast()->IterateRecursively([this](ir::AstNode *node) { AddStaticBlockToClass(node); }); - auto &body = program->Ast()->Statements(); + auto &body = program->Ast()->StatementsForUpdates(); auto stmts = CollectProgramGlobalStatements(body, globalClass, program->Ast()); auto end = std::remove_if(body.begin(), body.end(), [&namespaces](ir::AstNode *node) { if (node->IsETSModule() && node->AsETSModule()->IsNamespace()) { @@ -306,7 +304,7 @@ void GlobalClassHandler::SetupGlobalClass(const ArenaVector & program->SetGlobalClass(globalClass); } - globalProgram->Ast()->Statements().emplace_back(globalDecl); + globalProgram->Ast()->AddStatement(globalDecl); globalDecl->SetParent(globalProgram->Ast()); globalClass->SetGlobalInitialized(); CollectProgramGlobalClasses(globalProgram, namespaces); @@ -367,7 +365,7 @@ void GlobalClassHandler::AddInitializerBlockToStaticBlock(ir::ClassDefinition *g auto *blockBody = staticBlock->Function()->Body()->AsBlockStatement(); initializerStmts->SetParent(blockBody); - blockBody->Statements().emplace_back(initializerStmts); + blockBody->AddStatement(initializerStmts); } void GlobalClassHandler::AddInitCallToStaticBlock(ir::ClassDefinition *globalClass, ir::MethodDefinition *initMethod) @@ -388,7 +386,7 @@ void GlobalClassHandler::AddInitCallToStaticBlock(ir::ClassDefinition *globalCla auto *blockBody = staticBlock->Function()->Body()->AsBlockStatement(); auto exprStmt = NodeAllocator::Alloc(allocator_, callExpr); exprStmt->SetParent(blockBody); - blockBody->Statements().emplace_back(exprStmt); + blockBody->AddStatement(exprStmt); } ir::Identifier *GlobalClassHandler::RefIdent(const util::StringView &name) diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h index ae589327d1..18d7fbbbc4 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h @@ -62,8 +62,8 @@ private: ir::ClassDefinition *globalClass, bool isDeclare); void SetupInitializerBlock(parser::Program *program, ArenaVector> &&initializerBlock, ir::ClassDefinition *globalClass); - ArenaVector TransformNamespaces(ArenaVector &namespaces, - parser::Program *program); + ArenaVector TransformNamespaces(ArenaVector &namespaces, + parser::Program *program); ir::ClassDeclaration *CreateGlobalClass(const parser::Program *globalProgram); ir::ClassStaticBlock *CreateStaticBlock(ir::ClassDefinition *classDef); diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp index 8e3afe694c..dc8869fffa 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp @@ -58,7 +58,7 @@ void GlobalDeclTransformer::VisitFunctionDeclaration(ir::FunctionDeclaration *fu allocator_, methodKind, funcDecl->Function()->Id()->Clone(allocator_, nullptr), funcExpr, funcDecl->Function()->Modifiers(), allocator_, false); method->SetRange(funcDecl->Range()); - method->Function()->SetAnnotations(std::move(funcDecl->Annotations())); + method->Function()->SetAnnotations(funcDecl->Annotations()); if (funcDecl->Function()->IsExported() && funcDecl->Function()->HasExportAlias()) { method->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS); diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp index aa76dbdc45..fd25d833a5 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp @@ -57,8 +57,10 @@ GlobalClassHandler::ModuleDependencies ImportExportDecls::HandleGlobalStmts(Aren if (!programs.empty()) { std::sort(programs.begin(), programs.end(), ProgramFileNameLessThan); } - for (const auto &program : programs) { - PreMergeNamespaces(program); + for (auto const &program : programs) { + if (!program->IsASTLowered()) { + PreMergeNamespaces(program); + } SavedImportExportDeclsContext savedContext(this, program); ProcessProgramStatements(program, program->Ast()->Statements(), moduleDependencies); VerifyCollectedExportName(program); @@ -318,7 +320,7 @@ void ImportExportDecls::PreMergeNamespaces(parser::Program *program) } ArenaVector namespaces(program->Allocator()->Adapter()); - auto &body = ast->AsETSModule()->Statements(); + auto &body = ast->AsETSModule()->StatementsForUpdates(); auto originalSize = body.size(); auto end = std::remove_if(body.begin(), body.end(), [&namespaces](ir::AstNode *node) { if (node->IsETSModule() && node->AsETSModule()->IsNamespace()) { diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp index 28c205ee50..3db02c7218 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp @@ -58,8 +58,10 @@ bool TopLevelStatements::Perform(public_lib::Context *ctx, parser::Program *prog GlobalClassHandler globalClass(ctx->parser->AsETSParser(), ctx->Allocator()); for (auto &[package, extPrograms] : program->ExternalSources()) { - auto moduleDependencies = imports.HandleGlobalStmts(extPrograms); - globalClass.SetupGlobalClass(extPrograms, &moduleDependencies); + if (!extPrograms.front()->IsASTLowered()) { + auto moduleDependencies = imports.HandleGlobalStmts(extPrograms); + globalClass.SetupGlobalClass(extPrograms, &moduleDependencies); + } } ArenaVector mainModule(ctx->Allocator()->Adapter()); diff --git a/ets2panda/compiler/lowering/ets/typeFromLowering.cpp b/ets2panda/compiler/lowering/ets/typeFromLowering.cpp index 2ee7cc83d8..31f98cba35 100644 --- a/ets2panda/compiler/lowering/ets/typeFromLowering.cpp +++ b/ets2panda/compiler/lowering/ets/typeFromLowering.cpp @@ -116,7 +116,7 @@ std::string HandleTypeParameter(ir::Expression *param, checker::ETSChecker *chec ir::Expression *ReplaceTypeFrom(public_lib::Context *ctx, ir::CallExpression *ast) { auto parser = ctx->parser->AsETSParser(); - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); auto *typeParams = ast->AsCallExpression()->TypeParams(); ES2PANDA_ASSERT(typeParams != nullptr && typeParams->Params().size() == 1); diff --git a/ets2panda/compiler/lowering/ets/unionLowering.cpp b/ets2panda/compiler/lowering/ets/unionLowering.cpp index 2df65448a0..ecbedb0619 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unionLowering.cpp @@ -32,7 +32,7 @@ static void ReplaceAll(std::string &str, std::string_view substr, std::string_vi } } -static std::string GetAccessClassName(const checker::ETSUnionType *unionType) +std::string GetAccessClassName(const checker::ETSUnionType *unionType) { std::stringstream ss; ss << PREFIX; @@ -47,7 +47,7 @@ static std::string GetAccessClassName(const checker::ETSUnionType *unionType) static ir::ClassDefinition *GetUnionAccessClass(public_lib::Context *ctx, varbinder::VarBinder *varbinder, std::string const &name) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->Allocator(); // Create the name for the synthetic class node if (auto foundVar = checker->Scope()->FindLocal(util::StringView(name), varbinder::ResolveBindingOptions::BINDINGS); @@ -72,7 +72,7 @@ static ir::ClassDefinition *GetUnionAccessClass(public_lib::Context *ctx, varbin auto globalBlock = varbinder->Program()->Ast(); classDecl->SetParent(globalBlock); - globalBlock->Statements().push_back(classDecl); + globalBlock->AddStatement(classDecl); classDecl->Check(checker); return classDef; } @@ -82,7 +82,7 @@ static std::tuple CreateNamedA checker::Signature *signature) { auto *allocator = ctx->Allocator(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto unionType = checker->GetApparentType(checker->GetNonNullishType(expr->Object()->TsType()))->AsETSUnionType(); auto *const accessClass = GetUnionAccessClass(ctx, varbinder, GetAccessClassName(unionType)); @@ -131,7 +131,7 @@ static varbinder::LocalVariable *CreateNamedAccessProperty(public_lib::Context * ir::MemberExpression *expr) { auto *const allocator = ctx->Allocator(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto unionType = checker->GetApparentType(checker->GetNonNullishType(expr->Object()->TsType()))->AsETSUnionType(); auto *const accessClass = GetUnionAccessClass(ctx, varbinder, GetAccessClassName(unionType)); @@ -166,7 +166,7 @@ static varbinder::LocalVariable *CreateNamedAccess(public_lib::Context *ctx, var { auto type = expr->TsType(); auto name = expr->Property()->AsIdentifier()->Name(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto unionType = checker->GetApparentType(checker->GetNonNullishType(expr->Object()->TsType()))->AsETSUnionType(); auto *const accessClass = GetUnionAccessClass(ctx, varbinder, GetAccessClassName(unionType)); @@ -208,7 +208,7 @@ static ir::TSAsExpression *GenAsExpression(public_lib::Context *ctx, checker::Ty auto *const typeNode = ctx->AllocNode(opaqueType, ctx->Allocator()); auto *const asExpression = ctx->AllocNode(node, typeNode, false); asExpression->SetParent(parent); - asExpression->Check(ctx->checker->AsETSChecker()); + asExpression->Check(ctx->GetChecker()->AsETSChecker()); return asExpression; } @@ -227,7 +227,7 @@ static ir::TSAsExpression *UnionCastToPrimitive(public_lib::Context *ctx, checke static ir::TSAsExpression *HandleUnionCastToPrimitive(public_lib::Context *ctx, ir::TSAsExpression *expr) { - checker::ETSChecker *checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *checker = ctx->GetChecker()->AsETSChecker(); auto *const unionType = expr->Expr()->TsType()->AsETSUnionType(); auto *sourceType = unionType->FindExactOrBoxedType(checker, expr->TsType()); if (sourceType == nullptr) { @@ -262,7 +262,7 @@ static ir::TSAsExpression *HandleUnionCastToPrimitive(public_lib::Context *ctx, bool UnionLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *checker = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( [ctx, checker](checker::AstNodePtr ast) -> checker::AstNodePtr { @@ -290,7 +290,7 @@ bool UnionLowering::PerformForModule(public_lib::Context *ctx, parser::Program * bool UnionLowering::PostconditionForModule(public_lib::Context *ctx, const parser::Program *program) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); bool current = !program->Ast()->IsAnyChild([checker](ir::AstNode *ast) { if (!ast->IsMemberExpression() || ast->AsMemberExpression()->Object()->TsType() == nullptr) { return false; diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 6cd559f27d..a871d1f962 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -74,67 +74,18 @@ namespace ark::es2panda::compiler { -static CheckerPhase g_checkerPhase; -static SetJumpTargetPhase g_setJumpTargetPhase; -static CFGBuilderPhase g_cfgBuilderPhase; -static ResolveIdentifiers g_resolveIdentifiers {}; -static AmbientLowering g_ambientLowering; -static ArrayLiteralLowering g_arrayLiteralLowering {}; -static BigIntLowering g_bigintLowering; -static StringConstructorLowering g_stringConstructorLowering; -static ConstantExpressionLowering g_constantExpressionLowering; -static InterfacePropertyDeclarationsPhase g_interfacePropDeclPhase; // NOLINT(fuchsia-statically-constructed-objects) -static EnumLoweringPhase g_enumLoweringPhase; -static EnumPostCheckLoweringPhase g_enumPostCheckLoweringPhase; -static RestTupleConstructionPhase g_restTupleConstructionPhase; -static SpreadConstructionPhase g_spreadConstructionPhase; -static ExtensionAccessorPhase g_extensionAccessorPhase; -static ExpressionLambdaConstructionPhase g_expressionLambdaConstructionPhase; -static OpAssignmentLowering g_opAssignmentLowering; -static BoxingForLocals g_boxingForLocals; -static CapturedVariables g_capturedVariables {}; -static LambdaConversionPhase g_lambdaConversionPhase; -static ObjectIndexLowering g_objectIndexLowering; -static ObjectIteratorLowering g_objectIteratorLowering; -static ObjectLiteralLowering g_objectLiteralLowering; -static InterfaceObjectLiteralLowering g_interfaceObjectLiteralLowering; -static UnionLowering g_unionLowering; -static OptionalLowering g_optionalLowering; -static ExpandBracketsPhase g_expandBracketsPhase; -static ExportAnonymousConstPhase g_exportAnonymousConstPhase; -static PromiseVoidInferencePhase g_promiseVoidInferencePhase; -static RecordLowering g_recordLowering; -static DeclareOverloadLowering g_declareOverloadLowering; -static DefaultParametersLowering g_defaultParametersLowering; -static DefaultParametersInConstructorLowering g_defaultParametersInConstructorLowering; -static OptionalArgumentsLowering g_optionalArgumentsLowering; -static TopLevelStatements g_topLevelStatements; -static LocalClassConstructionPhase g_localClassLowering; -static StringComparisonLowering g_stringComparisonLowering; -static StringConstantsLowering g_stringConstantsLowering; -static PartialExportClassGen g_partialExportClassGen; -static PackageImplicitImport g_packageImplicitImport; -static GenericBridgesPhase g_genericBridgesLowering; -static BoxedTypeLowering g_boxedTypeLowering; -static AsyncMethodLowering g_asyncMethodLowering; -static TypeFromLowering g_typeFromLowering; -static ResizableArrayConvert g_resizableArrayConvert; -static RestArgsLowering g_restArgsLowering; -static LateInitializationConvert g_lateInitializationConvert; -static InsertOptionalParametersAnnotation g_insertOptionalParametersAnnotation; -static ConvertPrimitiveCastMethodCall g_convertPrimitiveCastMethodCall; -static PluginPhase g_pluginsAfterParse {"plugins-after-parse", ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}; -static PluginPhase g_pluginsAfterBind {"plugins-after-bind", ES2PANDA_STATE_BOUND, &util::Plugin::AfterBind}; -static PluginPhase g_pluginsAfterCheck {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; -static PluginPhase g_pluginsAfterLowerings {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, - &util::Plugin::AfterLowerings}; // NOLINTBEGIN(fuchsia-statically-constructed-objects) +static CheckerPhase g_checkerPhase; static InitScopesPhaseETS g_initScopesPhaseEts; static InitScopesPhaseAS g_initScopesPhaseAs; static InitScopesPhaseTs g_initScopesPhaseTs; static InitScopesPhaseJs g_initScopesPhaseJs; // NOLINTEND(fuchsia-statically-constructed-objects) -static DynamicImportLowering g_dynamicImportLowering; +// static DynamicImportLowering g_dynamicImportLowering; +const static inline char *g_pluginsAfterParse = "plugins-after-parse"; +const static inline char *g_pluginsAfterBind = "plugins-after-bind"; +const static inline char *g_pluginsAfterCheck = "plugins-after-check"; +const static inline char *g_pluginsAfterLowering = "plugins-after-lowering"; // CC-OFFNXT(huge_method, G.FUN.01-CPP) long initialization list std::vector GetETSPhaseList() @@ -142,66 +93,77 @@ std::vector GetETSPhaseList() // clang-format off // NOLINTBEGIN return { - &g_pluginsAfterParse, - &g_stringConstantsLowering, - &g_packageImplicitImport, - &g_exportAnonymousConstPhase, - &g_topLevelStatements, - &g_resizableArrayConvert, - &g_expressionLambdaConstructionPhase, - &g_insertOptionalParametersAnnotation, - &g_defaultParametersInConstructorLowering, - &g_defaultParametersLowering, - &g_ambientLowering, - &g_restTupleConstructionPhase, - &g_initScopesPhaseEts, - &g_optionalLowering, - &g_promiseVoidInferencePhase, - &g_interfacePropDeclPhase, - &g_constantExpressionLowering, - &g_enumLoweringPhase, - &g_resolveIdentifiers, - &g_pluginsAfterBind, - &g_capturedVariables, - &g_setJumpTargetPhase, - &g_cfgBuilderPhase, - &g_checkerPhase, // please DO NOT change order of these two phases: checkerPhase and pluginsAfterCheck - &g_pluginsAfterCheck, // pluginsAfterCheck has to go right after checkerPhase, nothing should be between them - &g_convertPrimitiveCastMethodCall, - &g_dynamicImportLowering, - &g_asyncMethodLowering, - &g_declareOverloadLowering, - &g_enumPostCheckLoweringPhase, - &g_spreadConstructionPhase, - &g_restArgsLowering, - &g_arrayLiteralLowering, - &g_bigintLowering, - &g_opAssignmentLowering, - &g_lateInitializationConvert, - &g_extensionAccessorPhase, - &g_boxingForLocals, - &g_recordLowering, - &g_boxedTypeLowering, - &g_objectIndexLowering, - &g_objectIteratorLowering, - &g_lambdaConversionPhase, - &g_unionLowering, - &g_expandBracketsPhase, - &g_localClassLowering, - &g_partialExportClassGen, - &g_interfaceObjectLiteralLowering, // this lowering should be put after all classs generated. - &g_objectLiteralLowering, - &g_stringConstructorLowering, - &g_stringComparisonLowering, - &g_optionalArgumentsLowering, // #22952 could be moved to earlier phase - &g_genericBridgesLowering, - &g_typeFromLowering, - &g_pluginsAfterLowerings, // pluginsAfterLowerings has to come at the very end, nothing should go after it + new PluginPhase {g_pluginsAfterParse, ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}, + new StringConstantsLowering, + new PackageImplicitImport, + new ExportAnonymousConstPhase, + new TopLevelStatements, + new ResizableArrayConvert, + new ExpressionLambdaConstructionPhase, + new InsertOptionalParametersAnnotation, + new DefaultParametersInConstructorLowering, + new DefaultParametersLowering, + new AmbientLowering, + new RestTupleConstructionPhase, + new InitScopesPhaseETS, + new OptionalLowering, + new PromiseVoidInferencePhase, + new InterfacePropertyDeclarationsPhase, + new ConstantExpressionLowering, + new EnumLoweringPhase, + new ResolveIdentifiers, + new PluginPhase {g_pluginsAfterBind, ES2PANDA_STATE_BOUND, &util::Plugin::AfterBind}, + new CapturedVariables, + new SetJumpTargetPhase, + new CFGBuilderPhase, + // please DO NOT change order of these two phases: checkerPhase and pluginsAfterCheck + new CheckerPhase, + // pluginsAfterCheck has to go right after checkerPhase, nothing should be between them + new PluginPhase {g_pluginsAfterCheck, ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}, + new ConvertPrimitiveCastMethodCall, + new DynamicImportLowering, + new AsyncMethodLowering, + new DeclareOverloadLowering, + new EnumPostCheckLoweringPhase, + new SpreadConstructionPhase, + new RestArgsLowering, + new ArrayLiteralLowering, + new BigIntLowering, + new OpAssignmentLowering, + new LateInitializationConvert, + new ExtensionAccessorPhase, + new BoxingForLocals, + new RecordLowering, + new BoxedTypeLowering, + new ObjectIndexLowering, + new ObjectIteratorLowering, + new LambdaConversionPhase, + new UnionLowering, + new ExpandBracketsPhase, + new LocalClassConstructionPhase, + new PartialExportClassGen, + new InterfaceObjectLiteralLowering, // must be put after all classes are generated. + new ObjectLiteralLowering, + new StringConstructorLowering, + new StringComparisonLowering, + new OptionalArgumentsLowering, // #22952 could be moved to earlier phase + new GenericBridgesPhase, + new TypeFromLowering, + // pluginsAfterLowerings has to come at the very end, nothing should go after it + new PluginPhase{g_pluginsAfterLowering, ES2PANDA_STATE_LOWERED, + &util::Plugin::AfterLowerings}, }; // NOLINTEND // clang-format on } +void DestoryETSPhaseList(std::vector &list) +{ + for (auto *phase : list) { + delete phase; + } +} + std::vector GetASPhaseList() { return { @@ -239,6 +201,16 @@ void SetPhaseManager(PhaseManager *phaseManager) g_phaseManager = phaseManager; } +void PhaseManager::Reset() +{ + prev_ = {0, INVALID_PHASE_ID}; + curr_ = {0, PARSER_PHASE_ID}; + next_ = PARSER_PHASE_ID + 1; + ES2PANDA_ASSERT(next_ == 0); + + SetPhaseManager(this); +} + bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) { SetPhaseManager(ctx->phaseManager); @@ -246,7 +218,7 @@ bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) #ifndef NDEBUG if (!Precondition(ctx, program)) { - ctx->checker->LogError(diagnostic::PRECOND_FAILED, {Name()}, lexer::SourcePosition {}); + ctx->GetChecker()->LogError(diagnostic::PRECOND_FAILED, {Name()}, lexer::SourcePosition {}); return false; } #endif @@ -257,7 +229,7 @@ bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) #ifndef NDEBUG if (!Postcondition(ctx, program)) { - ctx->checker->LogError(diagnostic::POSTCOND_FAILED, {Name()}, lexer::SourcePosition {}); + ctx->GetChecker()->LogError(diagnostic::POSTCOND_FAILED, {Name()}, lexer::SourcePosition {}); return false; } #endif @@ -270,6 +242,9 @@ bool PhaseForDeclarations::Precondition(public_lib::Context *ctx, const parser:: for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { + if (extProg->IsASTLowered()) { + continue; + } if (!Precondition(ctx, extProg)) { return false; } @@ -281,11 +256,14 @@ bool PhaseForDeclarations::Precondition(public_lib::Context *ctx, const parser:: bool PhaseForDeclarations::Perform(public_lib::Context *ctx, parser::Program *program) { + FetchCache(ctx, program); bool result = true; for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { - result &= Perform(ctx, extProg); + if (!extProg->IsASTLowered()) { + result &= Perform(ctx, extProg); + } } } @@ -298,6 +276,9 @@ bool PhaseForDeclarations::Postcondition(public_lib::Context *ctx, const parser: for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { + if (extProg->IsASTLowered()) { + continue; + } if (!Postcondition(ctx, extProg)) { return false; } @@ -330,17 +311,27 @@ bool PhaseForBodies::Precondition(public_lib::Context *ctx, const parser::Progra return PreconditionForModule(ctx, program); } -bool PhaseForBodies::Perform(public_lib::Context *ctx, parser::Program *program) +bool PhaseForBodies::ProcessExternalPrograms(public_lib::Context *ctx, parser::Program *program) { bool result = true; - if (ctx->config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB) { - for (auto &[_, extPrograms] : program->ExternalSources()) { - (void)_; - for (auto *extProg : extPrograms) { + for (auto &[_, extPrograms] : program->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + if (!extProg->IsASTLowered()) { result &= Perform(ctx, extProg); } } } + return result; +} + +bool PhaseForBodies::Perform(public_lib::Context *ctx, parser::Program *program) +{ + FetchCache(ctx, program); + bool result = true; + if (ctx->config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB) { + result &= ProcessExternalPrograms(ctx, program); + } result &= PerformForModule(ctx, program); return result; @@ -369,6 +360,13 @@ bool PhaseForBodies::Postcondition(public_lib::Context *ctx, const parser::Progr return PostconditionForModule(ctx, program); } +PhaseManager::~PhaseManager() +{ + if (ScriptExtension::ETS == ext_) { + DestoryETSPhaseList(phases_); + } +} + void PhaseManager::InitializePhases() { switch (ext_) { @@ -390,6 +388,19 @@ void PhaseManager::InitializePhases() int id = 0; for (auto phase : phases_) { + // js side UI plugin needs an extra phaseID, which is different from c++ side plugin phase + if (phase->Name() == std::string(g_pluginsAfterParse)) { + jsPluginAfterParse_ = id++; + } + if (phase->Name() == std::string(g_pluginsAfterBind)) { + jsPluginAfterBind_ = id++; + } + if (phase->Name() == std::string(g_pluginsAfterCheck)) { + jsPluginAfterCheck_ = id++; + } + if (phase->Name() == std::string(g_pluginsAfterLowering)) { + jsPluginAfterLower_ = id++; + } phase->id_ = id++; } } @@ -403,21 +414,36 @@ std::vector PhaseManager::AllPhases() std::vector PhaseManager::RebindPhases() { ES2PANDA_ASSERT(IsInitialized()); - return { - &g_initScopesPhaseEts, - &g_resolveIdentifiers, - }; + return GetSubPhases({ScopesInitPhase::NAME, ResolveIdentifiers::NAME}); +} + +std::vector PhaseManager::GetSubPhases(const std::vector &phaseNames) +{ + std::vector phases; + for (auto &phaseName : phaseNames) { + for (auto phase : phases_) { + if (phase->Name() == phaseName) { + phases.emplace_back(phase); + } + } + } + return phases; } std::vector PhaseManager::RecheckPhases() { ES2PANDA_ASSERT(IsInitialized()); - return { - &g_initScopesPhaseEts, - &g_resolveIdentifiers, - &g_capturedVariables, - &g_checkerPhase, - }; + return GetSubPhases({ScopesInitPhase::NAME, ResolveIdentifiers::NAME, "CapturedVariables", CheckerPhase::NAME}); +} + +int32_t PhaseManager::GetCurrentMajor() const +{ + return curr_.major; +} + +int32_t PhaseManager::GetCurrentMinor() const +{ + return curr_.minor; } } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/phase.h b/ets2panda/compiler/lowering/phase.h index e1ff9c3885..63c3e493f4 100644 --- a/ets2panda/compiler/lowering/phase.h +++ b/ets2panda/compiler/lowering/phase.h @@ -16,21 +16,28 @@ #ifndef ES2PANDA_COMPILER_LOWERING_PHASE_H #define ES2PANDA_COMPILER_LOWERING_PHASE_H +#include "macros.h" #include "parser/program/program.h" #include "public/public.h" +#include "phase_id.h" namespace ark::es2panda::compiler { -constexpr int32_t INVALID_PHASE_ID = -2; -constexpr int32_t PARSER_PHASE_ID = -1; - class Phase { public: /* If Apply returns false, processing is stopped. */ bool Apply(public_lib::Context *ctx, parser::Program *program); + virtual ~Phase() = default; + Phase() = default; + + NO_COPY_SEMANTIC(Phase); + NO_MOVE_SEMANTIC(Phase); + virtual std::string_view Name() const = 0; + virtual void FetchCache([[maybe_unused]] public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) {} + virtual bool Precondition([[maybe_unused]] public_lib::Context *ctx, [[maybe_unused]] const parser::Program *program) { @@ -73,6 +80,7 @@ class PhaseForDeclarations : public Phase { */ class PhaseForBodies : public Phase { bool Precondition(public_lib::Context *ctx, const parser::Program *program) override; + bool ProcessExternalPrograms(public_lib::Context *ctx, parser::Program *program); bool Perform(public_lib::Context *ctx, parser::Program *program) override; bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; @@ -95,23 +103,46 @@ public: PhaseManager(ScriptExtension ext, ArenaAllocator *allocator) : allocator_ {allocator}, ext_ {ext} { InitializePhases(); - Restart(); + Reset(); + } + + PhaseManager(public_lib::Context *context, ScriptExtension ext, ArenaAllocator *allocator) + : PhaseManager(ext, allocator) + { + context_ = context; + } + + NO_COPY_SEMANTIC(PhaseManager); + NO_MOVE_SEMANTIC(PhaseManager); + + ~PhaseManager(); + + public_lib::Context *Context() + { + return context_; } - int32_t PreviousPhaseId() const + PhaseId PreviousPhaseId() const { return prev_; } - int32_t CurrentPhaseId() const + PhaseId CurrentPhaseId() const { return curr_; } void SetCurrentPhaseId(int32_t phaseId) { + if (phaseId == curr_.minor) { + return; + } prev_ = curr_; - curr_ = phaseId; + + if (curr_.minor > phaseId) { + curr_.major++; + } + curr_.minor = phaseId; } ArenaAllocator *Allocator() const @@ -124,13 +155,7 @@ public: return allocator_ != nullptr && ext_ != ScriptExtension::INVALID; } - void Restart() - { - prev_ = INVALID_PHASE_ID; - curr_ = PARSER_PHASE_ID; - next_ = PARSER_PHASE_ID + 1; - ES2PANDA_ASSERT(next_ == 0); - } + void Reset(); Phase *NextPhase() { @@ -144,20 +169,47 @@ public: std::vector RebindPhases(); std::vector RecheckPhases(); + void SetCurrentPhaseIdToAfterParse() + { + GetPhaseManager()->SetCurrentPhaseId(jsPluginAfterParse_); + } + + void SetCurrentPhaseIdToAfterBind() + { + GetPhaseManager()->SetCurrentPhaseId(jsPluginAfterBind_); + } + + void SetCurrentPhaseIdToAfterCheck() + { + GetPhaseManager()->SetCurrentPhaseId(jsPluginAfterCheck_); + } + + void SetCurrentPhaseIdToAfterLower() + { + GetPhaseManager()->SetCurrentPhaseId(jsPluginAfterLower_); + } + + int32_t GetCurrentMajor() const; + int32_t GetCurrentMinor() const; + + std::vector GetSubPhases(const std::vector &phaseNames); + private: void InitializePhases(); - int32_t prev_ {INVALID_PHASE_ID}; - int32_t curr_ {INVALID_PHASE_ID}; + PhaseId prev_ {0, INVALID_PHASE_ID}; + PhaseId curr_ {0, INVALID_PHASE_ID}; int32_t next_ {INVALID_PHASE_ID}; + int32_t jsPluginAfterParse_ {0}; + int32_t jsPluginAfterBind_ {0}; + int32_t jsPluginAfterCheck_ {0}; + int32_t jsPluginAfterLower_ {0}; ArenaAllocator *allocator_ {nullptr}; + public_lib::Context *context_ {nullptr}; ScriptExtension ext_ {ScriptExtension::INVALID}; std::vector phases_; }; -PhaseManager *GetPhaseManager(); -void SetPhaseManager(PhaseManager *phaseManager); - } // namespace ark::es2panda::compiler #endif diff --git a/ets2panda/compiler/lowering/phase_id.h b/ets2panda/compiler/lowering/phase_id.h new file mode 100644 index 0000000000..a3ba46c8f5 --- /dev/null +++ b/ets2panda/compiler/lowering/phase_id.h @@ -0,0 +1,56 @@ +/* + * 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_PHASE_ID_H +#define ES2PANDA_COMPILER_LOWERING_PHASE_ID_H + +namespace ark::es2panda::compiler { + +constexpr int32_t INVALID_PHASE_ID = -2; +constexpr int32_t PARSER_PHASE_ID = -1; + +struct PhaseId { + int32_t major; // NOLINT(misc-non-private-member-variables-in-classes) + int32_t minor; // NOLINT(misc-non-private-member-variables-in-classes) + + bool operator<(const PhaseId &other) const + { + return major == other.major ? minor < other.minor : major < other.major; + } + + bool operator<=(const PhaseId &other) const + { + return major == other.major ? minor <= other.minor : major <= other.major; + } + + bool operator==(const PhaseId &other) const + { + return major == other.major && minor == other.minor; + } + + bool operator>=(const PhaseId &other) const + { + return major == other.major ? minor >= other.minor : major >= other.major; + } + + bool operator>(const PhaseId &other) const + { + return major == other.major ? minor > other.minor : major > other.major; + } +}; + +} // namespace ark::es2panda::compiler + +#endif diff --git a/ets2panda/compiler/lowering/plugin_phase.cpp b/ets2panda/compiler/lowering/plugin_phase.cpp index 14f72aa7f0..f4dcbebf93 100644 --- a/ets2panda/compiler/lowering/plugin_phase.cpp +++ b/ets2panda/compiler/lowering/plugin_phase.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Copyright (c) 2023-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 @@ -28,7 +28,7 @@ bool PluginPhase::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Pro for (auto &plugin : *(ctx->plugins)) { (plugin.*methodCall_)(reinterpret_cast(ctx)); if (ctx->state == ES2PANDA_STATE_ERROR) { - ctx->checker->LogTypeError(ctx->errorMessage, ctx->errorPos); + ctx->GetChecker()->LogTypeError(ctx->errorMessage, ctx->errorPos); return false; } } diff --git a/ets2panda/compiler/lowering/resolveIdentifiers.cpp b/ets2panda/compiler/lowering/resolveIdentifiers.cpp index cc13b62ce3..541af34dee 100644 --- a/ets2panda/compiler/lowering/resolveIdentifiers.cpp +++ b/ets2panda/compiler/lowering/resolveIdentifiers.cpp @@ -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 @@ -19,12 +19,45 @@ #include "util/options.h" namespace ark::es2panda::compiler { + +void ResolveIdentifiers::InsertReExported(parser::Program *program, varbinder::ETSBinder *pVarBinder, + parser::Program *extProgram) +{ + auto etsBinder = extProgram->VarBinder()->AsETSBinder(); + auto &reExportedImports = pVarBinder->ReExportImports(); + for (auto &it : etsBinder->ReExportImports()) { + if (it->GetTopStatement()->AsETSModule()->Program()->SourceFile().GetPath() != + program->SourceFile().GetPath()) { + reExportedImports.insert(it); + } + } + + auto &aliasMap = pVarBinder->GetSelectiveExportAliasMultimap(); + aliasMap.insert(etsBinder->GetSelectiveExportAliasMultimap().begin(), + etsBinder->GetSelectiveExportAliasMultimap().end()); +} + +void ResolveIdentifiers::FetchCache([[maybe_unused]] public_lib::Context *ctx, + [[maybe_unused]] parser::Program *program) +{ + auto pVarBinder = program->VarBinder()->AsETSBinder(); + for (auto &[package, extPrograms] : program->ExternalSources()) { + auto *extProgram = extPrograms.front(); + if (!extProgram->IsStdLib() && extProgram->IsASTLowered()) { + InsertReExported(program, pVarBinder, extProgram); + } + } +} + bool ResolveIdentifiers::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) { + FetchCache(ctx, program); auto const *options = ctx->config->options; auto *varbinder = ctx->parserProgram->VarBinder()->AsETSBinder(); - if (options->IsDumpAst()) { + static bool firstDump = true; + if (options->IsDumpAst() && firstDump) { + firstDump = false; std::cout << varbinder->Program()->Dump() << std::endl; } diff --git a/ets2panda/compiler/lowering/resolveIdentifiers.h b/ets2panda/compiler/lowering/resolveIdentifiers.h index 186363fbb0..1b7f962edb 100644 --- a/ets2panda/compiler/lowering/resolveIdentifiers.h +++ b/ets2panda/compiler/lowering/resolveIdentifiers.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 @@ -23,12 +23,16 @@ class ResolveIdentifiers : public Phase { public: static constexpr std::string_view NAME = "ResolveIdentifiers"; + void FetchCache(public_lib::Context *ctx, parser::Program *program) override; + std::string_view Name() const override { return "ResolveIdentifiers"; } bool Perform(public_lib::Context *ctx, parser::Program *program) override; + + void InsertReExported(parser::Program *program, varbinder::ETSBinder *pVarBinder, parser::Program *extProgram); }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/scopesInit/savedBindingsCtx.cpp b/ets2panda/compiler/lowering/scopesInit/savedBindingsCtx.cpp index 56aa8c8318..8d4ee9e016 100644 --- a/ets2panda/compiler/lowering/scopesInit/savedBindingsCtx.cpp +++ b/ets2panda/compiler/lowering/scopesInit/savedBindingsCtx.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 - 2023 Huawei Device Co., Ltd. + * Copyright (c) 2021 - 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 @@ -55,7 +55,7 @@ void ExportDeclarationContext::BindExportDecl(ir::AstNode *exportDecl) util::StringView(DEFAULT_EXPORT), rhs->AsFunctionDeclaration()->Function()); } else { - VarBinder()->AddDecl(rhs->Start(), util::StringView(DEFAULT_EXPORT)); + VarBinder()->AddDecl(rhs->Start(), util::StringView(DEFAULT_EXPORT), rhs); } } } diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 49bec80f6e..b0c239c381 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -841,6 +841,9 @@ void InitScopesPhaseETS::HandleProgram(parser::Program *program) (void)_; auto savedTopScope(program->VarBinder()->TopScope()); auto mainProg = progList.front(); + if (mainProg->IsASTLowered()) { + continue; + } mainProg->VarBinder()->InitTopScope(); AddGlobalToBinder(mainProg); BindScopeNode(mainProg->VarBinder()->GetScope(), mainProg->Ast()); @@ -1251,7 +1254,9 @@ void InitScopesPhaseETS::VisitClassDefinition(ir::ClassDefinition *classDef) auto classCtx = LexicalScopeCreateOrEnter(VarBinder(), classDef); IterateNoTParams(classDef); - FilterOverloads(classDef->Body()); + + // Will generate new node when compiling decl, so when compiling main file, will not generate new history in decl. + FilterOverloads(classDef->BodyForUpdate()); auto *classScope = classCtx.GetScope(); BindScopeNode(classScope, classDef); } @@ -1378,7 +1383,7 @@ void InitScopesPhaseETS::ParseGlobalClass(ir::ClassDefinition *global) CallNode(decl); } CallNode(global->Annotations()); - FilterOverloads(global->Body()); + FilterOverloads(global->BodyForUpdate()); } void InitScopesPhaseETS::AddGlobalDeclaration(ir::AstNode *node) diff --git a/ets2panda/compiler/lowering/util.cpp b/ets2panda/compiler/lowering/util.cpp index 09fe048e25..dfddc8ba92 100644 --- a/ets2panda/compiler/lowering/util.cpp +++ b/ets2panda/compiler/lowering/util.cpp @@ -52,7 +52,13 @@ ir::Identifier *Gensym(ArenaAllocator *const allocator) util::UString GenName(ArenaAllocator *const allocator) { static std::size_t gensymCounter = 0U; - return util::UString {std::string(GENSYM_CORE) + std::to_string(++gensymCounter), allocator}; + static std::mutex gensymCounterMutex {}; + std::size_t individualGensym = 0; + { + std::lock_guard lock(gensymCounterMutex); + individualGensym = ++gensymCounter; + } + return util::UString {std::string(GENSYM_CORE) + std::to_string(individualGensym), allocator}; } void SetSourceRangesRecursively(ir::AstNode *node, const lexer::SourceRange &range) @@ -69,7 +75,7 @@ ir::AstNode *RefineSourceRanges(ir::AstNode *node) }; auto const refine = [isDummyLoc](ir::AstNode *ast) { - if (isDummyLoc(ast->Range(), ast) && ast->Parent() != nullptr) { + if (ast->Parent() != nullptr && isDummyLoc(ast->Range(), ast)) { ast->SetRange(ast->Parent()->Range()); } }; @@ -167,7 +173,7 @@ static void ClearHelper(parser::Program *prog) { ResetGlobalClass(prog); // #24256 Should be removed when code refactoring on checker is done and no ast node allocated in checker. - auto &stmts = prog->Ast()->Statements(); + auto &stmts = prog->Ast()->StatementsForUpdates(); // clang-format off stmts.erase(std::remove_if(stmts.begin(), stmts.end(), [](ir::AstNode *ast) -> bool { @@ -216,31 +222,56 @@ varbinder::Scope *Rebind(PhaseManager *phaseManager, varbinder::ETSBinder *varBi return scope; } +void HandleExternalProgram(varbinder::ETSBinder *newVarbinder, parser::Program *program) +{ + for (auto [_, program_list] : program->ExternalSources()) { + for (auto prog : program_list) { + if (!prog->IsASTLowered()) { + ClearHelper(prog); + prog->PushVarBinder(newVarbinder); + } + } + } +} + // Rerun varbinder and checker on the node. void Recheck(PhaseManager *phaseManager, varbinder::ETSBinder *varBinder, checker::ETSChecker *checker, ir::AstNode *node) { RefineSourceRanges(node); if (node->IsProgram()) { + auto ctx = varBinder->GetContext(); + phaseManager->SetCurrentPhaseId(0); auto program = node->AsETSModule()->Program(); - if (program->IsPackage()) { - return; - } - for (auto [_, program_list] : program->ExternalSources()) { - for (auto prog : program_list) { - ClearHelper(prog); - } - } + auto newVarbinder = ctx->allocator->New(ctx->allocator); + newVarbinder->SetProgram(program); + newVarbinder->SetContext(ctx); + program->PushVarBinder(newVarbinder); + varBinder->CopyTo(newVarbinder); + HandleExternalProgram(newVarbinder, program); ClearHelper(program); - varBinder->CleanUp(); - varBinder->GetContext()->checker->CleanUp(); + auto newChecker = + ctx->allocator->New(ctx->allocator, *ctx->diagnosticEngine, ctx->allocator); + auto analyzer = ctx->allocator->New(newChecker); + + ctx->PushAnalyzer(analyzer); + newChecker->SetAnalyzer(analyzer); + newChecker->Initialize(newVarbinder); + ctx->PushChecker(newChecker); + for (auto [_, program_list] : program->ExternalSources()) { + if (auto prog = program_list.front(); prog->IsASTLowered()) { + newChecker->SetGlobalTypesHolder(prog->Checker()->GetGlobalTypesHolder()); + break; + } + } for (auto *phase : phaseManager->RecheckPhases()) { - phase->Apply(varBinder->GetContext(), program); + phase->Apply(ctx, program); } + phaseManager->SetCurrentPhaseIdToAfterCheck(); return; } diff --git a/ets2panda/declgen_ets2ts/main.cpp b/ets2panda/declgen_ets2ts/main.cpp index d55467fc90..385e9f37c8 100644 --- a/ets2panda/declgen_ets2ts/main.cpp +++ b/ets2panda/declgen_ets2ts/main.cpp @@ -105,7 +105,7 @@ static int Run(int argc, const char **argv) impl->CreateContextFromString(cfg, parserInputCStr, cfgImpl->options->SourceFileName().c_str()); auto *ctxImpl = reinterpret_cast(ctx); - auto *checker = reinterpret_cast(ctxImpl->checker); + auto *checker = reinterpret_cast(ctxImpl->GetChecker()); auto *isolatedDeclgenChecker = reinterpret_cast(ctxImpl->isolatedDeclgenChecker); impl->ProceedToState(ctx, ES2PANDA_STATE_BOUND); diff --git a/ets2panda/driver/build_system/src/build/base_mode.ts b/ets2panda/driver/build_system/src/build/base_mode.ts index 99fad43361..5d374555e6 100644 --- a/ets2panda/driver/build_system/src/build/base_mode.ts +++ b/ets2panda/driver/build_system/src/build/base_mode.ts @@ -17,10 +17,17 @@ import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs'; import * as child_process from 'child_process'; +import * as crypto from 'crypto'; + + import cluster, { Cluster, - Worker + Worker, } from 'cluster'; +import { + Worker as ThreadWorker, + workerData +} from 'worker_threads'; import { ABC_SUFFIX, ARKTSCONFIG_JSON_FILE, @@ -59,13 +66,18 @@ import { CompileFileInfo, DependencyFileConfig, DependentModuleConfig, + JobInfo, + KPointer, ModuleInfo } from '../types'; import { ArkTSConfigGenerator } from './generate_arktsconfig'; import { SetupClusterOptions } from '../types'; +import { create } from 'domain'; +import { emitKeypressEvents } from 'readline'; export abstract class BaseMode { buildConfig: BuildConfig; entryFiles: Set; + allFiles: Map; compileFiles: Map; outputDir: string; cacheDir: string; @@ -93,6 +105,7 @@ export abstract class BaseMode { isCacheFileExists: boolean; dependencyFileMap: DependencyFileConfig | null; isBuildConfigModified: boolean | undefined; + hasCleanWorker: boolean; constructor(buildConfig: BuildConfig) { this.buildConfig = buildConfig; @@ -121,12 +134,14 @@ export abstract class BaseMode { this.moduleInfos = new Map(); this.compileFiles = new Map(); + this.allFiles = new Map(); this.mergedAbcFile = path.resolve(this.outputDir, MERGED_ABC_FILE); this.dependencyJsonFile = path.resolve(this.cacheDir, DEPENDENCY_JSON_FILE); this.abcLinkerCmd = ['"' + this.buildConfig.abcLinkerPath + '"']; this.dependencyAnalyzerCmd = ['"' + this.buildConfig.dependencyAnalyzerPath + '"']; this.logger = Logger.getInstance(); + this.hasCleanWorker = false; } public declgen(fileInfo: CompileFileInfo): void { @@ -465,8 +480,17 @@ export abstract class BaseMode { const filePathFromModuleRoot = path.relative(moduleInfo.moduleRootPath, file); const filePathInCache = path.join(this.cacheDir, moduleInfo.packageName, filePathFromModuleRoot); const abcFilePath = path.resolve(changeFileExtension(filePathInCache, ABC_SUFFIX)); - this.abcFiles.add(abcFilePath); + + const fileInfo: CompileFileInfo = { + filePath: file, + dependentFiles: this.dependencyFileMap?.dependants[file] || [], + abcFilePath, + arktsConfigFile: moduleInfo.arktsConfigFile, + packageName: moduleInfo.packageName + }; + this.allFiles.set(file, fileInfo); + if (this.isBuildConfigModified || this.isFileChanged(file, abcFilePath)) { compileFiles.add(file); queue.push(file); @@ -541,7 +565,7 @@ export abstract class BaseMode { } protected collectCompileFiles(): void { - if (!this.isBuildConfigModified && this.isCacheFileExists && !this.enableDeclgenEts2Ts) { + if (!this.enableDeclgenEts2Ts) { this.collectDependentCompileFiles(); return; } @@ -554,19 +578,16 @@ export abstract class BaseMode { let filePathInCache: string = path.join(this.cacheDir, moduleInfo.packageName, filePathFromModuleRoot); let abcFilePath: string = path.resolve(changeFileExtension(filePathInCache, ABC_SUFFIX)); this.abcFiles.add(abcFilePath); - if (!this.isBuildConfigModified && this.shouldSkipFile(file, moduleInfo, filePathFromModuleRoot, abcFilePath)) { - return; - } this.hashCache[file] = getFileHash(file); let fileInfo: CompileFileInfo = { - filePath: file, + filePath: path.resolve(file), dependentFiles: [], abcFilePath: abcFilePath, arktsConfigFile: moduleInfo.arktsConfigFile, packageName: moduleInfo.packageName }; moduleInfo.compileFileInfos.push(fileInfo); - this.compileFiles.set(file, fileInfo); + this.compileFiles.set(path.resolve(file), fileInfo); return; } const logData: LogData = LogDataFactory.newInstance( @@ -615,6 +636,7 @@ export abstract class BaseMode { this.mergeAbcFiles(); } + // -- runParallell code begins -- private terminateAllWorkers(): void { Object.values(cluster.workers || {}).forEach(worker => { worker?.kill(); @@ -622,7 +644,7 @@ export abstract class BaseMode { }; public generatedependencyFileMap(): void { - if (this.isBuildConfigModified || !this.isCacheFileExists || this.enableDeclgenEts2Ts) { + if (this.enableDeclgenEts2Ts) { return; } let dependencyInputFile: string = path.join(this.cacheDir, DEPENDENCY_INPUT_FILE); @@ -808,7 +830,6 @@ export abstract class BaseMode { }); return JSON.parse(jsonStr); } - setupCluster(cluster: Cluster, options: SetupClusterOptions): void { const { clearExitListeners, @@ -825,4 +846,488 @@ export abstract class BaseMode { execArgv: execArgs, }); } + // -- runParallell code ends -- + + + // -- runConcurrent code begins -- + + private findStronglyConnectedComponents(graph: DependencyFileConfig): Map> { + const adjacencyList: Record = {}; + const reverseAdjacencyList: Record = {}; + const allNodes = new Set(); + + for (const node in graph.dependencies) { + allNodes.add(node); + graph.dependencies[node].forEach(dep => allNodes.add(dep)); + } + for (const node in graph.dependants) { + allNodes.add(node); + graph.dependants[node].forEach(dep => allNodes.add(dep)); + } + + Array.from(allNodes).forEach(node => { + adjacencyList[node] = graph.dependencies[node] || []; + reverseAdjacencyList[node] = graph.dependants[node] || []; + }); + + const visited = new Set(); + const order: string[] = []; + + function dfs(node: string): void { + visited.add(node); + for (const neighbor of adjacencyList[node]) { + if (!visited.has(neighbor)) { + dfs(neighbor); + } + } + order.push(node); + } + + Array.from(allNodes).forEach(node => { + if (!visited.has(node)) { + dfs(node); + } + }); + + visited.clear(); + const components = new Map>(); + + function reverseDfs(node: string, component: Set): void { + visited.add(node); + component.add(node); + for (const neighbor of reverseAdjacencyList[node]) { + if (!visited.has(neighbor)) { + reverseDfs(neighbor, component); + } + } + } + + for (let i = order.length - 1; i >= 0; i--) { + const node = order[i]; + if (!visited.has(node)) { + const component = new Set(); + reverseDfs(node, component); + if (component.size > 1) { + const sortedFiles = Array.from(component).sort(); + const hashKey = createHash(sortedFiles.join('|')); + components.set(hashKey, component); + } + + } + } + + return components; + } + + + private getJobDependencies(fileDeps: string[], cycleFiles: Map): Set { + let depJobList: Set = new Set(); + fileDeps.forEach((file) => { + if (!cycleFiles.has(file)) { + depJobList.add(this.getExternalProgramJobId(file)); + } else { + cycleFiles.get(file)?.forEach((f) => { + depJobList.add(f); + }); + } + }); + + return depJobList; + } + + private getAbcJobId(file: string): string { + return '1' + file; + } + + private getExternalProgramJobId(file: string): string { + return '0' + file; + } + + private getJobDependants(fileDeps: string[], cycleFiles: Map): Set { + let depJobList: Set = new Set(); + fileDeps.forEach((file) => { + if (!file.endsWith(DECL_ETS_SUFFIX)) { + depJobList.add(this.getAbcJobId(file)); + } + if (cycleFiles.has(file)) { + cycleFiles.get(file)?.forEach((f) => { + depJobList.add(f); + }); + } else { + depJobList.add(this.getExternalProgramJobId(file)); + } + }); + + return depJobList; + } + + private collectCompileJobs(jobs: Record): void { + let fileDepsInfo: DependencyFileConfig = this.dependencyFileMap!; + Object.keys(fileDepsInfo.dependants).forEach((file) => { + if (!(file in fileDepsInfo.dependencies)) { + fileDepsInfo.dependencies[file] = []; + } + }); + + const cycleGroups = this.findStronglyConnectedComponents(fileDepsInfo); + let cycleFiles: Map = new Map(); + cycleGroups.forEach((value: Set, key: string) => { + value.forEach((file) => { + cycleFiles.set(file, [key]); + }); + }); + + Object.entries(fileDepsInfo.dependencies).forEach(([key, value]) => { + if (this.entryFiles.has(key) && !this.compileFiles.has(key)) { + return; + } + let dependencies = this.getJobDependencies(value, cycleFiles); + + if (!key.endsWith(DECL_ETS_SUFFIX)) { + let abcJobId: string = this.getAbcJobId(key); + jobs[abcJobId] = { + id: abcJobId, + isDeclFile: false, + isInCycle: cycleFiles.has(key), + isAbcJob: true, + fileList: [key], + dependencies: Array.from(dependencies), // 依赖external program + dependants: [] + }; + } + + if (cycleFiles.has(key)) { + const externalProgramJobIds = cycleFiles.get(key)!; + externalProgramJobIds.forEach((id) => { + let fileList: string[] = Array.from(cycleGroups.get(id)!); + this.createExternalProgramJob(id, fileList, jobs, dependencies, true); + }); + } else { + const id = this.getExternalProgramJobId(key); + let fileList: string[] = [key]; + this.createExternalProgramJob(id, fileList, jobs, dependencies); + } + + if (key.endsWith(DECL_ETS_SUFFIX)) { + let fileInfo: CompileFileInfo = { + filePath: key, + dependentFiles: [], + abcFilePath: '', + arktsConfigFile: this.moduleInfos.get(this.packageName)!.arktsConfigFile, + packageName: this.moduleInfos.get(this.packageName)!.packageName + }; + + if (!this.allFiles.has(key)) { + this.allFiles.set(key, fileInfo); + } + } + }); + + Object.entries(fileDepsInfo.dependants).forEach(([key, value]) => { + if (this.entryFiles.has(key) && !this.compileFiles.has(key)) { + return; + } + let dependants = this.getJobDependants(value, cycleFiles); + + this.dealWithDependants(cycleFiles, key, jobs, dependants); + }); + } + + private dealWithDependants(cycleFiles: Map, key: string, jobs: Record, dependants: Set): void { + if (cycleFiles.has(key)) { + const externalProgramJobIds = cycleFiles.get(key)!; + externalProgramJobIds.forEach((id) => { + jobs[id].dependants.forEach(dep => { + dependants.add(dep); + }); + if (dependants.has(id)) { + dependants.delete(id); + } + + jobs[id].dependants = Array.from(dependants); + }); + } else { + const id = this.getExternalProgramJobId(key); + jobs[id].dependants.forEach(dep => { + dependants.add(dep); + }); + if (dependants.has(id)) { + dependants.delete(id); + } + jobs[id].dependants = Array.from(dependants); + } + } + + private createExternalProgramJob(id: string, fileList: string[], jobs: Record, dependencies: Set, isInCycle?: boolean): void { + if (dependencies.has(id)) { + dependencies.delete(id); + } + + // TODO: can be duplicated ids + if (jobs[id]) { + // If job already exists, merge the file lists and dependencies + const existingJob = jobs[id]; + const mergedDependencies = new Set([ + ...existingJob.dependencies, + ...Array.from(dependencies) + ]); + jobs[id] = { + ...existingJob, + dependencies: Array.from(mergedDependencies) + }; + } else { + jobs[id] = { + id, + fileList, + isDeclFile: true, + isInCycle, + isAbcJob: false, + dependencies: Array.from(dependencies), // 依赖external program + dependants: [] + }; + } + } + + private addJobToQueues(job: Job, queues: Queues): void { + if (queues.externalProgramQueue.some(j => j.id === job.id) || + queues.abcQueue.some(j => j.id === job.id)) { + return; + } + + if (!job.isAbcJob) { + queues.externalProgramQueue.push(job); + } else { + queues.abcQueue.push(job); + } + } + + private initCompileQueues(jobs: Record, queues: Queues): void { + this.collectCompileJobs(jobs); + Object.values(jobs).forEach(job => { + if (job.dependencies.length === 0) { + this.addJobToQueues(job, queues); + } + }); + } + + private checkAllTasksDone(queues: Queues, workerPool: WorkerInfo[]): boolean { + if (queues.externalProgramQueue.length === 0) { + for (let i = 0; i < workerPool.length; i++) { + if (!workerPool[i].isIdle) { + return false; + } + } + return true; + } + return false; + } + + private processAfterCompile(config: KPointer, globalContext: KPointer): void { + + if (this.hasCleanWorker) { + return; + } + this.hasCleanWorker = true; + let arktsGlobal = this.buildConfig.arktsGlobal; + let arkts = this.buildConfig.arkts; + + arktsGlobal.es2panda._DestroyGlobalContext(globalContext); + arkts.destroyConfig(config); + arktsGlobal.es2panda._MemFinalize(); + + this.mergeAbcFiles(); + } + + // CC-OFFNXT(huge_depth) + private async invokeWorkers(jobs: Record, queues: Queues, processingJobs: Set, workers: ThreadWorker[]): Promise { + return new Promise((resolve) => { + const numWorkers = 1; + + let files: string[] = []; + + Object.entries(jobs).forEach(([key, job]) => { + for (let i = 0; i < job.fileList.length; i++) { + files.push(job.fileList[i]); + } + }); + + let arkts = this.buildConfig.arkts; + let fileInfo = this.compileFiles.values().next().value!; + + let ets2pandaCmd: string[] = [ + '_', + '--extension', + 'ets', + '--arktsconfig', + fileInfo.arktsConfigFile, + '--output', + fileInfo.abcFilePath, + ]; + + if (this.isDebug) { + ets2pandaCmd.push('--debug-info'); + } + ets2pandaCmd.push(fileInfo.filePath); + + arkts.MemInitialize(); + + let config = arkts.Config.create(ets2pandaCmd).peer; + + let globalContextPtr = arkts.CreateGlobalContext(config, files, files.length, false); + const serializableConfig = this.getSerializableConfig(); + + const workerPool: WorkerInfo[] = []; + for (let i = 0; i < numWorkers; i++) { + const worker = new ThreadWorker( + path.resolve(__dirname, 'compile_thread_worker.js'), + { workerData: { workerId: i } } + ); + + workers.push(worker); + workerPool.push({ worker, isIdle: true }); + this.assignTaskToIdleWorker(workerPool[i], queues, processingJobs, serializableConfig, globalContextPtr); + worker.on('message', (msg) => { + if (msg.type === 'TASK_FINISH') { + const workerInfo = workerPool.find(w => w.worker === worker); + if (workerInfo) { + workerInfo.isIdle = true; + } + const jobId = msg.jobId; + finishedJob.push(jobId); + processingJobs.delete(jobId); + const completedJob = jobs[jobId]; + completedJob.dependants.forEach(depJobId => { + const depJob = jobs[depJobId]; + if (!depJob) { + return; + } + const depIndex = depJob.dependencies.indexOf(jobId); + if (depIndex !== -1) { + depJob.dependencies.splice(depIndex, 1); + if (depJob.dependencies.length === 0) { + this.addJobToQueues(depJob, queues); + } + } + }); + for (let j = 0; j < workerPool.length; j++) { + if (workerPool[j].isIdle) { + this.assignTaskToIdleWorker(workerPool[j], queues, processingJobs, serializableConfig, globalContextPtr); + } + } + } + if (this.checkAllTasksDone(queues, workerPool)) { + workers.forEach(worker => worker.postMessage({ type: 'EXIT' })); + this.processAfterCompile(config, globalContextPtr); + resolve(); + } + }); + } + }); + } + + private updateDependantJobs(jobId: string, processingJobs: Set, jobs: Record, queues: Queues): void { + finishedJob.push(jobId); + processingJobs.delete(jobId); + const completedJob = jobs[jobId]; + completedJob.dependants.forEach(depJobId => { + const depJob = jobs[depJobId]; + // During incremental compilation, the dependants task does not necessarily exist + if (!depJob) { + return; + } + const depIndex = depJob.dependencies.indexOf(jobId); + if (depIndex !== -1) { + depJob.dependencies.splice(depIndex, 1); + if (depJob.dependencies.length === 0) { + this.addJobToQueues(depJob, queues); + } + } + }); + } + + private assignTaskToIdleWorker( + workerInfo: WorkerInfo, + queues: Queues, + processingJobs: Set, + serializableConfig: Object, + globalContextPtr: KPointer): void { + let job: Job | undefined; + let jobInfo: JobInfo | undefined; + + if (queues.externalProgramQueue.length > 0) { + job = queues.externalProgramQueue.shift()!; + jobInfo = { + id: job.id, + isCompileAbc: false, + compileFileInfo: this.allFiles.get(job.fileList[0])!, + buildConfig: serializableConfig, + globalContextPtr: globalContextPtr + }; + } + else if (queues.abcQueue.length > 0) { + job = queues.abcQueue.shift()!; + jobInfo = { + id: job.id, + isCompileAbc: true, + compileFileInfo: this.allFiles.get(job.fileList[0])!, + buildConfig: serializableConfig, + globalContextPtr: globalContextPtr + }; + } + + if (job) { + processingJobs.add(job.id); + workerInfo.worker.postMessage({ type: 'ASSIGN_TASK', jobInfo }); + workerInfo.isIdle = false; + } + } + + public async runConcunrent(): Promise { + this.generateModuleInfos(); + if (this.compileFiles.size === 0) { + return; + } + this.generateArkTSConfigForModules(); + + const jobs: Record = {}; + const queues: Queues = { + externalProgramQueue: [], + abcQueue: [], + }; + this.initCompileQueues(jobs, queues); + + const processingJobs = new Set(); + const workers: ThreadWorker[] = []; + await this.invokeWorkers(jobs, queues, processingJobs, workers); + } +} + +interface WorkerInfo { + worker: ThreadWorker; + isIdle: boolean; } + +interface Job { + id: string; + isDeclFile: boolean; + isInCycle?: boolean; + fileList: string[]; + dependencies: string[]; + dependants: string[]; + isAbcJob: boolean; +} + +interface Queues { + externalProgramQueue: Job[]; + abcQueue: Job[]; +} + +function createHash(str: string): string { + const hash = crypto.createHash('sha256'); + hash.update(str); + return hash.digest('hex'); +} + + // -- runConcurrent code ends -- + +let finishedJob: string[] = []; \ No newline at end of file diff --git a/ets2panda/driver/build_system/src/build/build_mode.ts b/ets2panda/driver/build_system/src/build/build_mode.ts index 59bdb759ab..accdafbcca 100644 --- a/ets2panda/driver/build_system/src/build/build_mode.ts +++ b/ets2panda/driver/build_system/src/build/build_mode.ts @@ -26,6 +26,6 @@ export class BuildMode extends BaseMode { } public async run(): Promise { - await super.runParallell(); + await super.runConcunrent(); } } \ No newline at end of file diff --git a/ets2panda/driver/build_system/src/build/compile_thread_worker.ts b/ets2panda/driver/build_system/src/build/compile_thread_worker.ts new file mode 100644 index 0000000000..c8aaed5662 --- /dev/null +++ b/ets2panda/driver/build_system/src/build/compile_thread_worker.ts @@ -0,0 +1,170 @@ +/* + * 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. + */ + +import { parentPort, workerData } from 'worker_threads'; +import { CompileFileInfo, JobInfo } from '../types'; +import * as fs from 'fs'; +import * as path from 'path'; +import { ensurePathExists } from '../utils'; +import { KOALA_WRAPPER_PATH_FROM_SDK } from '../pre_define'; +import { PluginDriver, PluginHook } from '../plugins/plugins_driver'; +import { + BuildConfig, +} from '../types'; +import { + BUILD_MODE +} from '../pre_define'; +import { + LogData, + LogDataFactory, + Logger +} from '../logger'; +import { ErrorCode } from '../error_code'; + +const { workerId } = workerData; + +function compileAbc(jobInfo: JobInfo): void { + let config = jobInfo.buildConfig as BuildConfig; + Logger.getInstance(config); + PluginDriver.getInstance().initPlugins(config); + const koalaWrapperPath = path.resolve(config.buildSdkPath, KOALA_WRAPPER_PATH_FROM_SDK); + let { arkts, arktsGlobal } = require(koalaWrapperPath); + const isDebug = config.buildMode === BUILD_MODE.DEBUG; + + let errorStatus = false; + try { + let fileInfo = jobInfo.compileFileInfo; + ensurePathExists(fileInfo.abcFilePath); + + const ets2pandaCmd = [ + '_', '--extension', 'ets', + '--arktsconfig', fileInfo.arktsConfigFile, + '--output', fileInfo.abcFilePath, + ]; + + if (isDebug) { + ets2pandaCmd.push('--debug-info'); + } + ets2pandaCmd.push(fileInfo.filePath); + + let config = arkts.Config.create(ets2pandaCmd).peer; + arktsGlobal.config = config; + + let context = arkts.Context.createCacheContextFromFile(config, fileInfo.filePath, jobInfo.globalContextPtr, false).peer; + + PluginDriver.getInstance().getPluginContext().setContextPtr(context); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, context); + + PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, context); + + PluginDriver.getInstance().runPluginHook(PluginHook.CHECKED); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED, context); + } catch (error) { + errorStatus = true; + if (error instanceof Error) { + const logData: LogData = LogDataFactory.newInstance( + ErrorCode.BUILDSYSTEM_COMPILE_ABC_FAIL, + 'Compile abc files failed.', + error.message + ); + Logger.getInstance().printError(logData); + } + } finally { + if (!errorStatus) { + // when error occur,wrapper will destroy context. + arktsGlobal.es2panda._DestroyContext(arktsGlobal.compilerContext.peer); + } + PluginDriver.getInstance().runPluginHook(PluginHook.CLEAN); + arkts.destroyConfig(arktsGlobal.config); + } +} + +function compileExternalProgram(jobInfo: JobInfo): void { + let config = jobInfo.buildConfig as BuildConfig; + Logger.getInstance(config); + PluginDriver.getInstance().initPlugins(config); + const koalaWrapperPath = path.resolve(config.buildSdkPath, KOALA_WRAPPER_PATH_FROM_SDK); + let { arkts, arktsGlobal } = require(koalaWrapperPath); + const isDebug = config.buildMode === BUILD_MODE.DEBUG; + + let errorStatus = false; + try { + let fileInfo = jobInfo.compileFileInfo; + const ets2pandaCmd = ['-', '--extension', 'ets', '--arktsconfig', fileInfo.arktsConfigFile]; + + if (isDebug) { + ets2pandaCmd.push('--debug-info'); + } + ets2pandaCmd.push(fileInfo.filePath); + + let config = arkts.Config.create(ets2pandaCmd).peer; + arktsGlobal.config = config; + + let context = arkts.Context.createCacheContextFromFile(config, fileInfo.filePath, jobInfo.globalContextPtr, true).peer; + + PluginDriver.getInstance().getPluginContext().setContextPtr(context); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, context); + + PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, context); + + PluginDriver.getInstance().runPluginHook(PluginHook.CHECKED); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_LOWERED, context); + } catch (error) { + errorStatus = true; + if (error instanceof Error) { + const logData: LogData = LogDataFactory.newInstance( + ErrorCode.BUILDSYSTEM_COMPILE_ABC_FAIL, + 'Compile external program files failed.', + error.message + ); + Logger.getInstance().printError(logData); + } + } finally { + if (!errorStatus) { + // when error occur,wrapper will destroy context. + arktsGlobal.es2panda._DestroyContext(arktsGlobal.compilerContext.peer); + } + PluginDriver.getInstance().runPluginHook(PluginHook.CLEAN); + arkts.destroyConfig(arktsGlobal.config); + } +} + +parentPort?.on('message', (msg) => { + if (msg.type === 'ASSIGN_TASK') { + const job = msg.jobInfo; + + if (job.isCompileAbc) { + compileAbc(job); + } else { + compileExternalProgram(job); + } + + parentPort?.postMessage({ + type: 'TASK_FINISH', + jobId: job.id, + workerId, + }); + } else if (msg.type === 'EXIT') { + process.exit(0); + } +}); diff --git a/ets2panda/driver/build_system/src/entry.ts b/ets2panda/driver/build_system/src/entry.ts index c0a0542d9d..f6cd7ef78e 100644 --- a/ets2panda/driver/build_system/src/entry.ts +++ b/ets2panda/driver/build_system/src/entry.ts @@ -29,6 +29,7 @@ export async function build(projectConfig: BuildConfig): Promise { let logger: Logger = Logger.getInstance(projectConfig); let buildConfig: BuildConfig = processBuildConfig(projectConfig); + buildConfig.entryFiles = buildConfig.compileFiles; if (projectConfig.frameworkMode === true) { let buildframeworkMode: BuildFrameworkMode = new BuildFrameworkMode(buildConfig); await buildframeworkMode.run(); @@ -54,8 +55,6 @@ function clean(): void { } function main(): void { - console.log(process.argv); - const buildConfigPath: string = path.resolve(process.argv[2]); const projectConfig: BuildConfig = JSON.parse(fs.readFileSync(buildConfigPath, 'utf-8')); diff --git a/ets2panda/driver/build_system/src/plugins/FileManager.ts b/ets2panda/driver/build_system/src/plugins/FileManager.ts index 8548c8d092..9a2c8b4e18 100644 --- a/ets2panda/driver/build_system/src/plugins/FileManager.ts +++ b/ets2panda/driver/build_system/src/plugins/FileManager.ts @@ -14,11 +14,10 @@ */ import * as path from 'path'; -import * as fs from 'fs'; -import { BuildConfig, DependentModuleConfig } from "../types"; +import { BuildConfig, DependentModuleConfig } from '../types'; import { toUnixPath } from '../utils'; import { ETS_1_1, ETS_1_1_INTEROP, LANGUAGE_VERSION } from '../pre_define'; -import { readFirstLineSync } from '../utils' +import { readFirstLineSync } from '../utils'; export class FileManager { private static instance: FileManager | undefined = undefined; @@ -52,7 +51,7 @@ export class FileManager { static initSDK(externalApiPath: Set, buildSDKPath: string): void { externalApiPath?.forEach(path => { FileManager.staticApiPath.add(toUnixPath(path)); - }) + }); const etsPath = path.resolve(buildSDKPath, '../'); @@ -73,7 +72,7 @@ export class FileManager { declFilesPath: module.declFilesPath ? toUnixPath(module.declFilesPath) : undefined, }; convertedMap.set(module.packageName, convertedModule); - }) + }); this.arkTSModuleMap = convertedMap; } @@ -101,7 +100,7 @@ export class FileManager { if (!path.startsWith(moduleInfo.modulePath)) { continue; } - if (moduleInfo.language != LANGUAGE_VERSION.ARKTS_HYBRID) { + if (moduleInfo.language !== LANGUAGE_VERSION.ARKTS_HYBRID) { return moduleInfo.language; } /** diff --git a/ets2panda/driver/build_system/src/plugins/plugins_driver.ts b/ets2panda/driver/build_system/src/plugins/plugins_driver.ts index eb556eb023..67203f601d 100644 --- a/ets2panda/driver/build_system/src/plugins/plugins_driver.ts +++ b/ets2panda/driver/build_system/src/plugins/plugins_driver.ts @@ -71,12 +71,14 @@ class PluginContext { private program: object | undefined; private projectConfig: object | undefined; private fileManager: FileManager | undefined; + private contextPtr: number | undefined; constructor() { this.ast = undefined; this.program = undefined; this.projectConfig = undefined; this.fileManager = undefined; + this.contextPtr = undefined; } public setArkTSAst(ast: object): void { @@ -96,15 +98,6 @@ class PluginContext { } public setProjectConfig(projectConfig: object): void { - if (this.projectConfig) { - const logData: LogData = LogDataFactory.newInstance( - ErrorCode.BUILDSYSTEM_PLUGIN_CONTEXT_RESET_PROJECT_CONFIG, - 'Trying to reset projectConfig in PluginContext, abort compiling.', - 'projectConfig in PluginContext can only be set once.' - ); - Logger.getInstance().printErrorAndExit(logData); - return; - } this.projectConfig = projectConfig; } @@ -112,16 +105,24 @@ class PluginContext { return this.projectConfig; } - public setFileManager(projectConfig: BuildConfig):void{ - if(!this.fileManager){ + public setFileManager(projectConfig: BuildConfig): void { + if (!this.fileManager) { FileManager.init(projectConfig); this.fileManager = FileManager.getInstance(); } } - public getFileManager():FileManager| undefined{ + public getFileManager(): FileManager | undefined{ return this.fileManager; } + + public setContextPtr(ptr: number): void { + this.contextPtr = ptr; + } + + public getContextPtr(): number | undefined { + return this.contextPtr; + } } export class PluginDriver { diff --git a/ets2panda/driver/build_system/src/types.ts b/ets2panda/driver/build_system/src/types.ts index 0d0d0d38ac..91255055f1 100644 --- a/ets2panda/driver/build_system/src/types.ts +++ b/ets2panda/driver/build_system/src/types.ts @@ -37,6 +37,10 @@ export interface ArkTSGlobal { }; es2panda: { _DestroyContext: Function; + _MemInitialize: Function; + _MemFinalize: Function; + _CreateGlobalContext: Function; + _DestroyGlobalContext: Function; } } @@ -54,6 +58,8 @@ export interface ArkTS { generateTsDeclarationsFromContext: Function; destroyConfig: Function; Es2pandaContextState: typeof Es2pandaContextState; + MemInitialize: Function; + CreateGlobalContext: Function; } export enum Es2pandaContextState { @@ -133,6 +139,7 @@ export interface DependentModuleConfig { export interface BuildConfig extends BuildBaseConfig, DeclgenConfig, LoggerConfig, ModuleConfig, PathConfig, FrameworkConfig { plugins: PluginsConfig; compileFiles: string[]; + entryFiles?: string[]; dependentModuleList: DependentModuleConfig[]; } // ProjectConfig ends @@ -178,4 +185,14 @@ export interface DependencyFileConfig { dependencies: { [filePath: string]: string[]; } -} \ No newline at end of file +} + +export interface JobInfo { + id: string; + isCompileAbc: boolean; + compileFileInfo: CompileFileInfo; + buildConfig: Object; + globalContextPtr?: KPointer; +} + +export type KPointer = number | bigint; \ No newline at end of file diff --git a/ets2panda/driver/build_system/test/demo_hap/entry/a.ets b/ets2panda/driver/build_system/test/demo_hap/entry/a.ets index 76a66d7bbf..03e10fb47a 100644 --- a/ets2panda/driver/build_system/test/demo_hap/entry/a.ets +++ b/ets2panda/driver/build_system/test/demo_hap/entry/a.ets @@ -13,7 +13,22 @@ * limitations under the License. */ + +import {str, strd} from './c' +import {strA} from 'harA' +import {strB} from 'harB' + function main() { let a: string = "hello world" console.log(a) + + console.log(strd); + + console.log(strA); + console.log(strB); + + console.log("end hello world a.ets") } + +let stra = "hello world from a" +export {stra} \ No newline at end of file diff --git a/ets2panda/driver/build_system/test/demo_hap/entry/c.ets b/ets2panda/driver/build_system/test/demo_hap/entry/c.ets index bfbc0dd50e..1fd443aa1f 100644 --- a/ets2panda/driver/build_system/test/demo_hap/entry/c.ets +++ b/ets2panda/driver/build_system/test/demo_hap/entry/c.ets @@ -13,7 +13,9 @@ * limitations under the License. */ -import {strd} from './d' +import {strd, strArr} from './d' + +let d: string[] = strArr; export let str: string = "hello world from c!"; export {strd} \ No newline at end of file diff --git a/ets2panda/driver/build_system/test/demo_hap/entry/d.ets b/ets2panda/driver/build_system/test/demo_hap/entry/d.ets index 0cd8a43084..a880df3c2a 100644 --- a/ets2panda/driver/build_system/test/demo_hap/entry/d.ets +++ b/ets2panda/driver/build_system/test/demo_hap/entry/d.ets @@ -13,4 +13,9 @@ * limitations under the License. */ -export let strd: string = "hello world from d!"; \ No newline at end of file +// import {foo} from './b'; + +// foo(); + +export let strd: string = "hello world from d!"; +export let strArr: string[] = ['1', '2']; \ No newline at end of file diff --git a/ets2panda/driver/dependency_analyzer/dep_analyzer.cpp b/ets2panda/driver/dependency_analyzer/dep_analyzer.cpp index 1ddb8ad777..1ea40a4e2b 100644 --- a/ets2panda/driver/dependency_analyzer/dep_analyzer.cpp +++ b/ets2panda/driver/dependency_analyzer/dep_analyzer.cpp @@ -146,6 +146,8 @@ int DepAnalyzer::AnalyzeDepsForMultiFiles(const char *exec, std::vector parsedFileList; const auto *impl = es2panda_GetImpl(ES2PANDA_LIB_VERSION); + impl->MemInitialize(); + for (auto &file : fileList) { if (parsedFileList.count(file) != 0U || fileDirectDependencies_.count(file) != 0U) { continue; @@ -173,8 +175,8 @@ int DepAnalyzer::AnalyzeDepsForMultiFiles(const char *exec, std::vectorProceedToState(ctx, ES2PANDA_STATE_PARSED); if (ctxImpl->state == ES2PANDA_STATE_ERROR) { - ctxImpl->checker->LogTypeError(std::string("Parse Failed: ").append(ctxImpl->errorMessage), - ctxImpl->errorPos); + ctxImpl->GetChecker()->LogTypeError(std::string("Parse Failed: ").append(ctxImpl->errorMessage), + ctxImpl->errorPos); impl->DestroyContext(ctx); impl->DestroyConfig(cfg); return 1; @@ -188,6 +190,8 @@ int DepAnalyzer::AnalyzeDepsForMultiFiles(const char *exec, std::vectorDestroyContext(ctx); impl->DestroyConfig(cfg); } + + impl->MemFinalize(); return 0; } @@ -230,6 +234,7 @@ std::optional ParseArguments(ark::Span args) int DepAnalyzer::AnalyzeDeps(int argc, const char **argv) { + // NOLINTBEGIN int minArgCount = 2; if (argc < minArgCount) { std::cerr << "No file has been entered for analysis" << std::endl; @@ -241,4 +246,5 @@ int DepAnalyzer::AnalyzeDeps(int argc, const char **argv) return 1; } return 0; + // NOLINTEND } diff --git a/ets2panda/es2panda.cpp b/ets2panda/es2panda.cpp index aadd815b18..b2b63e0635 100644 --- a/ets2panda/es2panda.cpp +++ b/ets2panda/es2panda.cpp @@ -87,7 +87,7 @@ pandasm::Program *Compiler::Compile(const SourceFile &input, const util::Options util::DiagnosticEngine &diagnosticEngine, uint32_t parseStatus) { public_lib::Context context; - ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + ThreadSafeArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); context.allocator = &allocator; context.compilingState = public_lib::CompilingState::SINGLE_COMPILING; @@ -105,7 +105,7 @@ unsigned int Compiler::CompileM(std::vector &inputs, util::Options & { public_lib::Context context; context.transitionMemory = - new public_lib::TransitionMemory(new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true)); + new public_lib::TransitionMemory(new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true)); context.allocator = context.transitionMemory->PermanentAllocator(); context.compilingState = public_lib::CompilingState::MULTI_COMPILING_INIT; @@ -138,6 +138,6 @@ void Compiler::DumpAsm(const pandasm::Program *prog) compiler::CompilerImpl::DumpAsm(prog); } -util::DiagnosticEngine *g_diagnosticEngine = nullptr; - +// When compiling multi thread, this is need by each thread indenpengdentlt +thread_local util::DiagnosticEngine *g_diagnosticEngine = nullptr; } // namespace ark::es2panda diff --git a/ets2panda/es2panda.h b/ets2panda/es2panda.h index 21c202e405..39cdbf9e1b 100644 --- a/ets2panda/es2panda.h +++ b/ets2panda/es2panda.h @@ -140,7 +140,7 @@ private: // g_diagnosticEngine used only for flush diagnostic before unexpected process termination: // - inside SIGSEGV handler -extern util::DiagnosticEngine *g_diagnosticEngine; +thread_local extern util::DiagnosticEngine *g_diagnosticEngine; } // namespace ark::es2panda #endif diff --git a/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp b/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp index e78fd348d3..e1101e2b00 100644 --- a/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp +++ b/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp @@ -68,7 +68,7 @@ ir::ClassDeclaration *ClassBuilder::Build(parser::Program *program) && classDecl->SetParent(programAst); // Here we assume that global statements of the passed `program` are not currently checked, so that // insertion is safe. - programAst->Statements().push_back(classDecl); + programAst->AddStatement(classDecl); return classDecl; } diff --git a/ets2panda/evaluate/scopedDebugInfoPlugin.cpp b/ets2panda/evaluate/scopedDebugInfoPlugin.cpp index fc8666dc9e..16b6396f9f 100644 --- a/ets2panda/evaluate/scopedDebugInfoPlugin.cpp +++ b/ets2panda/evaluate/scopedDebugInfoPlugin.cpp @@ -149,7 +149,7 @@ bool ScopedDebugInfoPlugin::InsertReturnStatement() // which will also modify method signature's return type. auto *evalMethodStatements = context_.methodStatements; - auto &statementsList = evalMethodStatements->Statements(); + auto &statementsList = evalMethodStatements->StatementsForUpdates(); // Omit the emplaced `DebuggerAPI.setLocal<>` calls and find the original last statement. auto lastStatementIter = std::find(statementsList.rbegin(), statementsList.rend(), lastStatement); ES2PANDA_ASSERT(lastStatementIter != statementsList.rend()); @@ -195,7 +195,7 @@ void ScopedDebugInfoPlugin::AddPrologueEpilogue(ir::BlockStatement *block) } // Prepend prologue. - auto &statements = block->Statements(); + auto &statements = block->StatementsForUpdates(); for (auto *stmt : iter->second.first) { statements.insert(statements.begin(), stmt); } diff --git a/ets2panda/ir/annotationAllowed.h b/ets2panda/ir/annotationAllowed.h index 0053c073dc..90eea9d954 100644 --- a/ets2panda/ir/annotationAllowed.h +++ b/ets2panda/ir/annotationAllowed.h @@ -19,6 +19,7 @@ #include "ir/astNode.h" #include "ir/statement.h" #include "ir/statements/annotationUsage.h" +#include "util/es2pandaMacros.h" namespace ark::es2panda::ir { @@ -31,24 +32,77 @@ public: NO_COPY_OPERATOR(AnnotationAllowed); NO_MOVE_SEMANTIC(AnnotationAllowed); - [[nodiscard]] ArenaVector &Annotations() noexcept + void EmplaceAnnotations(AnnotationUsage *source) { - return annotations_; + auto newNode = reinterpret_cast *>(this->GetOrCreateHistoryNode()); + newNode->annotations_.emplace_back(source); + } + + void ClearAnnotations() + { + auto newNode = reinterpret_cast *>(this->GetOrCreateHistoryNode()); + newNode->annotations_.clear(); + } + + void SetValueAnnotations(AnnotationUsage *source, size_t index) + { + auto newNode = reinterpret_cast *>(this->GetOrCreateHistoryNode()); + auto &arenaVector = newNode->annotations_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = source; + }; + + void TransformAnnotations(const NodeTransformer &cb, std::string_view const transformationName) + { + auto &annotations = Annotations(); + for (size_t ix = 0; ix < annotations.size(); ix++) { + if (auto *transformedNode = cb(annotations[ix]); annotations[ix] != transformedNode) { + annotations[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), ix); + } + } + } + + ArenaVector &AnnotationsForUpdate() + { + return AstNode::GetOrCreateHistoryNodeAs>()->annotations_; + } + + const ArenaVector &Annotations() + { + return AstNode::GetHistoryNodeAs>()->annotations_; } [[nodiscard]] const ArenaVector &Annotations() const noexcept { - return annotations_; + return AstNode::GetHistoryNodeAs>()->annotations_; } - void SetAnnotations(ArenaVector &&annotations) + void SetAnnotations(const ArenaVector &&annotationList) { - annotations_ = std::move(annotations); - for (ir::AnnotationUsage *anno : annotations_) { - anno->SetParent(this); + auto &annotations = AstNode::GetOrCreateHistoryNodeAs>()->annotations_; + annotations = ArenaVector {annotationList}; + + for (auto annotation : Annotations()) { + annotation->SetParent(this); + } + } + + void SetAnnotations(const ArenaVector &annotationList) + { + auto &annotations = AstNode::GetOrCreateHistoryNodeAs>()->annotations_; + annotations = annotationList; + + for (auto annotation : Annotations()) { + annotation->SetParent(this); } } + void AddAnnotations(AnnotationUsage *annotations) + { + AstNode::GetOrCreateHistoryNodeAs>()->annotations_.emplace_back(annotations); + } + protected: explicit AnnotationAllowed(Expression const &other, ArenaAllocator *allocator) : T(other), annotations_(allocator->Adapter()) @@ -82,11 +136,6 @@ protected: { } - void AddAnnotations(AnnotationUsage *const annotations) - { - annotations_.emplace_back(annotations); - } - AnnotationAllowed(AnnotationAllowed const &other) : T(static_cast(other)), annotations_(other.annotations_.get_allocator()) { diff --git a/ets2panda/ir/as/namedType.cpp b/ets2panda/ir/as/namedType.cpp index 7bf5f66ecb..48880e1589 100644 --- a/ets2panda/ir/as/namedType.cpp +++ b/ets2panda/ir/as/namedType.cpp @@ -45,12 +45,7 @@ void NamedType::TransformChildren(const NodeTransformer &cb, std::string_view co } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void NamedType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/astNode.cpp b/ets2panda/ir/astNode.cpp index 9d920eeac2..3b8a45b1bc 100644 --- a/ets2panda/ir/astNode.cpp +++ b/ets2panda/ir/astNode.cpp @@ -14,7 +14,9 @@ */ #include "astNode.h" +#include "compiler/lowering/phase.h" #include "ir/astDump.h" +#include "ir/astNodeHistory.h" #include "ir/srcDump.h" #include "ir/typed.h" @@ -22,50 +24,51 @@ namespace ark::es2panda::ir { AstNode::AstNode(AstNode const &other) { - range_ = other.range_; - type_ = other.type_; - if (other.variable_ != nullptr) { - variable_ = other.variable_; + auto otherHistoryNode = other.GetHistoryNode(); + range_ = otherHistoryNode->range_; + type_ = otherHistoryNode->type_; + if (otherHistoryNode->variable_ != nullptr) { + variable_ = otherHistoryNode->variable_; } - flags_ = other.flags_; - astNodeFlags_ = other.astNodeFlags_; + flags_ = otherHistoryNode->flags_; + astNodeFlags_ = otherHistoryNode->astNodeFlags_; // boxing_unboxing_flags_ {}; leave default value! } [[nodiscard]] bool AstNode::IsExported() const noexcept { if (UNLIKELY(IsClassDefinition())) { - return parent_->IsExported(); + return GetHistoryNode()->parent_->IsExported(); } - return (flags_ & ModifierFlags::EXPORT) != 0; + return (Modifiers() & ModifierFlags::EXPORT) != 0; } [[nodiscard]] bool AstNode::IsDefaultExported() const noexcept { if (UNLIKELY(IsClassDefinition())) { - return parent_->IsDefaultExported(); + return GetHistoryNode()->parent_->IsDefaultExported(); } - return (flags_ & ModifierFlags::DEFAULT_EXPORT) != 0; + return (Modifiers() & ModifierFlags::DEFAULT_EXPORT) != 0; } [[nodiscard]] bool AstNode::IsExportedType() const noexcept { if (UNLIKELY(IsClassDefinition())) { - return this->parent_->IsExportedType(); + return GetHistoryNode()->parent_->IsExportedType(); } - return (flags_ & ModifierFlags::EXPORT_TYPE) != 0; + return (Modifiers() & ModifierFlags::EXPORT_TYPE) != 0; } [[nodiscard]] bool AstNode::HasExportAlias() const noexcept { if (UNLIKELY(IsClassDefinition())) { - return parent_->HasExportAlias(); + return GetHistoryNode()->parent_->HasExportAlias(); } - return (astNodeFlags_ & AstNodeFlags::HAS_EXPORT_ALIAS) != 0; + return (GetHistoryNode()->astNodeFlags_ & AstNodeFlags::HAS_EXPORT_ALIAS) != 0; } bool AstNode::IsScopeBearer() const noexcept @@ -247,18 +250,28 @@ std::string AstNode::IsolatedDumpDecl() const void AstNode::SetOriginalNode(AstNode *originalNode) noexcept { - originalNode_ = originalNode; + if (OriginalNode() != originalNode) { + GetOrCreateHistoryNode()->originalNode_ = originalNode; + } } AstNode *AstNode::OriginalNode() const noexcept { - return originalNode_; + return GetHistoryNode()->originalNode_; +} + +const std::optional> &AstNode::TransformedNode() const noexcept +{ + return GetHistoryNode()->transformedNode_; } void AstNode::SetTransformedNode(std::string_view const transformationName, AstNode *transformedNode) { - transformedNode->SetOriginalNode(this); - transformedNode_ = std::make_optional(std::make_pair(transformationName, transformedNode)); + if (transformedNode != nullptr) { + transformedNode->SetOriginalNode(this); + GetOrCreateHistoryNode()->transformedNode_ = + std::make_optional(std::make_pair(transformationName, transformedNode)); + } } void AstNode::CleanUp() @@ -274,33 +287,33 @@ void AstNode::CleanUp() bool AstNode::IsReadonly() const noexcept { - return (flags_ & ModifierFlags::READONLY) != 0; + return (Modifiers() & ModifierFlags::READONLY) != 0; } // NOTE: For readonly parameter type bool AstNode::IsReadonlyType() const noexcept { - return (flags_ & ModifierFlags::READONLY_PARAMETER) != 0; + return (Modifiers() & ModifierFlags::READONLY_PARAMETER) != 0; } bool AstNode::IsOptionalDeclaration() const noexcept { - return (flags_ & ModifierFlags::OPTIONAL) != 0; + return (Modifiers() & ModifierFlags::OPTIONAL) != 0; } bool AstNode::IsDefinite() const noexcept { - return (flags_ & ModifierFlags::DEFINITE) != 0; + return (Modifiers() & ModifierFlags::DEFINITE) != 0; } bool AstNode::IsConstructor() const noexcept { - return (flags_ & ModifierFlags::CONSTRUCTOR) != 0; + return (Modifiers() & ModifierFlags::CONSTRUCTOR) != 0; } bool AstNode::IsOverride() const noexcept { - return (flags_ & ModifierFlags::OVERRIDE) != 0; + return (Modifiers() & ModifierFlags::OVERRIDE) != 0; } AstNode *AstNode::ShallowClone(ArenaAllocator *allocator) @@ -319,6 +332,7 @@ void AstNode::CopyTo(AstNode *other) const other->flags_ = flags_; other->astNodeFlags_ = astNodeFlags_; other->boxingUnboxingFlags_ = boxingUnboxingFlags_; + other->history_ = history_; other->variable_ = variable_; other->originalNode_ = originalNode_; other->transformedNode_ = transformedNode_; @@ -328,4 +342,80 @@ AstNode *AstNode::Construct([[maybe_unused]] ArenaAllocator *allocator) { ES2PANDA_UNREACHABLE(); } + +bool AstNode::IsValidInCurrentPhase() const +{ + if (!HistoryInitialized()) { + return true; + } + return compiler::GetPhaseManager()->CurrentPhaseId() >= GetFirstCreated(); +} + +compiler::PhaseId AstNode::GetFirstCreated() const +{ + return history_->FirstCreated(); +} + +AstNode *AstNode::GetHistoryNode() const +{ + AstNode *node = nullptr; + + if (HistoryInitialized()) { + node = history_->Get(compiler::GetPhaseManager()->CurrentPhaseId()); + } else { + node = const_cast(this); + } + + ES2PANDA_ASSERT(node != nullptr); + return node; +} + +AstNode *AstNode::GetOrCreateHistoryNode() const +{ + AstNode *node = nullptr; + + if (HistoryInitialized()) { + node = history_->At(compiler::GetPhaseManager()->CurrentPhaseId()); + if (node == nullptr) { + node = history_->Get(compiler::GetPhaseManager()->PreviousPhaseId()); + ES2PANDA_ASSERT(node != nullptr); + node = node->ShallowClone(compiler::GetPhaseManager()->Allocator()); + history_->Set(node, compiler::GetPhaseManager()->CurrentPhaseId()); + } + } else { + node = const_cast(this); + } + + return node; +} + +void AstNode::AddModifier(ModifierFlags const flags) noexcept +{ + if (!All(Modifiers(), flags)) { + GetOrCreateHistoryNode()->flags_ |= flags; + } +} + +void AstNode::ClearModifier(ModifierFlags const flags) noexcept +{ + if (Any(Modifiers(), flags)) { + GetOrCreateHistoryNode()->flags_ &= ~flags; + } +} + +void AstNode::InitHistory() +{ + if (!g_enableContextHistory || HistoryInitialized()) { + return; + } + + history_ = compiler::GetPhaseManager()->Allocator()->New( + this, compiler::GetPhaseManager()->CurrentPhaseId(), compiler::GetPhaseManager()->Allocator()); +} + +bool AstNode::HistoryInitialized() const +{ + return history_ != nullptr; +} + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/astNode.h b/ets2panda/ir/astNode.h index c8f07a0c75..5489ceb5f6 100644 --- a/ets2panda/ir/astNode.h +++ b/ets2panda/ir/astNode.h @@ -19,6 +19,7 @@ #include "es2panda.h" #include "astNodeFlags.h" #include "astNodeMapping.h" +#include "compiler/lowering/phase_id.h" #include "ir/visitor/AstVisitor.h" #include "lexer/token/sourceLocation.h" #include "util/es2pandaMacros.h" @@ -41,6 +42,20 @@ class Scope; } // namespace ark::es2panda::varbinder namespace ark::es2panda::ir { + +inline thread_local bool g_enableContextHistory; +// CC-OFFNXT(G.INC.10) +[[maybe_unused]] static void DisableContextHistory() +{ + g_enableContextHistory = false; +} + +// CC-OFFNXT(G.INC.10) +[[maybe_unused]] static void EnableContextHistory() +{ + g_enableContextHistory = true; +} + // NOLINTBEGIN(modernize-avoid-c-arrays) inline constexpr char const CLONE_ALLOCATION_ERROR[] = "Unsuccessful allocation during cloning."; // NOLINTEND(modernize-avoid-c-arrays) @@ -96,6 +111,7 @@ inline std::string_view ToString(AstNodeType nodeType) #undef STRING_FROM_NODE_TYPE // Forward declarations +class AstNodeHistory; class AstDumper; class Expression; class SrcDumper; @@ -127,31 +143,31 @@ public: bool IsProgram() const { - return parent_ == nullptr; + return GetHistoryNode()->parent_ == nullptr; } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DECLARE_IS_CHECKS(nodeType, className) \ - bool Is##className() const \ - { \ - /* CC-OFFNXT(G.PRE.02) name part*/ \ - /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ - return type_ == AstNodeType::nodeType; /* CC-OFF(G.PRE.02) name part*/ \ +#define DECLARE_IS_CHECKS(nodeType, className) \ + bool Is##className() const \ + { \ + /* CC-OFFNXT(G.PRE.02) name part*/ \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ + return GetHistoryNode()->type_ == AstNodeType::nodeType; /* CC-OFF(G.PRE.02) name part*/ \ } AST_NODE_MAPPING(DECLARE_IS_CHECKS) #undef DECLARE_IS_CHECKS // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DECLARE_IS_CHECKS(nodeType1, nodeType2, baseClass, reinterpretClass) \ - bool Is##baseClass() const \ - { \ - /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ - return type_ == AstNodeType::nodeType1; /* CC-OFF(G.PRE.02) name part*/ \ - } \ - bool Is##reinterpretClass() const \ - { \ - /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ - return type_ == AstNodeType::nodeType2; /* CC-OFF(G.PRE.02) name part*/ \ +#define DECLARE_IS_CHECKS(nodeType1, nodeType2, baseClass, reinterpretClass) \ + bool Is##baseClass() const \ + { \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ + return GetHistoryNode()->type_ == AstNodeType::nodeType1; /* CC-OFF(G.PRE.02) name part*/ \ + } \ + bool Is##reinterpretClass() const \ + { \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ + return GetHistoryNode()->type_ == AstNodeType::nodeType2; /* CC-OFF(G.PRE.02) name part*/ \ } AST_NODE_REINTERPRET_MAPPING(DECLARE_IS_CHECKS) #undef DECLARE_IS_CHECKS @@ -265,62 +281,72 @@ public: void SetRange(const lexer::SourceRange &loc) noexcept { - range_ = loc; + if (GetHistoryNode()->range_ != loc) { + GetOrCreateHistoryNode()->range_ = loc; + } } void SetStart(const lexer::SourcePosition &start) noexcept { - range_.start = start; + if (GetHistoryNode()->range_.start != start) { + GetOrCreateHistoryNode()->range_.start = start; + } } void SetEnd(const lexer::SourcePosition &end) noexcept { - range_.end = end; + if (GetHistoryNode()->range_.end != end) { + GetOrCreateHistoryNode()->range_.end = end; + } } [[nodiscard]] const lexer::SourcePosition &Start() const noexcept { - return range_.start; + return GetHistoryNode()->range_.start; } [[nodiscard]] const lexer::SourcePosition &End() const noexcept { - return range_.end; + return GetHistoryNode()->range_.end; } [[nodiscard]] const lexer::SourceRange &Range() const noexcept { - return range_; + return GetHistoryNode()->range_; } [[nodiscard]] AstNodeType Type() const noexcept { - return type_; + return GetHistoryNode()->type_; } [[nodiscard]] AstNode *Parent() noexcept { - return parent_; + return GetHistoryNode()->parent_; } [[nodiscard]] const AstNode *Parent() const noexcept { - return parent_; + return GetHistoryNode()->parent_; } void SetParent(AstNode *const parent) noexcept { - parent_ = parent; + if (GetHistoryNode()->parent_ != parent) { + GetOrCreateHistoryNode()->parent_ = parent; + } } [[nodiscard]] varbinder::Variable *Variable() const noexcept { - return variable_; + return GetHistoryNode()->variable_; } void SetVariable(varbinder::Variable *variable) noexcept { - variable_ = variable; + if (GetHistoryNode()->variable_ != variable) { + GetOrCreateHistoryNode()->variable_ = variable; + } } // When no decorators are allowed, we cannot return a reference to an empty vector. @@ -354,62 +380,62 @@ public: void SetOverride() noexcept { - flags_ |= ModifierFlags::OVERRIDE; + AddModifier(ModifierFlags::OVERRIDE); } [[nodiscard]] bool IsAsync() const noexcept { - return (flags_ & ModifierFlags::ASYNC) != 0; + return (Modifiers() & ModifierFlags::ASYNC) != 0; } [[nodiscard]] bool IsSynchronized() const noexcept { - return (flags_ & ModifierFlags::SYNCHRONIZED) != 0; + return (Modifiers() & ModifierFlags::SYNCHRONIZED) != 0; } [[nodiscard]] bool IsNative() const noexcept { - return (flags_ & ModifierFlags::NATIVE) != 0; + return (Modifiers() & ModifierFlags::NATIVE) != 0; } [[nodiscard]] bool IsConst() const noexcept { - return (flags_ & ModifierFlags::CONST) != 0; + return (Modifiers() & ModifierFlags::CONST) != 0; } [[nodiscard]] bool IsStatic() const noexcept { - return (flags_ & ModifierFlags::STATIC) != 0; + return (Modifiers() & ModifierFlags::STATIC) != 0; } [[nodiscard]] bool IsFinal() const noexcept { - return (flags_ & ModifierFlags::FINAL) != 0U; + return (Modifiers() & ModifierFlags::FINAL) != 0U; } [[nodiscard]] bool IsAbstract() const noexcept { - return (flags_ & ModifierFlags::ABSTRACT) != 0; + return (Modifiers() & ModifierFlags::ABSTRACT) != 0; } [[nodiscard]] bool IsPublic() const noexcept { - return (flags_ & ModifierFlags::PUBLIC) != 0; + return (Modifiers() & ModifierFlags::PUBLIC) != 0; } [[nodiscard]] bool IsProtected() const noexcept { - return (flags_ & ModifierFlags::PROTECTED) != 0; + return (Modifiers() & ModifierFlags::PROTECTED) != 0; } [[nodiscard]] bool IsPrivate() const noexcept { - return (flags_ & ModifierFlags::PRIVATE) != 0; + return (Modifiers() & ModifierFlags::PRIVATE) != 0; } [[nodiscard]] bool IsInternal() const noexcept { - return (flags_ & ModifierFlags::INTERNAL) != 0; + return (Modifiers() & ModifierFlags::INTERNAL) != 0; } [[nodiscard]] bool IsExported() const noexcept; @@ -420,42 +446,36 @@ public: [[nodiscard]] bool IsDeclare() const noexcept { - return (flags_ & ModifierFlags::DECLARE) != 0; + return (Modifiers() & ModifierFlags::DECLARE) != 0; } [[nodiscard]] bool IsIn() const noexcept { - return (flags_ & ModifierFlags::IN) != 0; + return (Modifiers() & ModifierFlags::IN) != 0; } [[nodiscard]] bool IsOut() const noexcept { - return (flags_ & ModifierFlags::OUT) != 0; + return (Modifiers() & ModifierFlags::OUT) != 0; } [[nodiscard]] bool IsSetter() const noexcept { - return (flags_ & ModifierFlags::SETTER) != 0; + return (Modifiers() & ModifierFlags::SETTER) != 0; } - void AddModifier(ModifierFlags const flags) noexcept - { - flags_ |= flags; - } + void AddModifier(ModifierFlags const flags) noexcept; - void ClearModifier(ModifierFlags const flags) noexcept - { - flags_ &= ~flags; - } + void ClearModifier(ModifierFlags const flags) noexcept; [[nodiscard]] ModifierFlags Modifiers() noexcept { - return flags_; + return GetHistoryNode()->flags_; } [[nodiscard]] ModifierFlags Modifiers() const noexcept { - return flags_; + return GetHistoryNode()->flags_; } [[nodiscard]] bool HasExportAlias() const noexcept; @@ -464,28 +484,34 @@ public: #define DECLARE_FLAG_OPERATIONS(flag_type, member_name) \ void Set##flag_type(flag_type flags) const noexcept \ { \ - (member_name) = flags; \ + if (GetHistoryNode()->member_name != flags) { \ + GetOrCreateHistoryNode()->member_name = flags; \ + } \ } \ \ void Add##flag_type(flag_type flag) const noexcept \ { \ - (member_name) |= flag; \ + if (!All(GetHistoryNode()->member_name, flag)) { \ + GetOrCreateHistoryNode()->member_name |= flag; \ + } \ } \ \ [[nodiscard]] flag_type Get##flag_type() const noexcept \ { \ /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ - return (member_name); \ + return GetHistoryNode()->member_name; \ } \ \ bool Has##flag_type(flag_type flag) const noexcept \ { \ /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ - return ((member_name)&flag) != 0U; \ + return (GetHistoryNode()->member_name & flag) != 0U; \ } \ void Remove##flag_type(flag_type flag) const noexcept \ { \ - (member_name) &= ~flag; \ + if (Any(GetHistoryNode()->member_name, flag)) { \ + GetOrCreateHistoryNode()->member_name &= ~flag; \ + } \ } DECLARE_FLAG_OPERATIONS(BoxingUnboxingFlags, boxingUnboxingFlags_); @@ -552,6 +578,11 @@ public: AstNode *ShallowClone(ArenaAllocator *allocator); + bool IsValidInCurrentPhase() const; + + AstNode *GetHistoryNode() const; + AstNode *GetOrCreateHistoryNode() const; + protected: AstNode(AstNode const &other); @@ -561,7 +592,24 @@ protected: void SetType(AstNodeType const type) noexcept { - type_ = type; + if (Type() != type) { + GetOrCreateHistoryNode()->type_ = type; + } + } + + void InitHistory(); + bool HistoryInitialized() const; + + template + T *GetHistoryNodeAs() const + { + return reinterpret_cast(GetHistoryNode()); + } + + template + T *GetOrCreateHistoryNodeAs() const + { + return reinterpret_cast(GetOrCreateHistoryNode()); } friend class SizeOfNodeTest; @@ -572,11 +620,15 @@ protected: ModifierFlags flags_ {}; mutable AstNodeFlags astNodeFlags_ {}; mutable BoxingUnboxingFlags boxingUnboxingFlags_ {}; + AstNodeHistory *history_ {nullptr}; // NOLINTEND(misc-non-private-member-variables-in-classes) private: + compiler::PhaseId GetFirstCreated() const; AstNode &operator=(const AstNode &) = default; + const std::optional> &TransformedNode() const noexcept; + varbinder::Variable *variable_ {}; AstNode *originalNode_ = nullptr; // {lowering_phase_name, new_generated_node} @@ -594,12 +646,14 @@ public: [[nodiscard]] TypeNode *TypeAnnotation() const noexcept { - return typeAnnotation_; + return AstNode::GetHistoryNodeAs>()->typeAnnotation_; } void SetTsTypeAnnotation(TypeNode *const typeAnnotation) noexcept { - typeAnnotation_ = typeAnnotation; + if (TypeAnnotation() != typeAnnotation) { + AstNode::GetOrCreateHistoryNodeAs>()->typeAnnotation_ = typeAnnotation; + } } void CopyTo(AstNode *other) const override diff --git a/ets2panda/ir/astNodeFlags.h b/ets2panda/ir/astNodeFlags.h index 110cd9fcb8..617e3e42f8 100644 --- a/ets2panda/ir/astNodeFlags.h +++ b/ets2panda/ir/astNodeFlags.h @@ -105,6 +105,8 @@ enum class ScriptFunctionFlags : uint32_t { ASYNC_IMPL = 1U << 19U, EXTERNAL_OVERLOAD = 1U << 20U, HAS_THROW = 1U << 21U, + IN_RECORD = 1U << 22U, + TRAILING_LAMBDA = 1U << 23U, }; enum class TSOperatorType { READONLY, KEYOF, UNIQUE }; diff --git a/ets2panda/ir/astNodeHistory.cpp b/ets2panda/ir/astNodeHistory.cpp index c27d68e8d2..5d46aea8b2 100644 --- a/ets2panda/ir/astNodeHistory.cpp +++ b/ets2panda/ir/astNodeHistory.cpp @@ -18,12 +18,12 @@ namespace ark::es2panda::ir { -AstNodeHistory::AstNodeHistory(AstNode *node, int32_t phaseId, ArenaAllocator *allocator) : list_ {allocator} +AstNodeHistory::AstNodeHistory(AstNode *node, compiler::PhaseId phaseId, ArenaAllocator *allocator) : list_ {allocator} { Set(node, phaseId); } -AstNode *AstNodeHistory::FindBackwardEquals(int32_t phaseId) +AstNode *AstNodeHistory::FindBackwardEquals(compiler::PhaseId phaseId) { auto item = item_; @@ -37,7 +37,7 @@ AstNode *AstNodeHistory::FindBackwardEquals(int32_t phaseId) return nullptr; } -AstNode *AstNodeHistory::FindForwardEquals(int32_t phaseId) +AstNode *AstNodeHistory::FindForwardEquals(compiler::PhaseId phaseId) { auto item = item_; @@ -53,8 +53,9 @@ AstNode *AstNodeHistory::FindForwardEquals(int32_t phaseId) // Find node state precisely at phase with a given ID // (e.g. find the node history record with `phaseId` equal to a given value) -AstNode *AstNodeHistory::At(int32_t phaseId) +AstNode *AstNodeHistory::At(compiler::PhaseId phaseId) { + std::lock_guard lock(itemMutex_); if (LIKELY(item_->data.phaseId == phaseId)) { // Start searching with last accessed item // In most cases last accessed item is the one we are looking for @@ -70,8 +71,9 @@ AstNode *AstNodeHistory::At(int32_t phaseId) // Find node state at phase with a given ID // (e.g. find last node history record with `phaseId` less or equal to a given value) -AstNode *AstNodeHistory::Get(int32_t phaseId) +AstNode *AstNodeHistory::Get(compiler::PhaseId phaseId) { + std::lock_guard lock(itemMutex_); auto found = FindLessOrEquals(phaseId); if (LIKELY(found != nullptr)) { item_ = found; @@ -82,8 +84,9 @@ AstNode *AstNodeHistory::Get(int32_t phaseId) } // Find node state at phase with a given ID and set its new value, insert new history record if not found -void AstNodeHistory::Set(AstNode *node, int32_t phaseId) +void AstNodeHistory::Set(AstNode *node, compiler::PhaseId phaseId) { + std::lock_guard lock(itemMutex_); HistoryRecord record {node, phaseId}; if (LIKELY(list_.Empty() || list_.Tail()->data.phaseId < phaseId)) { item_ = list_.Append(record); @@ -105,7 +108,7 @@ void AstNodeHistory::Set(AstNode *node, int32_t phaseId) // Find node state at phase with a given ID // (e.g. find last node history record with `phaseId` less or equal to a given value) -AstNodeHistory::HistoryList::Item *AstNodeHistory::FindLessOrEquals(int32_t phaseId) +AstNodeHistory::HistoryList::Item *AstNodeHistory::FindLessOrEquals(compiler::PhaseId phaseId) { // Start searching with last accessed item auto item = item_; @@ -136,6 +139,10 @@ AstNodeHistory::HistoryList::Item *AstNodeHistory::FindLessOrEquals(int32_t phas if (item->data.phaseId <= phaseId) { return item; } + if (item->data.phaseId > phaseId && item->prev != nullptr) { + item = item->prev; + return item; + } } return nullptr; diff --git a/ets2panda/ir/astNodeHistory.h b/ets2panda/ir/astNodeHistory.h index 8aebde4a7a..e424046403 100644 --- a/ets2panda/ir/astNodeHistory.h +++ b/ets2panda/ir/astNodeHistory.h @@ -16,33 +16,41 @@ #ifndef ES2PANDA_IR_AST_NODE_HISTORY_H #define ES2PANDA_IR_AST_NODE_HISTORY_H +#include + #include "ir/astNode.h" +#include "compiler/lowering/phase_id.h" #include "util/doubleLinkedList.h" namespace ark::es2panda::ir { class AstNodeHistory { public: - AstNodeHistory(AstNode *node, int32_t phaseId, ArenaAllocator *allocator); + AstNodeHistory(AstNode *node, compiler::PhaseId phaseId, ArenaAllocator *allocator); - AstNode *At(int32_t phaseId); - AstNode *Get(int32_t phaseId); - void Set(AstNode *node, int32_t phaseId); + AstNode *At(compiler::PhaseId phaseId); + AstNode *Get(compiler::PhaseId phaseId); + void Set(AstNode *node, compiler::PhaseId phaseId); + compiler::PhaseId FirstCreated() + { + return list_.Head()->data.phaseId; + } private: struct HistoryRecord { AstNode *node; - int32_t phaseId; + compiler::PhaseId phaseId; }; using HistoryList = util::ArenaDoubleLinkedList; - AstNode *FindBackwardEquals(int32_t phaseId); - AstNode *FindForwardEquals(int32_t phaseId); - HistoryList::Item *FindLessOrEquals(int32_t phaseId); + AstNode *FindBackwardEquals(compiler::PhaseId phaseId); + AstNode *FindForwardEquals(compiler::PhaseId phaseId); + HistoryList::Item *FindLessOrEquals(compiler::PhaseId phaseId); HistoryList list_; // Node history list HistoryList::Item *item_ {nullptr}; // Last accessed history record + std::mutex itemMutex_ {}; }; } // namespace ark::es2panda::ir #endif diff --git a/ets2panda/ir/base/classDefinition.cpp b/ets2panda/ir/base/classDefinition.cpp index 2c88bf449e..5fe57979b3 100644 --- a/ets2panda/ir/base/classDefinition.cpp +++ b/ets2panda/ir/base/classDefinition.cpp @@ -28,28 +28,142 @@ #include "ir/ts/tsClassImplements.h" namespace ark::es2panda::ir { + +void ClassDefinition::SetCtor(MethodDefinition *ctor) +{ + this->GetOrCreateHistoryNodeAs()->ctor_ = ctor; +} + +void ClassDefinition::SetTypeParams(TSTypeParameterDeclaration *typeParams) +{ + this->GetOrCreateHistoryNodeAs()->typeParams_ = typeParams; +} + +void ClassDefinition::SetOrigEnumDecl(TSEnumDeclaration *origEnumDecl) +{ + this->GetOrCreateHistoryNodeAs()->origEnumDecl_ = origEnumDecl; +} + +void ClassDefinition::SetAnonClass(ClassDeclaration *anonClass) +{ + this->GetOrCreateHistoryNodeAs()->anonClass_ = anonClass; +} + +void ClassDefinition::SetSuperClass(Expression *superClass) +{ + this->GetOrCreateHistoryNodeAs()->superClass_ = superClass; +} + +void ClassDefinition::SetSuperTypeParams(TSTypeParameterInstantiation *superTypeParams) +{ + this->GetOrCreateHistoryNodeAs()->superTypeParams_ = superTypeParams; +} + +void ClassDefinition::SetScope(varbinder::LocalScope *scope) +{ + this->GetOrCreateHistoryNodeAs()->scope_ = scope; +} + +void ClassDefinition::SetModifiers(ClassDefinitionModifiers modifiers) +{ + this->GetOrCreateHistoryNodeAs()->modifiers_ = modifiers; +} + +void ClassDefinition::SetInternalName(util::StringView internalName) +{ + this->GetOrCreateHistoryNodeAs()->internalName_ = internalName; +} + +void ClassDefinition::EmplaceBody(AstNode *body) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->body_.emplace_back(body); +} + +void ClassDefinition::ClearBody() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->body_.clear(); +} + +void ClassDefinition::SetValueBody(AstNode *body, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->body_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = body; +} + +[[nodiscard]] const ArenaVector &ClassDefinition::Body() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->body_; +} + +[[nodiscard]] ArenaVector &ClassDefinition::BodyForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->body_; +} + +void ClassDefinition::EmplaceImplements(TSClassImplements *implements) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->implements_.emplace_back(implements); +} + +void ClassDefinition::ClearImplements() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->implements_.clear(); +} + +void ClassDefinition::SetValueImplements(TSClassImplements *implements, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->implements_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = implements; +} + +[[nodiscard]] const ArenaVector &ClassDefinition::Implements() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->implements_; +} + +[[nodiscard]] ArenaVector &ClassDefinition::ImplementsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->implements_; +} + const FunctionExpression *ClassDefinition::Ctor() const { - return ctor_ != nullptr ? ctor_->Value()->AsFunctionExpression() : nullptr; + auto const newNode = GetHistoryNode()->AsClassDefinition(); + return newNode->ctor_ != nullptr ? newNode->ctor_->Value()->AsFunctionExpression() : nullptr; } bool ClassDefinition::HasPrivateMethod() const { - return std::any_of(body_.cbegin(), body_.cend(), [](auto *element) { + auto const body = Body(); + return std::any_of(body.cbegin(), body.cend(), [](auto const *element) { return element->IsMethodDefinition() && element->AsClassElement()->IsPrivateElement(); }); } bool ClassDefinition::HasNativeMethod() const { - return std::any_of(body_.cbegin(), body_.cend(), [](auto *element) { + auto const body = Body(); + return std::any_of(body.cbegin(), body.cend(), [](auto const *element) { return element->IsMethodDefinition() && element->AsMethodDefinition()->IsNative(); }); } bool ClassDefinition::HasComputedInstanceField() const { - return std::any_of(body_.cbegin(), body_.cend(), [](auto *element) { + auto const body = Body(); + return std::any_of(body.cbegin(), body.cend(), [](auto *element) { return element->IsClassProperty() && element->AsClassElement()->IsComputed() && !(element->AsClassElement()->Modifiers() & ir::ModifierFlags::STATIC); }); @@ -57,115 +171,131 @@ bool ClassDefinition::HasComputedInstanceField() const bool ClassDefinition::HasMatchingPrivateKey(const util::StringView &name) const { - return std::any_of(body_.cbegin(), body_.cend(), [&name](auto *element) { + auto const body = Body(); + return std::any_of(body.cbegin(), body.cend(), [&name](auto *element) { return element->AsClassElement()->IsPrivateElement() && element->AsClassElement()->Id()->Name() == name; }); } -void ClassDefinition::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) +void ClassDefinition::TransformBase(const NodeTransformer &cb, std::string_view transformationName) { - if (ident_ != nullptr) { - if (auto *transformedNode = cb(ident_); ident_ != transformedNode) { - ident_->SetTransformedNode(transformationName, transformedNode); - ident_ = transformedNode->AsIdentifier(); + auto const ident = Ident(); + if (ident != nullptr) { + if (auto *transformedNode = cb(ident); ident != transformedNode) { + ident->SetTransformedNode(transformationName, transformedNode); + SetIdent(transformedNode->AsIdentifier()); } } - if (typeParams_ != nullptr) { - if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) { - typeParams_->SetTransformedNode(transformationName, transformedNode); - typeParams_ = transformedNode->AsTSTypeParameterDeclaration(); + auto const typeParam = TypeParams(); + if (typeParam != nullptr) { + if (auto *transformedNode = cb(typeParam); typeParam != transformedNode) { + typeParam->SetTransformedNode(transformationName, transformedNode); + SetTypeParams(transformedNode->AsTSTypeParameterDeclaration()); } } - if (superClass_ != nullptr) { - if (auto *transformedNode = cb(superClass_); superClass_ != transformedNode) { - superClass_->SetTransformedNode(transformationName, transformedNode); - superClass_ = transformedNode->AsExpression(); + auto const superClass = SuperClass(); + if (superClass != nullptr) { + if (auto *transformedNode = cb(superClass); superClass != transformedNode) { + superClass->SetTransformedNode(transformationName, transformedNode); + SetSuperClass(transformedNode->AsExpression()); } } - if (superTypeParams_ != nullptr) { - if (auto *transformedNode = cb(superTypeParams_); superTypeParams_ != transformedNode) { - superTypeParams_->SetTransformedNode(transformationName, transformedNode); - superTypeParams_ = transformedNode->AsTSTypeParameterInstantiation(); + auto const superTypeParam = SuperTypeParams(); + if (superTypeParam != nullptr) { + if (auto *transformedNode = cb(superTypeParam); superTypeParam != transformedNode) { + superTypeParam->SetTransformedNode(transformationName, transformedNode); + SetSuperTypeParams(transformedNode->AsTSTypeParameterInstantiation()); } } +} - for (auto *&it : VectorIterationGuard(implements_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsTSClassImplements(); - } - } +void ClassDefinition::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) +{ + TransformBase(cb, transformationName); - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + auto const &implement = Implements(); + for (size_t ix = 0; ix < implement.size(); ix++) { + if (auto *transformedNode = cb(implement[ix]); implement[ix] != transformedNode) { + implement[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueImplements(transformedNode->AsTSClassImplements(), ix); } } - if (ctor_ != nullptr) { - if (auto *transformedNode = cb(ctor_); ctor_ != transformedNode) { - ctor_->SetTransformedNode(transformationName, transformedNode); - ctor_ = transformedNode->AsMethodDefinition(); + TransformAnnotations(cb, transformationName); + + auto const &ctor = Ctor(); + if (ctor != nullptr) { + if (auto *transformedNode = cb(ctor); ctor != transformedNode) { + ctor->SetTransformedNode(transformationName, transformedNode); + SetCtor(transformedNode->AsMethodDefinition()); } } // Survives adding new elements to the end // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < body_.size(); ix++) { - if (auto *transformedNode = cb(body_[ix]); body_[ix] != transformedNode) { - body_[ix]->SetTransformedNode(transformationName, transformedNode); - body_[ix] = transformedNode; + auto const &body = Body(); + for (size_t ix = 0; ix < body.size(); ix++) { + if (auto *transformedNode = cb(body[ix]); body[ix] != transformedNode) { + body[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueBody(transformedNode, ix); } } } void ClassDefinition::Iterate(const NodeTraverser &cb) const { - if (ident_ != nullptr) { - cb(ident_); + auto const ident = GetHistoryNodeAs()->ident_; + if (ident != nullptr) { + cb(ident); } - if (typeParams_ != nullptr) { - cb(typeParams_); + auto const typeParams = GetHistoryNodeAs()->typeParams_; + if (typeParams != nullptr) { + cb(typeParams); } - if (superClass_ != nullptr) { - cb(superClass_); + auto const superClass = GetHistoryNodeAs()->superClass_; + if (superClass != nullptr) { + cb(superClass); } - if (superTypeParams_ != nullptr) { - cb(superTypeParams_); + auto const superTypeParams = GetHistoryNodeAs()->superTypeParams_; + if (superTypeParams != nullptr) { + cb(superTypeParams); } // Survives adding new elements to the end // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < implements_.size(); ix++) { - cb(implements_[ix]); + auto const &implements = GetHistoryNodeAs()->implements_; + for (auto implement : implements) { + cb(implement); } for (auto *it : VectorIterationGuard(Annotations())) { cb(it); } - if (ctor_ != nullptr) { - cb(ctor_); + auto const ctor = GetHistoryNodeAs()->ctor_; + if (ctor != nullptr) { + cb(ctor); } + auto const &body = GetHistoryNodeAs()->body_; // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < body_.size(); ix++) { - cb(body_[ix]); + for (size_t ix = 0; ix < body.size(); ix++) { + cb(body[ix]); } } void ClassDefinition::SetIdent(ir::Identifier *ident) noexcept { - ident_ = ident; - if (ident_ != nullptr) { - ident_->SetParent(this); + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->ident_ = ident; + if (ident != nullptr) { + ident->SetParent(this); } } @@ -174,26 +304,27 @@ void ClassDefinition::Dump(ir::AstDumper *dumper) const auto propFilter = [](AstNode *prop) -> bool { return !prop->IsClassStaticBlock() || !prop->AsClassStaticBlock()->Function()->IsHidden(); }; - dumper->Add({{"id", AstDumper::Nullish(ident_)}, - {"typeParameters", AstDumper::Optional(typeParams_)}, - {"superClass", AstDumper::Nullish(superClass_)}, - {"superTypeParameters", AstDumper::Optional(superTypeParams_)}, - {"implements", implements_}, + auto ctor = GetHistoryNodeAs()->ctor_; + dumper->Add({{"id", AstDumper::Nullish(Ident())}, + {"typeParameters", AstDumper::Optional(TypeParams())}, + {"superClass", AstDumper::Nullish(SuperClass())}, + {"superTypeParameters", AstDumper::Optional(SuperTypeParams())}, + {"implements", Implements()}, {"annotations", AstDumper::Optional(Annotations())}, - {"constructor", AstDumper::Optional(ctor_)}, - {"body", body_, propFilter}}); + {"constructor", AstDumper::Optional(ctor)}, + {"body", Body(), propFilter}}); } void ClassDefinition::DumpGlobalClass(ir::SrcDumper *dumper) const { ES2PANDA_ASSERT(IsGlobal()); - for (auto elem : body_) { + for (auto elem : Body()) { if (elem->IsClassProperty()) { elem->Dump(dumper); dumper->Endl(); } } - for (auto elem : body_) { + for (auto elem : Body()) { if (elem->IsMethodDefinition()) { elem->Dump(dumper); dumper->Endl(); @@ -204,13 +335,14 @@ void ClassDefinition::DumpGlobalClass(ir::SrcDumper *dumper) const // This method is needed by OHOS CI code checker void ClassDefinition::DumpBody(ir::SrcDumper *dumper) const { + auto const body = Body(); dumper->Add(" {"); - if (!body_.empty()) { + if (!body.empty()) { dumper->IncrIndent(); dumper->Endl(); - for (auto elem : body_) { + for (auto elem : body) { elem->Dump(dumper); - if (elem == body_.back()) { + if (elem == body.back()) { dumper->DecrIndent(); } dumper->Endl(); @@ -270,7 +402,8 @@ bool ClassDefinition::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const void ClassDefinition::Dump(ir::SrcDumper *dumper) const { // NOTE: plugin API fails - if ((ident_->Name().StartsWith("$dynmodule")) || (ident_->Name().StartsWith("$jscall"))) { + auto const ident = Ident(); + if ((ident->Name().StartsWith("$dynmodule")) || (ident->Name().StartsWith("$jscall"))) { return; } @@ -292,19 +425,20 @@ void ClassDefinition::Dump(ir::SrcDumper *dumper) const DumpPrefix(dumper); ident_->Dump(dumper); - if (typeParams_ != nullptr) { + if (TypeParams() != nullptr) { dumper->Add("<"); - typeParams_->Dump(dumper); + TypeParams()->Dump(dumper); dumper->Add("> "); } - if (superClass_ != nullptr) { + if (SuperClass() != nullptr) { dumper->Add(" extends "); - superClass_->Dump(dumper); + SuperClass()->Dump(dumper); } - DumpItems(dumper, " implements ", implements_); - if (!IsDeclare() || !body_.empty()) { + DumpItems(dumper, " implements ", Implements()); + + if (!IsDeclare() || !Body().empty()) { DumpBody(dumper); } if (IsLocal()) { @@ -337,7 +471,7 @@ ClassDefinition *ClassDefinition::Construct(ArenaAllocator *allocator) { ArenaVector body {allocator->Adapter()}; return allocator->New(allocator, nullptr, std::move(body), ClassDefinitionModifiers::NONE, - ModifierFlags::NONE, Language::Id::COUNT); + ModifierFlags::NONE, Language::Id::COUNT, history_); } void ClassDefinition::CopyTo(AstNode *other) const @@ -367,6 +501,6 @@ void ClassDefinition::CopyTo(AstNode *other) const JsDocAllowed>::CopyTo(other); } -int ClassDefinition::classCounter_ = 0; +std::atomic ClassDefinition::classCounter_ = 0; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/base/classDefinition.h b/ets2panda/ir/base/classDefinition.h index 2eb349f8cc..7a8c0ed2ef 100644 --- a/ets2panda/ir/base/classDefinition.h +++ b/ets2panda/ir/base/classDefinition.h @@ -21,6 +21,7 @@ #include "ir/srcDump.h" #include "ir/annotationAllowed.h" #include "ir/astNode.h" +#include "ir/astNodeHistory.h" #include "ir/expressions/identifier.h" #include "ir/jsDocAllowed.h" #include "ir/statements/annotationUsage.h" @@ -101,6 +102,7 @@ public: localPrefix_("$" + std::to_string(localIndex_)), exportedClasses_(body_.get_allocator()) { + InitHistory(); } // CC-OFFNXT(G.FUN.01-CPP) solid logic explicit ClassDefinition(ArenaAllocator *allocator, Identifier *ident, ArenaVector &&body, @@ -117,6 +119,7 @@ public: localPrefix_("$" + std::to_string(localIndex_)), exportedClasses_(body_.get_allocator()) { + InitHistory(); } explicit ClassDefinition(ArenaAllocator *allocator, Identifier *ident, ClassDefinitionModifiers modifiers, @@ -133,116 +136,130 @@ public: localPrefix_("$" + std::to_string(localIndex_)), exportedClasses_(body_.get_allocator()) { + InitHistory(); } - [[nodiscard]] bool IsScopeBearer() const noexcept override + // CC-OFFNXT(G.FUN.01-CPP) solid logic + explicit ClassDefinition(ArenaAllocator *allocator, Identifier *ident, ArenaVector &&body, + ClassDefinitionModifiers modifiers, ModifierFlags flags, Language lang, + AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::CLASS_DEFINITION, flags, allocator), + ident_(ident), + implements_(allocator->Adapter()), + body_(std::move(body)), + modifiers_(modifiers), + lang_(lang), + capturedVars_(allocator->Adapter()), + localVariableIsNeeded_(allocator->Adapter()), + localIndex_(classCounter_++), + localPrefix_("$" + std::to_string(localIndex_)), + exportedClasses_(body_.get_allocator()) { - return true; + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } - [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override + [[nodiscard]] bool IsScopeBearer() const noexcept override { - return scope_; + return true; } - void SetScope(varbinder::LocalScope *scope) + [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - ES2PANDA_ASSERT(scope_ == nullptr); - scope_ = scope; + return GetHistoryNodeAs()->scope_; } void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } [[nodiscard]] const Identifier *Ident() const noexcept { - return ident_; + return GetHistoryNodeAs()->ident_; } [[nodiscard]] Identifier *Ident() noexcept { - return ident_; + return GetHistoryNodeAs()->ident_; } void SetIdent(ir::Identifier *ident) noexcept; [[nodiscard]] const util::StringView &InternalName() const noexcept { - return internalName_; - } - - void SetInternalName(util::StringView internalName) noexcept - { - internalName_ = internalName; + return GetHistoryNodeAs()->internalName_; } [[nodiscard]] Expression *Super() noexcept { - return superClass_; + return GetHistoryNodeAs()->superClass_; } [[nodiscard]] const Expression *Super() const noexcept { - return superClass_; + return GetHistoryNodeAs()->superClass_; } void SetSuper(Expression *superClass) { - superClass_ = superClass; - if (superClass_ != nullptr) { - superClass_->SetParent(this); + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->superClass_ = superClass; + if (newNode->superClass_ != nullptr) { + newNode->superClass_->SetParent(this); } } [[nodiscard]] bool IsGlobal() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::GLOBAL) != 0; + return (Modifiers() & ClassDefinitionModifiers::GLOBAL) != 0; } [[nodiscard]] bool IsLocal() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::LOCAL) != 0; + return (Modifiers() & ClassDefinitionModifiers::LOCAL) != 0; } [[nodiscard]] bool IsExtern() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::EXTERN) != 0; + return (Modifiers() & ClassDefinitionModifiers::EXTERN) != 0; } [[nodiscard]] bool IsFromExternal() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::FROM_EXTERNAL) != 0; + return (Modifiers() & ClassDefinitionModifiers::FROM_EXTERNAL) != 0; } [[nodiscard]] bool IsInner() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::INNER) != 0; + return (Modifiers() & ClassDefinitionModifiers::INNER) != 0; } [[nodiscard]] bool IsGlobalInitialized() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::GLOBAL_INITIALIZED) != 0; + return (Modifiers() & ClassDefinitionModifiers::GLOBAL_INITIALIZED) != 0; } [[nodiscard]] bool IsClassDefinitionChecked() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::CLASSDEFINITION_CHECKED) != 0; + return (Modifiers() & ClassDefinitionModifiers::CLASSDEFINITION_CHECKED) != 0; } [[nodiscard]] bool IsAnonymous() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::ANONYMOUS) != 0; + return (Modifiers() & ClassDefinitionModifiers::ANONYMOUS) != 0; } [[nodiscard]] bool IsIntEnumTransformed() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::INT_ENUM_TRANSFORMED) != 0; + return (Modifiers() & ClassDefinitionModifiers::INT_ENUM_TRANSFORMED) != 0; } [[nodiscard]] bool IsStringEnumTransformed() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::STRING_ENUM_TRANSFORMED) != 0; + return (Modifiers() & ClassDefinitionModifiers::STRING_ENUM_TRANSFORMED) != 0; } [[nodiscard]] bool IsEnumTransformed() const noexcept @@ -252,12 +269,12 @@ public: [[nodiscard]] bool IsNamespaceTransformed() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::NAMESPACE_TRANSFORMED) != 0; + return (Modifiers() & ClassDefinitionModifiers::NAMESPACE_TRANSFORMED) != 0; } [[nodiscard]] bool IsFromStruct() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::FROM_STRUCT) != 0; + return (Modifiers() & ClassDefinitionModifiers::FROM_STRUCT) != 0; } [[nodiscard]] bool IsModule() const noexcept @@ -267,47 +284,42 @@ public: [[nodiscard]] es2panda::Language Language() const noexcept { - return lang_; + return GetHistoryNodeAs()->lang_; } void SetGlobalInitialized() noexcept { - modifiers_ |= ClassDefinitionModifiers::GLOBAL_INITIALIZED; + AddClassModifiers(ClassDefinitionModifiers::GLOBAL_INITIALIZED); } void SetInnerModifier() noexcept { - modifiers_ |= ClassDefinitionModifiers::INNER; + AddClassModifiers(ClassDefinitionModifiers::INNER); } void SetClassDefinitionChecked() noexcept { - modifiers_ |= ClassDefinitionModifiers::CLASSDEFINITION_CHECKED; + AddClassModifiers(ClassDefinitionModifiers::CLASSDEFINITION_CHECKED); } void SetAnonymousModifier() noexcept { - modifiers_ |= ClassDefinitionModifiers::ANONYMOUS; + AddClassModifiers(ClassDefinitionModifiers::ANONYMOUS); } void SetNamespaceTransformed() noexcept { - modifiers_ |= ClassDefinitionModifiers::NAMESPACE_TRANSFORMED; + AddClassModifiers(ClassDefinitionModifiers::NAMESPACE_TRANSFORMED); } void SetFromStructModifier() noexcept { - modifiers_ |= ClassDefinitionModifiers::FROM_STRUCT; + AddClassModifiers(ClassDefinitionModifiers::FROM_STRUCT); } [[nodiscard]] ClassDefinitionModifiers Modifiers() const noexcept { - return modifiers_; - } - - void SetModifiers(ClassDefinitionModifiers modifiers) noexcept - { - modifiers_ = modifiers; + return GetHistoryNodeAs()->modifiers_; } void AddProperties(ArenaVector &&body) @@ -316,64 +328,46 @@ public: prop->SetParent(this); } - body_.insert(body_.end(), body.begin(), body.end()); - } - - [[nodiscard]] ArenaVector &Body() noexcept - { - return body_; + auto newNode = GetOrCreateHistoryNode()->AsClassDefinition(); + newNode->body_.insert(newNode->body_.end(), body.begin(), body.end()); } [[nodiscard]] const ArenaVector &Body() const noexcept { - return body_; + return GetHistoryNodeAs()->body_; } [[nodiscard]] MethodDefinition *Ctor() noexcept { - return ctor_; - } - - void SetCtor(MethodDefinition *ctor) - { - ctor_ = ctor; - } - - [[nodiscard]] ArenaVector &Implements() noexcept - { - return implements_; + return GetHistoryNodeAs()->ctor_; } [[nodiscard]] const ArenaVector &Implements() const noexcept { - return implements_; + return GetHistoryNodeAs()->implements_; } [[nodiscard]] const ir::TSTypeParameterDeclaration *TypeParams() const noexcept { - return typeParams_; + return GetHistoryNodeAs()->typeParams_; } [[nodiscard]] ir::TSTypeParameterDeclaration *TypeParams() noexcept { - return typeParams_; - } - - void SetTypeParams(ir::TSTypeParameterDeclaration *typeParams) - { - typeParams_ = typeParams; + return GetHistoryNodeAs()->typeParams_; } const TSTypeParameterInstantiation *SuperTypeParams() const { - return superTypeParams_; + return GetHistoryNodeAs()->superTypeParams_; } TSTypeParameterInstantiation *SuperTypeParams() { - return superTypeParams_; + return GetHistoryNodeAs()->superTypeParams_; } + // ekkoruse: dangerous count for cache here [[nodiscard]] static int LocalTypeCounter() noexcept { return classCounter_; @@ -381,7 +375,7 @@ public: [[nodiscard]] int LocalIndex() const noexcept { - return localIndex_; + return GetHistoryNodeAs()->localIndex_; } [[nodiscard]] util::StringView FunctionalReferenceReferencedMethod() const noexcept @@ -396,52 +390,46 @@ public: [[nodiscard]] const std::string &LocalPrefix() const noexcept { - return localPrefix_; + return GetHistoryNodeAs()->localPrefix_; } bool CaptureVariable(varbinder::Variable *var) { - return capturedVars_.insert(var).second; + auto newNode = GetOrCreateHistoryNode()->AsClassDefinition(); + return newNode->capturedVars_.insert(var).second; } bool AddToLocalVariableIsNeeded(varbinder::Variable *var) { - return localVariableIsNeeded_.insert(var).second; + auto newNode = GetOrCreateHistoryNode()->AsClassDefinition(); + return newNode->localVariableIsNeeded_.insert(var).second; } bool IsLocalVariableNeeded(varbinder::Variable *var) const { - return localVariableIsNeeded_.find(var) != localVariableIsNeeded_.end(); + auto const newNode = GetHistoryNode()->AsClassDefinition(); + return newNode->localVariableIsNeeded_.find(var) != newNode->localVariableIsNeeded_.end(); } [[nodiscard]] const ArenaSet &CapturedVariables() const noexcept { - return capturedVars_; + return GetHistoryNodeAs()->capturedVars_; } bool EraseCapturedVariable(varbinder::Variable *var) { - return capturedVars_.erase(var) != 0; - } - - void SetOrigEnumDecl(ir::TSEnumDeclaration *enumDecl) - { - origEnumDecl_ = enumDecl; + auto newNode = GetOrCreateHistoryNode()->AsClassDefinition(); + return newNode->capturedVars_.erase(var) != 0; } ir::TSEnumDeclaration *OrigEnumDecl() const { - return origEnumDecl_; + return GetHistoryNodeAs()->origEnumDecl_; } ClassDeclaration *GetAnonClass() noexcept { - return anonClass_; - } - - void SetAnonClass(ClassDeclaration *anonClass) noexcept - { - anonClass_ = anonClass; + return GetHistoryNodeAs()->anonClass_; } const FunctionExpression *Ctor() const; @@ -450,6 +438,7 @@ public: bool HasComputedInstanceField() const; bool HasMatchingPrivateKey(const util::StringView &name) const; + void TransformBase(const NodeTransformer &cb, std::string_view transformationName); void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; void Iterate(const NodeTraverser &cb) const override; @@ -483,26 +472,74 @@ public: void CleanUp() override { AstNode::CleanUp(); - modifiers_ &= ~(ClassDefinitionModifiers::CLASSDEFINITION_CHECKED); + ClearClassModifiers(ClassDefinitionModifiers::CLASSDEFINITION_CHECKED); } void AddToExportedClasses(const ir::ClassDeclaration *cls) { ES2PANDA_ASSERT(cls->IsExported()); - exportedClasses_.push_back(cls); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + newNode->exportedClasses_.emplace_back(cls); } [[nodiscard]] const ArenaVector &ExportedClasses() const noexcept { - return exportedClasses_; + return GetHistoryNodeAs()->exportedClasses_; } + void SetScope(varbinder::LocalScope *scope); + void SetModifiers(ClassDefinitionModifiers modifiers); + + void EmplaceBody(AstNode *body); + void ClearBody(); + void SetValueBody(AstNode *body, size_t index); + const ArenaVector &Body(); + [[nodiscard]] ArenaVector &BodyForUpdate(); + + void EmplaceImplements(TSClassImplements *implements); + void ClearImplements(); + void SetValueImplements(TSClassImplements *implements, size_t index); + const ArenaVector &Implements(); + ArenaVector &ImplementsForUpdate(); + + void SetCtor(MethodDefinition *ctor); + void SetTypeParams(TSTypeParameterDeclaration *typeParams); + void SetOrigEnumDecl(TSEnumDeclaration *origEnumDecl); + void SetAnonClass(ClassDeclaration *anonClass); + void SetInternalName(util::StringView internalName); protected: ClassDefinition *Construct(ArenaAllocator *allocator) override; + void AddClassModifiers(ClassDefinitionModifiers const flags) noexcept + { + if (!All(Modifiers(), flags)) { + GetOrCreateHistoryNodeAs()->modifiers_ |= flags; + } + } + + void ClearClassModifiers(ClassDefinitionModifiers const flags) noexcept + { + if (Any(Modifiers(), flags)) { + GetOrCreateHistoryNodeAs()->modifiers_ &= ~flags; + } + } + void CopyTo(AstNode *other) const override; private: + void SetSuperClass(Expression *superClass); + void SetSuperTypeParams(TSTypeParameterInstantiation *superTypeParams); + + [[nodiscard]] Expression *SuperClass() + { + return GetHistoryNodeAs()->superClass_; + } + + [[nodiscard]] const Expression *SuperClass() const + { + return GetHistoryNodeAs()->superClass_; + } + void CompileStaticFieldInitializers(compiler::PandaGen *pg, compiler::VReg classReg, const std::vector &staticComputedFieldKeys) const; @@ -528,7 +565,7 @@ private: ArenaSet localVariableIsNeeded_; TSEnumDeclaration *origEnumDecl_ {}; ClassDeclaration *anonClass_ {nullptr}; - static int classCounter_; + static std::atomic classCounter_; int localIndex_ {}; std::string localPrefix_ {}; util::StringView functionalReferenceReferencedMethod_ {}; diff --git a/ets2panda/ir/base/classElement.cpp b/ets2panda/ir/base/classElement.cpp index 9c54368dd8..24c42eeb71 100644 --- a/ets2panda/ir/base/classElement.cpp +++ b/ets2panda/ir/base/classElement.cpp @@ -20,22 +20,70 @@ namespace ark::es2panda::ir { +void ClassElement::SetOrigEnumMember(TSEnumMember *enumMember) +{ + this->GetOrCreateHistoryNodeAs()->enumMember_ = enumMember; +} + +void ClassElement::SetKey(Expression *key) +{ + this->GetOrCreateHistoryNodeAs()->key_ = key; +} + +void ClassElement::EmplaceDecorators(Decorator *decorators) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.emplace_back(decorators); +} + +void ClassElement::ClearDecorators() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.clear(); +} + +void ClassElement::SetValueDecorators(Decorator *decorators, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->decorators_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = decorators; +} + +[[nodiscard]] const ArenaVector &ClassElement::Decorators() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->decorators_; +} + +[[nodiscard]] ArenaVector &ClassElement::DecoratorsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->decorators_; +} + void ClassElement::SetValue(Expression *value) noexcept { + if (Value() == value) { + return; + } + if (value != nullptr) { value->SetParent(this); } - value_ = value; + this->GetOrCreateHistoryNodeAs()->value_ = value; } Identifier *ClassElement::Id() noexcept { - return key_ != nullptr && key_->IsIdentifier() ? key_->AsIdentifier() : nullptr; + auto const key = GetHistoryNode()->AsClassElement()->key_; + return key != nullptr && key->IsIdentifier() ? key->AsIdentifier() : nullptr; } const Identifier *ClassElement::Id() const noexcept { - return key_ != nullptr && key_->IsIdentifier() ? key_->AsIdentifier() : nullptr; + auto const key = GetHistoryNode()->AsClassElement()->key_; + return key != nullptr && key->IsIdentifier() ? key->AsIdentifier() : nullptr; } bool ClassElement::IsPrivateElement() const noexcept @@ -44,7 +92,8 @@ bool ClassElement::IsPrivateElement() const noexcept return false; } - return key_->IsIdentifier() && key_->AsIdentifier()->IsPrivateIdent(); + auto const key = GetHistoryNode()->AsClassElement()->key_; + return key->IsIdentifier() && key->AsIdentifier()->IsPrivateIdent(); } void ClassElement::CopyTo(AstNode *other) const diff --git a/ets2panda/ir/base/classElement.h b/ets2panda/ir/base/classElement.h index fc372f8dc2..45101a888b 100644 --- a/ets2panda/ir/base/classElement.h +++ b/ets2panda/ir/base/classElement.h @@ -38,6 +38,24 @@ public: decorators_(allocator->Adapter()), isComputed_(isComputed) { + InitHistory(); + } + + // CC-OFFNXT(G.FUN.01-CPP) solid logic + explicit ClassElement(AstNodeType const elementType, Expression *const key, Expression *const value, + ModifierFlags const modifiers, ArenaAllocator *const allocator, bool const isComputed, + AstNodeHistory *history) + : TypedStatement(elementType, modifiers), + key_(key), + value_(value), + decorators_(allocator->Adapter()), + isComputed_(isComputed) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } [[nodiscard]] Identifier *Id() noexcept; @@ -46,62 +64,56 @@ public: [[nodiscard]] Expression *Key() noexcept { - return key_; + return GetHistoryNodeAs()->key_; } [[nodiscard]] const Expression *Key() const noexcept { - return key_; + return GetHistoryNodeAs()->key_; } [[nodiscard]] Expression *Value() noexcept { - return value_; + return GetHistoryNodeAs()->value_; } void SetValue(Expression *value) noexcept; [[nodiscard]] const Expression *Value() const noexcept { - return value_; + return GetHistoryNodeAs()->value_; } [[nodiscard]] const TSEnumMember *OriginEnumMember() const noexcept { - return enumMember_; + return GetHistoryNodeAs()->enumMember_; } - void SetOrigEnumMember(ir::TSEnumMember *enumMember) - { - enumMember_ = enumMember; - } + void SetOrigEnumMember(ir::TSEnumMember *enumMember); [[nodiscard]] bool IsPrivateElement() const noexcept; [[nodiscard]] const ArenaVector &Decorators() const noexcept { - return decorators_; - } - - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); + return GetHistoryNodeAs()->decorators_; } [[nodiscard]] bool IsComputed() const noexcept { - return isComputed_; + return GetHistoryNodeAs()->isComputed_; } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = reinterpret_cast(GetOrCreateHistoryNode()); + newNode->decorators_ = std::move(decorators); } void AddDecorator(ir::Decorator *const decorator) { if (decorator != nullptr) { - decorators_.emplace_back(decorator); + auto newNode = reinterpret_cast(GetOrCreateHistoryNode()); + newNode->decorators_.emplace_back(decorator); } } @@ -114,8 +126,18 @@ public: void CopyTo(AstNode *other) const override; + void EmplaceDecorators(Decorator *decorators); + void ClearDecorators(); + void SetValueDecorators(Decorator *decorators, size_t index); + const ArenaVector &Decorators(); + ArenaVector &DecoratorsForUpdate(); + protected: friend class SizeOfNodeTest; + +protected: + void SetKey(Expression *key); + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) Expression *key_; Expression *value_; diff --git a/ets2panda/ir/base/classProperty.cpp b/ets2panda/ir/base/classProperty.cpp index 0ec31492bc..2bacec57d1 100644 --- a/ets2panda/ir/base/classProperty.cpp +++ b/ets2panda/ir/base/classProperty.cpp @@ -23,55 +23,75 @@ #include "compiler/lowering/util.h" namespace ark::es2panda::ir { + +void ClassProperty::SetTypeAnnotation(TypeNode *typeAnnotation) +{ + this->GetOrCreateHistoryNodeAs()->typeAnnotation_ = typeAnnotation; +} + +void ClassProperty::SetDefaultAccessModifier(bool isDefault) +{ + this->GetOrCreateHistoryNodeAs()->isDefault_ = isDefault; +} + void ClassProperty::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (auto *transformedNode = cb(key_); key_ != transformedNode) { - key_->SetTransformedNode(transformationName, transformedNode); - key_ = transformedNode->AsExpression(); + auto *key = Key(); + if (key != nullptr) { + if (auto *transformedNode = cb(key); key != transformedNode) { + key->SetTransformedNode(transformationName, transformedNode); + SetKey(transformedNode->AsExpression()); + } } - if (value_ != nullptr) { - if (auto *transformedNode = cb(value_); value_ != transformedNode) { - value_->SetTransformedNode(transformationName, transformedNode); - value_ = transformedNode->AsExpression(); + auto *value = Value(); + if (value != nullptr) { + if (auto *transformedNode = cb(value); value != transformedNode) { + value->SetTransformedNode(transformationName, transformedNode); + SetValue(transformedNode->AsExpression()); } } - if (typeAnnotation_ != nullptr) { - if (auto *transformedNode = cb(typeAnnotation_); typeAnnotation_ != transformedNode) { - typeAnnotation_->SetTransformedNode(transformationName, transformedNode); - typeAnnotation_ = static_cast(transformedNode); + auto *typeAnnotation = TypeAnnotation(); + if (typeAnnotation != nullptr) { + if (auto *transformedNode = cb(typeAnnotation); typeAnnotation != transformedNode) { + typeAnnotation->SetTransformedNode(transformationName, transformedNode); + SetTypeAnnotation(static_cast(transformedNode)); } } - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - for (auto *&it : Annotations()) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + auto const &annotations = Annotations(); + for (size_t ix = 0; ix < annotations.size(); ix++) { + if (auto *transformedNode = cb(annotations[ix]); annotations[ix] != transformedNode) { + annotations[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), ix); } } } void ClassProperty::Iterate(const NodeTraverser &cb) const { - cb(key_); + auto const key = GetHistoryNode()->AsClassProperty()->key_; + cb(key); - if (value_ != nullptr) { - cb(value_); + auto const value = GetHistoryNode()->AsClassProperty()->value_; + if (value != nullptr) { + cb(value); } - if (typeAnnotation_ != nullptr) { - cb(typeAnnotation_); + if (TypeAnnotation() != nullptr) { + cb(TypeAnnotation()); } - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -83,17 +103,17 @@ void ClassProperty::Iterate(const NodeTraverser &cb) const void ClassProperty::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "ClassProperty"}, - {"key", key_}, - {"value", AstDumper::Optional(value_)}, - {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(flags_))}, + {"key", Key()}, + {"value", AstDumper::Optional(Value())}, + {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(Modifiers()))}, {"static", IsStatic()}, {"readonly", IsReadonly()}, {"declare", IsDeclare()}, {"optional", IsOptionalDeclaration()}, - {"computed", isComputed_}, - {"typeAnnotation", AstDumper::Optional(typeAnnotation_)}, + {"computed", IsComputed()}, + {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}, {"definite", IsDefinite()}, - {"decorators", decorators_}, + {"decorators", Decorators()}, {"annotations", AstDumper::Optional(Annotations())}}); } @@ -224,8 +244,8 @@ void ClassProperty::Dump(ir::SrcDumper *dumper) const } DumpPrefix(dumper); - if (key_ != nullptr) { - key_->Dump(dumper); + if (Key() != nullptr) { + Key()->Dump(dumper); } if (IsOptionalDeclaration()) { @@ -238,14 +258,14 @@ void ClassProperty::Dump(ir::SrcDumper *dumper) const if (typeAnnotation_ != nullptr && !dumper->IsDeclgen()) { dumper->Add(": "); - typeAnnotation_->Dump(dumper); + TypeAnnotation()->Dump(dumper); } DumpCheckerTypeForDeclGen(dumper); if (value_ != nullptr && !dumper->IsDeclgen()) { dumper->Add(" = "); - value_->Dump(dumper); + Value()->Dump(dumper); } dumper->Add(";"); @@ -274,11 +294,11 @@ checker::VerifiedType ClassProperty::Check(checker::ETSChecker *checker) ClassProperty *ClassProperty::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const key = key_->Clone(allocator, nullptr)->AsExpression(); - auto *const value = value_ != nullptr ? value_->Clone(allocator, nullptr)->AsExpression() : nullptr; - auto *const typeAnnotation = typeAnnotation_ != nullptr ? typeAnnotation_->Clone(allocator, nullptr) : nullptr; + auto *const key = Key()->Clone(allocator, nullptr)->AsExpression(); + auto *const value = Value() != nullptr ? Value()->Clone(allocator, nullptr)->AsExpression() : nullptr; + auto *const typeAnnotation = TypeAnnotation() != nullptr ? TypeAnnotation()->Clone(allocator, nullptr) : nullptr; - auto *const clone = allocator->New(key, value, typeAnnotation, flags_, allocator, isComputed_); + auto *const clone = allocator->New(key, value, typeAnnotation, Modifiers(), allocator, IsComputed()); if (parent != nullptr) { clone->SetParent(parent); @@ -286,7 +306,7 @@ ClassProperty *ClassProperty::Clone(ArenaAllocator *const allocator, AstNode *co key->SetParent(clone); if (value != nullptr) { - value->SetTsType(value_->TsType()); + value->SetTsType(Value()->TsType()); value->SetParent(clone); } if (typeAnnotation != nullptr) { @@ -294,7 +314,7 @@ ClassProperty *ClassProperty::Clone(ArenaAllocator *const allocator, AstNode *co typeAnnotation->SetParent(clone); } - for (auto *const decorator : decorators_) { + for (auto *const decorator : Decorators()) { clone->AddDecorator(decorator->Clone(allocator, clone)); } @@ -306,7 +326,7 @@ ClassProperty *ClassProperty::Clone(ArenaAllocator *const allocator, AstNode *co clone->SetAnnotations(std::move(annotationUsages)); } - clone->SetRange(range_); + clone->SetRange(Range()); return clone; } diff --git a/ets2panda/ir/base/classProperty.h b/ets2panda/ir/base/classProperty.h index 9725118c57..ebdd968dc4 100644 --- a/ets2panda/ir/base/classProperty.h +++ b/ets2panda/ir/base/classProperty.h @@ -47,23 +47,17 @@ public: [[nodiscard]] bool IsDefaultAccessModifier() const noexcept { - return isDefault_; + return GetHistoryNodeAs()->isDefault_; } - void SetDefaultAccessModifier(bool isDefault) - { - isDefault_ = isDefault; - } + void SetDefaultAccessModifier(bool isDefault); [[nodiscard]] TypeNode *TypeAnnotation() const noexcept { - return typeAnnotation_; + return GetHistoryNodeAs()->typeAnnotation_; } - void SetTypeAnnotation(TypeNode *typeAnnotation) noexcept - { - typeAnnotation_ = typeAnnotation; - } + void SetTypeAnnotation(TypeNode *typeAnnotation); [[nodiscard]] PrivateFieldKind ToPrivateFieldKind(bool const isStatic) const override { diff --git a/ets2panda/ir/base/classStaticBlock.cpp b/ets2panda/ir/base/classStaticBlock.cpp index d912d1532b..f8b01d54a7 100644 --- a/ets2panda/ir/base/classStaticBlock.cpp +++ b/ets2panda/ir/base/classStaticBlock.cpp @@ -30,20 +30,22 @@ namespace ark::es2panda::ir { void ClassStaticBlock::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - if (auto *transformedNode = cb(value_); value_ != transformedNode) { - value_->SetTransformedNode(transformationName, transformedNode); - value_ = transformedNode->AsExpression(); + auto const value = Value(); + if (auto *transformedNode = cb(value); value != transformedNode) { + value->SetTransformedNode(transformationName, transformedNode); + SetValue(transformedNode->AsExpression()); } } void ClassStaticBlock::Iterate(const NodeTraverser &cb) const { - cb(value_); + auto const value = reinterpret_cast(GetHistoryNode())->value_; + cb(value); } void ClassStaticBlock::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ClassStaticBlock"}, {"value", value_}}); + dumper->Add({{"type", "ClassStaticBlock"}, {"value", Value()}}); } void ClassStaticBlock::Dump([[maybe_unused]] ir::SrcDumper *dumper) const @@ -84,12 +86,12 @@ checker::VerifiedType ClassStaticBlock::Check(checker::ETSChecker *checker) ir::ScriptFunction *ClassStaticBlock::Function() { - return value_->AsFunctionExpression()->Function(); + return Value()->AsFunctionExpression()->Function(); } const ir::ScriptFunction *ClassStaticBlock::Function() const { - return value_->AsFunctionExpression()->Function(); + return Value()->AsFunctionExpression()->Function(); } const util::StringView &ClassStaticBlock::Name() const diff --git a/ets2panda/ir/base/classStaticBlock.h b/ets2panda/ir/base/classStaticBlock.h index a1a1030b75..63ffc33f16 100644 --- a/ets2panda/ir/base/classStaticBlock.h +++ b/ets2panda/ir/base/classStaticBlock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-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 @@ -26,6 +26,7 @@ public: explicit ClassStaticBlock(Expression *value, ArenaAllocator *allocator) : ClassElement(AstNodeType::CLASS_STATIC_BLOCK, nullptr, value, ModifierFlags::NONE, allocator, false) { + InitHistory(); } PrivateFieldKind ToPrivateFieldKind([[maybe_unused]] bool isStatic) const override @@ -51,6 +52,16 @@ public: v->Accept(this); } + ClassStaticBlock *Construct(ArenaAllocator *allocator) override + { + return allocator->New(nullptr, allocator); + } + + void CopyTo(AstNode *other) const override + { + ClassElement::CopyTo(other); + }; + private: }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/base/methodDefinition.cpp b/ets2panda/ir/base/methodDefinition.cpp index cf497838fb..6f705a2f97 100644 --- a/ets2panda/ir/base/methodDefinition.cpp +++ b/ets2panda/ir/base/methodDefinition.cpp @@ -24,19 +24,36 @@ namespace ark::es2panda::ir { +void MethodDefinition::SetDefaultAccessModifier(bool isDefault) +{ + this->GetOrCreateHistoryNodeAs()->isDefault_ = isDefault; +} + +void MethodDefinition::SetBaseOverloadMethod(MethodDefinition *baseOverloadMethod) +{ + this->GetOrCreateHistoryNodeAs()->baseOverloadMethod_ = baseOverloadMethod; +} + +void MethodDefinition::SetAsyncPairMethod(MethodDefinition *asyncPairMethod) +{ + this->GetOrCreateHistoryNodeAs()->asyncPairMethod_ = asyncPairMethod; +} + ScriptFunction *MethodDefinition::Function() { - return value_->IsFunctionExpression() ? value_->AsFunctionExpression()->Function() : nullptr; + auto const value = Value(); + return value->IsFunctionExpression() ? value->AsFunctionExpression()->Function() : nullptr; } const ScriptFunction *MethodDefinition::Function() const { - return value_->IsFunctionExpression() ? value_->AsFunctionExpression()->Function() : nullptr; + auto const value = Value(); + return value->IsFunctionExpression() ? value->AsFunctionExpression()->Function() : nullptr; } PrivateFieldKind MethodDefinition::ToPrivateFieldKind(bool const isStatic) const { - switch (kind_) { + switch (Kind()) { case MethodDefinitionKind::METHOD: { return isStatic ? PrivateFieldKind::STATIC_METHOD : PrivateFieldKind::METHOD; } @@ -54,57 +71,65 @@ PrivateFieldKind MethodDefinition::ToPrivateFieldKind(bool const isStatic) const void MethodDefinition::ResolveReferences(const NodeTraverser &cb) const { - cb(key_); - cb(value_); + auto key = GetHistoryNode()->AsMethodDefinition()->key_; + auto value = GetHistoryNode()->AsMethodDefinition()->value_; + cb(key); + cb(value); - for (auto *it : VectorIterationGuard(overloads_)) { + for (auto *it : VectorIterationGuard(Overloads())) { cb(it); } - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } } void MethodDefinition::Iterate(const NodeTraverser &cb) const { - cb(key_); - cb(value_); + auto key = GetHistoryNode()->AsMethodDefinition()->key_; + auto value = GetHistoryNode()->AsMethodDefinition()->value_; + cb(key); + cb(value); - for (auto *it : overloads_) { + for (auto *it : Overloads()) { if (it->Parent() == this) { cb(it); } } - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } } void MethodDefinition::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (auto *transformedNode = cb(key_); key_ != transformedNode) { - key_->SetTransformedNode(transformationName, transformedNode); - key_ = transformedNode->AsExpression(); + auto *key = Key(); + if (auto *transformedNode = cb(key); key != transformedNode) { + key->SetTransformedNode(transformationName, transformedNode); + SetKey(transformedNode->AsExpression()); } - if (auto *transformedNode = cb(value_); value_ != transformedNode) { - value_->SetTransformedNode(transformationName, transformedNode); - value_ = transformedNode->AsExpression(); + auto *value = Value(); + if (auto *transformedNode = cb(value); value != transformedNode) { + value->SetTransformedNode(transformationName, transformedNode); + SetValue(transformedNode->AsExpression()); } - for (auto *&it : VectorIterationGuard(overloads_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsMethodDefinition(); + auto const &overloads = Overloads(); + for (size_t ix = 0; ix < overloads.size(); ix++) { + if (auto *transformedNode = cb(overloads[ix]); overloads[ix] != transformedNode) { + overloads[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueOverloads(transformedNode->AsMethodDefinition(), ix); } } - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } } @@ -113,7 +138,7 @@ void MethodDefinition::Dump(ir::AstDumper *dumper) const { const char *kind = nullptr; - switch (kind_) { + switch (Kind()) { case MethodDefinitionKind::CONSTRUCTOR: { kind = "constructor"; break; @@ -148,15 +173,15 @@ void MethodDefinition::Dump(ir::AstDumper *dumper) const } dumper->Add({{"type", "MethodDefinition"}, - {"key", key_}, + {"key", Key()}, {"kind", kind}, - {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(flags_))}, + {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(Modifiers()))}, {"static", IsStatic()}, {"optional", IsOptionalDeclaration()}, - {"computed", isComputed_}, - {"value", value_}, - {"overloads", overloads_}, - {"decorators", decorators_}}); + {"computed", IsComputed()}, + {"value", Value()}, + {"overloads", Overloads()}, + {"decorators", Decorators()}}); } void MethodDefinition::DumpModifierPrefix(ir::SrcDumper *dumper) const @@ -306,12 +331,13 @@ void MethodDefinition::Dump(ir::SrcDumper *dumper) const return; } - for (auto method : overloads_) { + for (auto method : Overloads()) { method->Dump(dumper); dumper->Endl(); } - for (auto *anno : value_->AsFunctionExpression()->Function()->Annotations()) { + auto value = Value(); + for (auto *anno : value->AsFunctionExpression()->Function()->Annotations()) { // NOTE(zhelyapov): workaround, see #26031 if (anno->GetBaseName()->Name() != compiler::Signatures::DEFAULT_ANNO_FOR_FUNC) { anno->Dump(dumper); @@ -319,12 +345,13 @@ void MethodDefinition::Dump(ir::SrcDumper *dumper) const } DumpPrefix(dumper); - if (key_ != nullptr) { - key_->Dump(dumper); + auto key = Key(); + if (key != nullptr) { + key->Dump(dumper); } - if (value_ != nullptr) { - value_->Dump(dumper); + if (value != nullptr) { + value->Dump(dumper); } } @@ -350,9 +377,9 @@ checker::VerifiedType MethodDefinition::Check(checker::ETSChecker *checker) MethodDefinition *MethodDefinition::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const key = key_->Clone(allocator, nullptr)->AsExpression(); - auto *const value = value_->Clone(allocator, nullptr)->AsExpression(); - auto *const clone = allocator->New(kind_, key, value, flags_, allocator, isComputed_); + auto *const key = Key()->Clone(allocator, nullptr)->AsExpression(); + auto *const value = Value()->Clone(allocator, nullptr)->AsExpression(); + auto *const clone = allocator->New(Kind(), key, value, Modifiers(), allocator, IsComputed()); if (parent != nullptr) { clone->SetParent(parent); @@ -361,13 +388,13 @@ MethodDefinition *MethodDefinition::Clone(ArenaAllocator *const allocator, AstNo key->SetParent(clone); value->SetParent(clone); - for (auto *const decorator : decorators_) { + for (auto *const decorator : Decorators()) { clone->AddDecorator(decorator->Clone(allocator, clone)); } - clone->baseOverloadMethod_ = baseOverloadMethod_; + clone->SetBaseOverloadMethod(BaseOverloadMethod()); - for (auto *const overloads : overloads_) { + for (auto *const overloads : Overloads()) { clone->AddOverload(overloads->Clone(allocator, clone)); } @@ -378,19 +405,16 @@ void MethodDefinition::InitializeOverloadInfo() { ES2PANDA_ASSERT(this->Function() != nullptr); - overloadInfo_ = {this->Function()->Signature()->MinArgCount(), - this->Function()->Signature()->ArgCount(), - false, - this->IsDeclare(), - (this->Function()->Signature()->RestVar() != nullptr), - this->Function()->Signature()->ReturnType()->IsETSVoidType()}; + SetOverloadInfo({this->Function()->Signature()->MinArgCount(), this->Function()->Signature()->ArgCount(), false, + this->IsDeclare(), (this->Function()->Signature()->RestVar() != nullptr), + this->Function()->Signature()->ReturnType()->IsETSVoidType()}); } void MethodDefinition::ResetOverloads() { - auto baseOverloadMethod = baseOverloadMethod_; - baseOverloadMethod_ = nullptr; - for (auto *overload : overloads_) { + auto baseOverloadMethod = BaseOverloadMethod(); + SetBaseOverloadMethod(nullptr); + for (auto *overload : Overloads()) { overload->CleanUp(); } ClearOverloads(); @@ -419,7 +443,8 @@ void MethodDefinition::ResetOverloads() } } - body.emplace_back(this); + parent->IsClassDefinition() ? parent->AsClassDefinition()->EmplaceBody(this) + : parent->AsTSInterfaceBody()->Body().push_back(this); } void MethodDefinition::CleanUp() @@ -448,4 +473,30 @@ void MethodDefinition::CopyTo(AstNode *other) const ClassElement::CopyTo(other); } +void MethodDefinition::EmplaceOverloads(MethodDefinition *overloads) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->overloads_.emplace_back(overloads); +} + +void MethodDefinition::ClearOverloads() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->overloads_.clear(); +} + +void MethodDefinition::SetValueOverloads(MethodDefinition *overloads, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->overloads_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = overloads; +} + +[[nodiscard]] ArenaVector &MethodDefinition::OverloadsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->overloads_; +} + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/base/methodDefinition.h b/ets2panda/ir/base/methodDefinition.h index 22b5321129..af54efb580 100644 --- a/ets2panda/ir/base/methodDefinition.h +++ b/ets2panda/ir/base/methodDefinition.h @@ -66,6 +66,24 @@ public: baseOverloadMethod_(nullptr), asyncPairMethod_(nullptr) { + InitHistory(); + } + + // CC-OFFNXT(G.FUN.01-CPP) solid logic + explicit MethodDefinition(MethodDefinitionKind const kind, Expression *const key, Expression *const value, + ModifierFlags const modifiers, ArenaAllocator *const allocator, bool const isComputed, + AstNodeHistory *history) + : ClassElement(AstNodeType::METHOD_DEFINITION, key, value, modifiers, allocator, isComputed), + kind_(kind), + overloads_(allocator->Adapter()), + baseOverloadMethod_(nullptr), + asyncPairMethod_(nullptr) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } // NOTE (csabahurton): these friend relationships can be removed once there are getters for private fields @@ -73,106 +91,120 @@ public: MethodDefinitionKind Kind() const { - return kind_; + return GetHistoryNodeAs()->kind_; } [[nodiscard]] bool IsConstructor() const noexcept { - return kind_ == MethodDefinitionKind::CONSTRUCTOR; + return Kind() == MethodDefinitionKind::CONSTRUCTOR; } [[nodiscard]] bool IsMethod() const noexcept { - return kind_ == MethodDefinitionKind::METHOD; + return Kind() == MethodDefinitionKind::METHOD; } [[nodiscard]] bool IsExtensionMethod() const noexcept { - return (kind_ == MethodDefinitionKind::EXTENSION_METHOD) || (kind_ == MethodDefinitionKind::EXTENSION_GET) || - (kind_ == MethodDefinitionKind::EXTENSION_SET); + auto const kind = Kind(); + return (kind == MethodDefinitionKind::EXTENSION_METHOD) || (kind == MethodDefinitionKind::EXTENSION_GET) || + (kind == MethodDefinitionKind::EXTENSION_SET); } [[nodiscard]] bool IsGetter() const noexcept { - return kind_ == MethodDefinitionKind::GET; + return Kind() == MethodDefinitionKind::GET; } [[nodiscard]] bool IsSetter() const noexcept { - return kind_ == MethodDefinitionKind::SET; + return Kind() == MethodDefinitionKind::SET; } [[nodiscard]] bool IsDefaultAccessModifier() const noexcept { - return isDefault_; + return GetHistoryNodeAs()->isDefault_; } - void SetDefaultAccessModifier(bool isDefault) - { - isDefault_ = isDefault; - } + void SetDefaultAccessModifier(bool isDefault); [[nodiscard]] const OverloadsT &Overloads() const noexcept { - return overloads_; + return GetHistoryNodeAs()->overloads_; } [[nodiscard]] const MethodDefinition *BaseOverloadMethod() const noexcept { - return baseOverloadMethod_; + return GetHistoryNodeAs()->baseOverloadMethod_; } [[nodiscard]] MethodDefinition *BaseOverloadMethod() noexcept { - return baseOverloadMethod_; + return GetHistoryNodeAs()->baseOverloadMethod_; } [[nodiscard]] const MethodDefinition *AsyncPairMethod() const noexcept { - return asyncPairMethod_; + return GetHistoryNodeAs()->asyncPairMethod_; } [[nodiscard]] MethodDefinition *AsyncPairMethod() noexcept { - return asyncPairMethod_; + return GetHistoryNodeAs()->asyncPairMethod_; } - [[nodiscard]] OverloadInfo &GetOverloadInfo() noexcept + [[nodiscard]] const OverloadInfo &GetOverloadInfo() noexcept { - return overloadInfo_; + auto newNode = this->GetHistoryNode()->AsMethodDefinition(); + return newNode->overloadInfo_; } - void SetOverloads(OverloadsT &&overloads) + [[nodiscard]] OverloadInfo &GetOverloadInfoForUpdate() noexcept { - overloads_ = std::move(overloads); + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + return newNode->overloadInfo_; } - void ClearOverloads() + [[nodiscard]] const OverloadInfo &GetOverloadInfo() const noexcept { - overloads_.clear(); + return GetHistoryNodeAs()->overloadInfo_; } - void AddOverload(MethodDefinition *const overload) + void SetOverloadInfo(OverloadInfo &&overloadInfo) { - ES2PANDA_ASSERT(overload != nullptr); - overloads_.emplace_back(overload); - overload->Function()->AddFlag((ir::ScriptFunctionFlags::OVERLOAD)); - overload->SetBaseOverloadMethod(this); + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + newNode->overloadInfo_ = overloadInfo; } - void SetBaseOverloadMethod(MethodDefinition *const baseOverloadMethod) + void SetOverloadInfo(OverloadInfo &overloadInfo) + { + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + newNode->overloadInfo_ = overloadInfo; + } + + void SetOverloads(OverloadsT &&overloads) { - baseOverloadMethod_ = baseOverloadMethod; + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + newNode->overloads_ = std::move(overloads); } - void SetAsyncPairMethod(MethodDefinition *const method) + void AddOverload(MethodDefinition *const overload) { - asyncPairMethod_ = method; + ES2PANDA_ASSERT(overload != nullptr); + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + newNode->overloads_.emplace_back(overload); + overload->Function()->AddFlag((ir::ScriptFunctionFlags::OVERLOAD)); + overload->SetBaseOverloadMethod(this); } + void SetBaseOverloadMethod(MethodDefinition *const baseOverloadMethod); + + void SetAsyncPairMethod(MethodDefinition *const asyncPairMethod); + [[nodiscard]] bool HasOverload(MethodDefinition *overload) noexcept { - return std::find(overloads_.begin(), overloads_.end(), overload) != overloads_.end(); + auto const overloads = Overloads(); + return std::find(overloads.begin(), overloads.end(), overload) != overloads.end(); } ScriptFunction *Function(); @@ -201,6 +233,11 @@ public: void CleanUp() override; + void EmplaceOverloads(MethodDefinition *overloads); + void ClearOverloads(); + void SetValueOverloads(MethodDefinition *overloads, size_t index); + [[nodiscard]] ArenaVector &OverloadsForUpdate(); + protected: MethodDefinition *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; diff --git a/ets2panda/ir/base/scriptFunction.cpp b/ets2panda/ir/base/scriptFunction.cpp index 0eb77cd6c8..73ef90390f 100644 --- a/ets2panda/ir/base/scriptFunction.cpp +++ b/ets2panda/ir/base/scriptFunction.cpp @@ -25,6 +25,90 @@ namespace ark::es2panda::ir { +void ScriptFunction::SetBody(AstNode *body) +{ + this->GetOrCreateHistoryNodeAs()->body_ = body; +} + +void ScriptFunction::SetSignature(checker::Signature *signature) +{ + this->GetOrCreateHistoryNodeAs()->signature_ = signature; +} + +void ScriptFunction::SetScope(varbinder::FunctionScope *scope) +{ + this->GetOrCreateHistoryNodeAs()->scope_ = scope; +} + +void ScriptFunction::SetPreferredReturnType(checker::Type *preferredReturnType) +{ + this->GetOrCreateHistoryNodeAs()->preferredReturnType_ = preferredReturnType; +} + +void ScriptFunction::EmplaceParams(Expression *params) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->irSignature_.Params().emplace_back(params); +} + +void ScriptFunction::ClearParams() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->irSignature_.Params().clear(); +} + +void ScriptFunction::SetValueParams(Expression *params, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->irSignature_.Params(); + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = params; +} + +[[nodiscard]] const ArenaVector &ScriptFunction::Params() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->irSignature_.Params(); +} + +[[nodiscard]] ArenaVector &ScriptFunction::ParamsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->irSignature_.Params(); +} + +void ScriptFunction::EmplaceReturnStatements(ReturnStatement *returnStatements) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->returnStatements_.emplace_back(returnStatements); +} + +void ScriptFunction::ClearReturnStatements() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->returnStatements_.clear(); +} + +void ScriptFunction::SetValueReturnStatements(ReturnStatement *returnStatements, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->returnStatements_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = returnStatements; +} + +[[nodiscard]] const ArenaVector &ScriptFunction::ReturnStatements() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->returnStatements_; +} + +[[nodiscard]] ArenaVector &ScriptFunction::ReturnStatementsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->returnStatements_; +} + ScriptFunction::ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data) : JsDocAllowed>(AstNodeType::SCRIPT_FUNCTION, data.flags, allocator), irSignature_(std::move(data.signature)), @@ -44,13 +128,40 @@ ScriptFunction::ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&d if (auto *typeParams = irSignature_.TypeParams(); typeParams != nullptr) { typeParams->SetParent(this); } + InitHistory(); +} + +ScriptFunction::ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data, AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::SCRIPT_FUNCTION, data.flags, allocator), + irSignature_(std::move(data.signature)), + body_(data.body), + funcFlags_(data.funcFlags), + lang_(data.lang), + returnStatements_(allocator->Adapter()) +{ + for (auto *param : irSignature_.Params()) { + param->SetParent(this); + } + + if (auto *returnType = irSignature_.ReturnType(); returnType != nullptr) { + returnType->SetParent(this); + } + + if (auto *typeParams = irSignature_.TypeParams(); typeParams != nullptr) { + typeParams->SetParent(this); + } + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } std::size_t ScriptFunction::FormalParamsLength() const noexcept { std::size_t length = 0U; - for (const auto *param : irSignature_.Params()) { + for (const auto *param : Params()) { if (param->IsRestElement() || param->IsAssignmentPattern()) { break; } @@ -63,8 +174,8 @@ std::size_t ScriptFunction::FormalParamsLength() const noexcept void ScriptFunction::SetIdent(Identifier *id) noexcept { - id_ = id; - id_->SetParent(this); + this->GetOrCreateHistoryNodeAs()->id_ = id; + id->SetParent(this); } ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent) @@ -80,7 +191,7 @@ ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent auto *res = util::NodeAllocator::ForceSetParent( allocator, allocator, ScriptFunctionData { - body_ != nullptr ? body_->Clone(allocator, nullptr) : nullptr, + Body() != nullptr ? Body()->Clone(allocator, nullptr) : nullptr, FunctionSignature { TypeParams() != nullptr ? TypeParams()->Clone(allocator, nullptr)->AsTSTypeParameterDeclaration() : nullptr, @@ -88,7 +199,7 @@ ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent ReturnTypeAnnotation() != nullptr ? ReturnTypeAnnotation()->Clone(allocator, nullptr)->AsTypeNode() : nullptr, HasReceiver()}, - funcFlags_, flags_, lang_}); + Flags(), Modifiers(), Language()}); res->SetParent(parent); res->SetAnnotations(std::move(annotationUsages)); return res; @@ -96,38 +207,38 @@ ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent void ScriptFunction::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (id_ != nullptr) { - if (auto *transformedNode = cb(id_); id_ != transformedNode) { - id_->SetTransformedNode(transformationName, transformedNode); - id_ = transformedNode->AsIdentifier(); + auto const id = Id(); + if (id != nullptr) { + if (auto *transformedNode = cb(id); id != transformedNode) { + id->SetTransformedNode(transformationName, transformedNode); + SetIdent(transformedNode->AsIdentifier()); } } - irSignature_.TransformChildren(cb, transformationName); + GetOrCreateHistoryNode()->AsScriptFunction()->irSignature_.TransformChildren(cb, transformationName); - if (body_ != nullptr) { - if (auto *transformedNode = cb(body_); body_ != transformedNode) { - body_->SetTransformedNode(transformationName, transformedNode); - body_ = transformedNode; + auto const &body = Body(); + if (body != nullptr) { + if (auto *transformedNode = cb(body); body != transformedNode) { + body->SetTransformedNode(transformationName, transformedNode); + SetBody(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ScriptFunction::Iterate(const NodeTraverser &cb) const { - if (id_ != nullptr) { - cb(id_); + auto id = GetHistoryNode()->AsScriptFunction()->id_; + if (id != nullptr) { + cb(id); } - irSignature_.Iterate(cb); - if (body_ != nullptr) { - cb(body_); + GetHistoryNode()->AsScriptFunction()->irSignature_.Iterate(cb); + + auto body = GetHistoryNode()->AsScriptFunction()->body_; + if (body != nullptr) { + cb(body); } for (auto *it : VectorIterationGuard(Annotations())) { cb(it); @@ -136,7 +247,8 @@ void ScriptFunction::Iterate(const NodeTraverser &cb) const void ScriptFunction::SetReturnTypeAnnotation(TypeNode *node) noexcept { - irSignature_.SetReturnType(node); + auto newNode = GetOrCreateHistoryNode()->AsScriptFunction(); + newNode->irSignature_.SetReturnType(node); if (node != nullptr) { node->SetParent(this); } @@ -151,15 +263,15 @@ void ScriptFunction::Dump(ir::AstDumper *dumper) const throwMarker = "rethrows"; } dumper->Add({{"type", "ScriptFunction"}, - {"id", AstDumper::Nullish(id_)}, + {"id", AstDumper::Nullish(Id())}, {"generator", IsGenerator()}, {"async", IsAsyncFunc()}, - {"expression", ((funcFlags_ & ir::ScriptFunctionFlags::EXPRESSION) != 0)}, - {"params", irSignature_.Params()}, - {"returnType", AstDumper::Optional(irSignature_.ReturnType())}, - {"typeParameters", AstDumper::Optional(irSignature_.TypeParams())}, + {"expression", ((Flags() & ir::ScriptFunctionFlags::EXPRESSION) != 0)}, + {"params", Params()}, + {"returnType", AstDumper::Optional(ReturnTypeAnnotation())}, + {"typeParameters", AstDumper::Optional(TypeParams())}, {"declare", AstDumper::Optional(IsDeclare())}, - {"body", AstDumper::Optional(body_)}, + {"body", AstDumper::Optional(Body())}, {"annotations", AstDumper::Optional(Annotations())}, {"throwMarker", AstDumper::Optional(throwMarker)}}); } diff --git a/ets2panda/ir/base/scriptFunction.h b/ets2panda/ir/base/scriptFunction.h index 5651635642..e5a246ebb6 100644 --- a/ets2panda/ir/base/scriptFunction.h +++ b/ets2panda/ir/base/scriptFunction.h @@ -56,136 +56,130 @@ public: explicit ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data); + explicit ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data, AstNodeHistory *history); + [[nodiscard]] const Identifier *Id() const noexcept { - return id_; + return GetHistoryNodeAs()->id_; } [[nodiscard]] Identifier *Id() noexcept { - return id_; + return GetHistoryNodeAs()->id_; } [[nodiscard]] const checker::Signature *Signature() const noexcept { - return signature_; + return GetHistoryNodeAs()->signature_; } [[nodiscard]] checker::Signature *Signature() noexcept { - return signature_; + return GetHistoryNodeAs()->signature_; } [[nodiscard]] const ArenaVector &Params() const noexcept { - return irSignature_.Params(); + return GetHistoryNodeAs()->irSignature_.Params(); } - [[nodiscard]] ArenaVector &Params() noexcept - { - return irSignature_.Params(); - } + [[nodiscard]] const ArenaVector &Params(); const ArenaVector &ReturnStatements() const { - return returnStatements_; + return GetHistoryNodeAs()->returnStatements_; } - ArenaVector &ReturnStatements() - { - return returnStatements_; - } + [[nodiscard]] const ArenaVector &ReturnStatements(); + [[nodiscard]] ArenaVector &ReturnStatementsForUpdate(); [[nodiscard]] const TSTypeParameterDeclaration *TypeParams() const noexcept { - return irSignature_.TypeParams(); + return GetHistoryNodeAs()->irSignature_.TypeParams(); } [[nodiscard]] TSTypeParameterDeclaration *TypeParams() noexcept { - return irSignature_.TypeParams(); + return GetHistoryNode()->AsScriptFunction()->irSignature_.TypeParams(); } [[nodiscard]] const AstNode *Body() const noexcept { - return body_; + return GetHistoryNodeAs()->body_; } [[nodiscard]] AstNode *Body() noexcept { - return body_; + return GetHistoryNodeAs()->body_; } void AddReturnStatement(ReturnStatement *returnStatement) { - returnStatements_.push_back(returnStatement); + EmplaceReturnStatements(returnStatement); } - void SetBody(AstNode *body) noexcept - { - body_ = body; - } + void SetBody(AstNode *body); [[nodiscard]] const TypeNode *ReturnTypeAnnotation() const noexcept { - return irSignature_.ReturnType(); + return GetHistoryNodeAs()->irSignature_.ReturnType(); } [[nodiscard]] TypeNode *ReturnTypeAnnotation() noexcept { - return irSignature_.ReturnType(); + return GetHistoryNode()->AsScriptFunction()->irSignature_.ReturnType(); } void SetReturnTypeAnnotation(TypeNode *node) noexcept; [[nodiscard]] bool IsEntryPoint() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ENTRY_POINT) != 0; + return (Flags() & ir::ScriptFunctionFlags::ENTRY_POINT) != 0; } [[nodiscard]] bool IsGenerator() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::GENERATOR) != 0; + return (Flags() & ir::ScriptFunctionFlags::GENERATOR) != 0; } [[nodiscard]] bool IsAsyncFunc() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ASYNC) != 0; + return (Flags() & ir::ScriptFunctionFlags::ASYNC) != 0; } [[nodiscard]] bool IsAsyncImplFunc() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ASYNC_IMPL) != 0; + return (Flags() & ir::ScriptFunctionFlags::ASYNC_IMPL) != 0; } [[nodiscard]] bool IsArrow() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ARROW) != 0; + return (Flags() & ir::ScriptFunctionFlags::ARROW) != 0; } [[nodiscard]] bool IsOverload() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::OVERLOAD) != 0; + return (Flags() & ir::ScriptFunctionFlags::OVERLOAD) != 0; } [[nodiscard]] bool IsExternalOverload() const { - return (funcFlags_ & ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD) != 0; + return (Flags() & ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD) != 0; } [[nodiscard]] bool IsConstructor() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::CONSTRUCTOR) != 0; + return (Flags() & ir::ScriptFunctionFlags::CONSTRUCTOR) != 0; } [[nodiscard]] bool IsGetter() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::GETTER) != 0; + return (Flags() & ir::ScriptFunctionFlags::GETTER) != 0; } [[nodiscard]] bool IsSetter() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::SETTER) != 0; + return (Flags() & ir::ScriptFunctionFlags::SETTER) != 0; } [[nodiscard]] bool IsExtensionAccessor() const noexcept @@ -195,72 +189,77 @@ public: [[nodiscard]] bool IsMethod() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::METHOD) != 0; + return (Flags() & ir::ScriptFunctionFlags::METHOD) != 0; } [[nodiscard]] bool IsProxy() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::PROXY) != 0; + return (Flags() & ir::ScriptFunctionFlags::PROXY) != 0; } [[nodiscard]] bool IsStaticBlock() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::STATIC_BLOCK) != 0; + return (Flags() & ir::ScriptFunctionFlags::STATIC_BLOCK) != 0; } [[nodiscard]] bool IsEnum() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ENUM) != 0; + return (Flags() & ir::ScriptFunctionFlags::ENUM) != 0; } [[nodiscard]] bool IsHidden() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::HIDDEN) != 0; + return (Flags() & ir::ScriptFunctionFlags::HIDDEN) != 0; } [[nodiscard]] bool IsExternal() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::EXTERNAL) != 0; + return (Flags() & ir::ScriptFunctionFlags::EXTERNAL) != 0; } [[nodiscard]] bool IsImplicitSuperCallNeeded() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED) != 0; + return (Flags() & ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED) != 0; } [[nodiscard]] bool HasBody() const noexcept { - return body_ != nullptr; + return Body() != nullptr; } [[nodiscard]] bool HasRestParameter() const noexcept { - return signature_->RestVar() != nullptr; + return Signature()->RestVar() != nullptr; } [[nodiscard]] bool HasReturnStatement() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::HAS_RETURN) != 0; + return (Flags() & ir::ScriptFunctionFlags::HAS_RETURN) != 0; } [[nodiscard]] bool HasThrowStatement() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::HAS_THROW) != 0; + return (Flags() & ir::ScriptFunctionFlags::HAS_THROW) != 0; } [[nodiscard]] bool IsThrowing() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::THROWS) != 0; + return (Flags() & ir::ScriptFunctionFlags::THROWS) != 0; } [[nodiscard]] bool IsRethrowing() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::RETHROWS) != 0; + return (Flags() & ir::ScriptFunctionFlags::RETHROWS) != 0; + } + + [[nodiscard]] bool IsTrailingLambda() const noexcept + { + return (Flags() & ir::ScriptFunctionFlags::TRAILING_LAMBDA) != 0; } [[nodiscard]] bool IsDynamic() const noexcept { - return lang_.IsDynamic(); + return Language().IsDynamic(); } // Note: This method has been written into CAPI, cannot remove it simply. @@ -271,34 +270,30 @@ public: [[nodiscard]] ir::ScriptFunctionFlags Flags() const noexcept { - return funcFlags_; + return GetHistoryNodeAs()->funcFlags_; } [[nodiscard]] bool HasReceiver() const noexcept { - return irSignature_.HasReceiver(); + return GetHistoryNodeAs()->irSignature_.HasReceiver(); } void SetIdent(Identifier *id) noexcept; - void SetSignature(checker::Signature *signature) noexcept - { - signature_ = signature; - } + void SetSignature(checker::Signature *signature); void AddFlag(ir::ScriptFunctionFlags flags) noexcept { - funcFlags_ |= flags; + if (!All(Flags(), flags)) { + GetOrCreateHistoryNode()->AsScriptFunction()->funcFlags_ |= flags; + } } void ClearFlag(ir::ScriptFunctionFlags flags) noexcept { - funcFlags_ &= (~flags); - } - - void AddModifier(ir::ModifierFlags flags) noexcept - { - flags_ |= flags; + if (Any(Flags(), flags)) { + GetOrCreateHistoryNode()->AsScriptFunction()->funcFlags_ &= ~flags; + } } [[nodiscard]] std::size_t FormalParamsLength() const noexcept; @@ -310,37 +305,31 @@ public: [[nodiscard]] varbinder::FunctionScope *Scope() const noexcept override { - return scope_; + return GetHistoryNodeAs()->scope_; } - void SetScope(varbinder::FunctionScope *scope) noexcept - { - scope_ = scope; - } + void SetScope(varbinder::FunctionScope *scope); void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } [[nodiscard]] es2panda::Language Language() const noexcept { - return lang_; + return GetHistoryNodeAs()->lang_; } - void SetPreferredReturnType(checker::Type *preferredReturnType) noexcept - { - preferredReturnType_ = preferredReturnType; - } + void SetPreferredReturnType(checker::Type *preferredReturnType); [[nodiscard]] checker::Type *GetPreferredReturnType() noexcept { - return preferredReturnType_; + return GetHistoryNodeAs()->preferredReturnType_; } [[nodiscard]] checker::Type const *GetPreferredReturnType() const noexcept { - return preferredReturnType_; + return GetHistoryNodeAs()->preferredReturnType_; } [[nodiscard]] ScriptFunction *Clone(ArenaAllocator *allocator, AstNode *parent) override; @@ -373,9 +362,17 @@ public: void CleanUp() override { AstNode::CleanUp(); - signature_ = nullptr; - preferredReturnType_ = nullptr; + SetSignature(nullptr); + SetPreferredReturnType(nullptr); } + void EmplaceReturnStatements(ReturnStatement *returnStatements); + void ClearReturnStatements(); + void SetValueReturnStatements(ReturnStatement *returnStatements, size_t index); + + void EmplaceParams(Expression *params); + void ClearParams(); + void SetValueParams(Expression *params, size_t index); + ArenaVector &ParamsForUpdate(); protected: ScriptFunction *Construct(ArenaAllocator *allocator) override; diff --git a/ets2panda/ir/base/scriptFunctionSignature.h b/ets2panda/ir/base/scriptFunctionSignature.h index b3918b5fbe..65b977c962 100644 --- a/ets2panda/ir/base/scriptFunctionSignature.h +++ b/ets2panda/ir/base/scriptFunctionSignature.h @@ -24,6 +24,7 @@ namespace ark::es2panda::ir { class TSTypeParameterDeclaration; class TypeNode; class ScriptFunction; +class ETSFunctionType; class FunctionSignature { public: @@ -93,6 +94,7 @@ private: bool hasReceiver_; friend class ScriptFunction; + friend class ETSFunctionType; void CopyFrom(const FunctionSignature &other) { typeParams_ = other.typeParams_; diff --git a/ets2panda/ir/base/spreadElement.cpp b/ets2panda/ir/base/spreadElement.cpp index 1f69ae5286..a841793031 100644 --- a/ets2panda/ir/base/spreadElement.cpp +++ b/ets2panda/ir/base/spreadElement.cpp @@ -143,7 +143,7 @@ void SpreadElement::Dump(ir::SrcDumper *dumper) const dumper->Add("..."); argument_->Dump(dumper); auto type = TypeAnnotation(); - if (type != nullptr) { + if (type != nullptr && type->IsValidInCurrentPhase()) { dumper->Add(": "); type->Dump(dumper); } diff --git a/ets2panda/ir/base/spreadElement.h b/ets2panda/ir/base/spreadElement.h index 803e8e32a4..f9eefb502c 100644 --- a/ets2panda/ir/base/spreadElement.h +++ b/ets2panda/ir/base/spreadElement.h @@ -59,11 +59,6 @@ public: return decorators_; } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - void AddDecorators(ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/ets/etsFunctionType.cpp b/ets2panda/ir/ets/etsFunctionType.cpp index da4e93b20c..f2d459dce3 100644 --- a/ets2panda/ir/ets/etsFunctionType.cpp +++ b/ets2panda/ir/ets/etsFunctionType.cpp @@ -23,18 +23,13 @@ namespace ark::es2panda::ir { void ETSFunctionType::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - signature_.TransformChildren(cb, transformationName); - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + GetHistoryNodeAs()->signature_.TransformChildren(cb, transformationName); + TransformAnnotations(cb, transformationName); } void ETSFunctionType::Iterate(const NodeTraverser &cb) const { - signature_.Iterate(cb); + GetHistoryNodeAs()->signature_.Iterate(cb); for (auto *it : VectorIterationGuard(Annotations())) { cb(it); } @@ -49,9 +44,9 @@ void ETSFunctionType::Dump(ir::AstDumper *dumper) const throwMarker = "rethrows"; } dumper->Add({{"type", "ETSFunctionType"}, - {"params", signature_.Params()}, - {"typeParameters", AstDumper::Optional(signature_.TypeParams())}, - {"returnType", signature_.ReturnType()}, + {"params", Params()}, + {"typeParameters", AstDumper::Optional(TypeParams())}, + {"returnType", ReturnType()}, {"throwMarker", AstDumper::Optional(throwMarker)}, {"annotations", AstDumper::Optional(Annotations())}}); } @@ -122,19 +117,17 @@ ETSFunctionType *ETSFunctionType::Clone(ArenaAllocator *const allocator, AstNode { ArenaVector paramsClone(allocator->Adapter()); - for (auto *const param : signature_.Params()) { + for (auto *const param : Params()) { paramsClone.emplace_back(param->Clone(allocator, nullptr)->AsExpression()); } auto *const typeParamsClone = - signature_.TypeParams() != nullptr - ? signature_.TypeParams()->Clone(allocator, nullptr)->AsTSTypeParameterDeclaration() - : nullptr; + TypeParams() != nullptr ? TypeParams()->Clone(allocator, nullptr)->AsTSTypeParameterDeclaration() : nullptr; auto *const returnTypeClone = - signature_.ReturnType() != nullptr ? signature_.ReturnType()->Clone(allocator, nullptr)->AsTypeNode() : nullptr; + ReturnType() != nullptr ? ReturnType()->Clone(allocator, nullptr)->AsTypeNode() : nullptr; auto *const clone = allocator->New( - FunctionSignature(typeParamsClone, std::move(paramsClone), returnTypeClone), funcFlags_, allocator); + FunctionSignature(typeParamsClone, std::move(paramsClone), returnTypeClone), Flags(), allocator); if (typeParamsClone != nullptr) { typeParamsClone->SetParent(clone); @@ -162,8 +155,28 @@ ETSFunctionType *ETSFunctionType::Clone(ArenaAllocator *const allocator, AstNode // If the scope is set to empty, it will result in the inability to retrieve the scope after clone, // and an error cannot find type will be reported - clone->SetScope(this->scope_); + clone->SetScope(Scope()); return clone; } + +ETSFunctionType *ETSFunctionType::Construct(ArenaAllocator *allocator) +{ + auto adapter = allocator->Adapter(); + return allocator->New(FunctionSignature(nullptr, ArenaVector(adapter), nullptr), + ScriptFunctionFlags::NONE, allocator); +} + +void ETSFunctionType::CopyTo(AstNode *other) const +{ + auto otherImpl = reinterpret_cast(other); + + otherImpl->scope_ = scope_; + otherImpl->signature_.CopyFrom(signature_); + otherImpl->functionalInterface_ = functionalInterface_; + otherImpl->funcFlags_ = funcFlags_; + + TypeNode::CopyTo(other); +} + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ets/etsFunctionType.h b/ets2panda/ir/ets/etsFunctionType.h index b6ae35203b..142e16671c 100644 --- a/ets2panda/ir/ets/etsFunctionType.h +++ b/ets2panda/ir/ets/etsFunctionType.h @@ -32,6 +32,7 @@ public: ArenaAllocator *const allocator) noexcept : TypeNode(AstNodeType::ETS_FUNCTION_TYPE, allocator), signature_(std::move(signature)), funcFlags_(funcFlags) { + InitHistory(); } ETSFunctionType() = delete; @@ -46,77 +47,82 @@ public: [[nodiscard]] varbinder::Scope *Scope() const noexcept override { - return scope_; + return GetHistoryNodeAs()->scope_; } void SetScope(varbinder::Scope *scope) { - scope_ = scope; + GetOrCreateHistoryNodeAs()->scope_ = scope; } void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } const TSTypeParameterDeclaration *TypeParams() const { - return signature_.TypeParams(); + return GetHistoryNodeAs()->signature_.TypeParams(); } TSTypeParameterDeclaration *TypeParams() { - return signature_.TypeParams(); + return GetHistoryNodeAs()->signature_.TypeParams(); } const ArenaVector &Params() const { - return signature_.Params(); + return GetHistoryNodeAs()->signature_.Params(); } const TypeNode *ReturnType() const { - return signature_.ReturnType(); + return GetHistoryNodeAs()->signature_.ReturnType(); } TypeNode *ReturnType() { - return signature_.ReturnType(); + return GetHistoryNodeAs()->signature_.ReturnType(); } ir::TSInterfaceDeclaration *FunctionalInterface() { - return functionalInterface_; + return GetHistoryNodeAs()->functionalInterface_; } const ir::TSInterfaceDeclaration *FunctionalInterface() const { - return functionalInterface_; + return GetHistoryNodeAs()->functionalInterface_; } void SetFunctionalInterface(ir::TSInterfaceDeclaration *functionalInterface) { - functionalInterface_ = functionalInterface; + GetOrCreateHistoryNodeAs()->functionalInterface_ = functionalInterface; } ir::ScriptFunctionFlags Flags() { - return funcFlags_; + return GetHistoryNodeAs()->funcFlags_; + } + + ir::ScriptFunctionFlags Flags() const + { + return GetHistoryNodeAs()->funcFlags_; } bool IsThrowing() const { - return (funcFlags_ & ir::ScriptFunctionFlags::THROWS) != 0; + return (Flags() & ir::ScriptFunctionFlags::THROWS) != 0; } bool IsRethrowing() const { - return (funcFlags_ & ir::ScriptFunctionFlags::RETHROWS) != 0; + return (Flags() & ir::ScriptFunctionFlags::RETHROWS) != 0; } bool IsExtensionFunction() const { - return signature_.HasReceiver(); + return GetHistoryNodeAs()->signature_.HasReceiver(); } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -137,6 +143,10 @@ public: [[nodiscard]] ETSFunctionType *Clone(ArenaAllocator *allocator, AstNode *parent) override; +protected: + ETSFunctionType *Construct(ArenaAllocator *allocator) override; + void CopyTo(AstNode *other) const override; + private: varbinder::Scope *scope_ {}; FunctionSignature signature_; diff --git a/ets2panda/ir/ets/etsImportDeclaration.h b/ets2panda/ir/ets/etsImportDeclaration.h index 4abdaff764..7f7e56683b 100644 --- a/ets2panda/ir/ets/etsImportDeclaration.h +++ b/ets2panda/ir/ets/etsImportDeclaration.h @@ -44,31 +44,32 @@ public: void SetImportMetadata(util::ImportFlags importFlags, Language::Id lang, std::string_view resolvedSource, std::string_view declPath, std::string_view ohmUrl) { - importMetadata_.importFlags = importFlags; - importMetadata_.lang = lang; - importMetadata_.resolvedSource = resolvedSource; - importMetadata_.declPath = declPath; - importMetadata_.ohmUrl = ohmUrl; + auto node = GetOrCreateHistoryNode()->AsETSImportDeclaration(); + node->importMetadata_.importFlags = importFlags; + node->importMetadata_.lang = lang; + node->importMetadata_.resolvedSource = resolvedSource; + node->importMetadata_.declPath = declPath; + node->importMetadata_.ohmUrl = ohmUrl; } es2panda::Language Language() const { - return es2panda::Language {importMetadata_.lang}; + return es2panda::Language {ImportMetadata().lang}; } std::string_view DeclPath() const { - return importMetadata_.declPath; + return ImportMetadata().declPath; } std::string_view OhmUrl() const { - return importMetadata_.ohmUrl; + return ImportMetadata().ohmUrl; } bool IsValid() const { - return (Source()->Str() != ERROR_LITERAL) && importMetadata_.IsValid(); + return (Source()->Str() != ERROR_LITERAL) && ImportMetadata().IsValid(); } bool IsPureDynamic() const @@ -76,24 +77,24 @@ public: return IsValid() && DeclPath().empty() && Language().IsDynamic(); } - util::StringView &AssemblerName() + void SetAssemblerName(util::StringView assemblerName) { - return assemblerName_; + GetOrCreateHistoryNode()->AsETSImportDeclaration()->assemblerName_ = assemblerName; } const util::StringView &AssemblerName() const { - return assemblerName_; + return GetHistoryNode()->AsETSImportDeclaration()->assemblerName_; } std::string_view ResolvedSource() const { - return importMetadata_.resolvedSource; + return ImportMetadata().resolvedSource; } - const auto &ImportMetadata() const + const util::ImportPathManager::ImportMetadata &ImportMetadata() const { - return importMetadata_; + return GetHistoryNode()->AsETSImportDeclaration()->importMetadata_; } void Accept(ASTVisitorT *v) override @@ -101,6 +102,22 @@ public: v->Accept(this); } + ETSImportDeclaration *Construct(ArenaAllocator *allocator) override + { + ArenaVector specifiers(allocator->Adapter()); + return allocator->New(nullptr, std::move(specifiers)); + } + + void CopyTo(AstNode *other) const override + { + auto otherImpl = other->AsETSImportDeclaration(); + + otherImpl->importMetadata_ = importMetadata_; + otherImpl->assemblerName_ = assemblerName_; + + ImportDeclaration::CopyTo(other); + }; + private: util::ImportPathManager::ImportMetadata importMetadata_; util::StringView assemblerName_ {}; diff --git a/ets2panda/ir/ets/etsModule.cpp b/ets2panda/ir/ets/etsModule.cpp index 3fea029e81..4891a53166 100644 --- a/ets2panda/ir/ets/etsModule.cpp +++ b/ets2panda/ir/ets/etsModule.cpp @@ -34,7 +34,7 @@ void ETSModule::Dump(ir::SrcDumper *dumper) const } dumper->Add("namespace "); - ident_->Dump(dumper); + Ident()->Dump(dumper); dumper->Add(" {"); dumper->IncrIndent(); } @@ -67,6 +67,7 @@ void ETSModule::CopyTo(AstNode *other) const otherImpl->ident_ = ident_; otherImpl->flag_ = flag_; otherImpl->program_ = program_; + otherImpl->globalClass_ = globalClass_; JsDocAllowed>::CopyTo(other); } diff --git a/ets2panda/ir/ets/etsModule.h b/ets2panda/ir/ets/etsModule.h index 0c967d8d24..8f2bb0ecd8 100644 --- a/ets2panda/ir/ets/etsModule.h +++ b/ets2panda/ir/ets/etsModule.h @@ -54,47 +54,81 @@ public: program_(program) { type_ = AstNodeType::ETS_MODULE; + InitHistory(); + } + + // CC-OFFNXT(G.FUN.01-CPP) solid logic + explicit ETSModule(ArenaAllocator *allocator, ArenaVector &&statementList, Identifier *ident, + ModuleFlag flag, parser::Program *program, AstNodeHistory *history) + : JsDocAllowed>(allocator, std::move(statementList)), + ident_(ident), + flag_(flag), + program_(program) + { + type_ = AstNodeType::ETS_MODULE; + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } ir::Identifier *Ident() { - return ident_; + return GetHistoryNodeAs()->ident_; } const ir::Identifier *Ident() const { - return ident_; + return GetHistoryNodeAs()->ident_; } parser::Program *Program() { - return program_; + return GetHistoryNodeAs()->program_; + } + + const ir::ClassDefinition *GlobalClass() const + { + return GetHistoryNodeAs()->globalClass_; + } + + ir::ClassDefinition *GlobalClass() + { + return GetHistoryNodeAs()->globalClass_; + } + + void SetGlobalClass(ir::ClassDefinition *globalClass) + { + if (globalClass != GlobalClass()) { + GetOrCreateHistoryNode()->AsETSModule()->globalClass_ = globalClass; + } } [[nodiscard]] bool IsETSScript() const noexcept { - return (flag_ & ModuleFlag::ETSSCRIPT) != 0; + return (ModuleFlags() & ModuleFlag::ETSSCRIPT) != 0; } [[nodiscard]] bool IsNamespace() const noexcept { - return (flag_ & ModuleFlag::NAMESPACE) != 0; + return (ModuleFlags() & ModuleFlag::NAMESPACE) != 0; } [[nodiscard]] bool IsNamespaceChainLastNode() const noexcept { - return (flag_ & ModuleFlag::NAMESPACE_CHAIN_LAST_NODE) != 0; + return (ModuleFlags() & ModuleFlag::NAMESPACE_CHAIN_LAST_NODE) != 0; } void SetNamespaceChainLastNode() noexcept { ES2PANDA_ASSERT(IsNamespace()); - flag_ |= ModuleFlag::NAMESPACE_CHAIN_LAST_NODE; + AddModuleFlag(ModuleFlag::NAMESPACE_CHAIN_LAST_NODE); } const parser::Program *Program() const { - return program_; + return GetHistoryNodeAs()->program_; } void Dump(ir::SrcDumper *dumper) const override; void Accept(ASTVisitorT *v) override @@ -107,9 +141,29 @@ public: private: friend class SizeOfNodeTest; + ModuleFlag ModuleFlags() const + { + return GetHistoryNodeAs()->flag_; + } + + void AddModuleFlag(ModuleFlag flag) noexcept + { + if (!All(ModuleFlags(), flag)) { + GetOrCreateHistoryNode()->AsETSModule()->flag_ |= flag; + } + } + + void ClearModuleFlag(ModuleFlag flag) noexcept + { + if (Any(ModuleFlags(), flag)) { + GetOrCreateHistoryNode()->AsETSModule()->flag_ &= ~flag; + } + } + Identifier *ident_; ModuleFlag flag_; parser::Program *program_; + ir::ClassDefinition *globalClass_ {}; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ets/etsNeverType.cpp b/ets2panda/ir/ets/etsNeverType.cpp index 79284dd1f7..3f40e34750 100644 --- a/ets2panda/ir/ets/etsNeverType.cpp +++ b/ets2panda/ir/ets/etsNeverType.cpp @@ -21,12 +21,7 @@ namespace ark::es2panda::ir { void ETSNeverType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSNeverType::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsNullishTypes.cpp b/ets2panda/ir/ets/etsNullishTypes.cpp index e3e9e79836..0957d162a4 100644 --- a/ets2panda/ir/ets/etsNullishTypes.cpp +++ b/ets2panda/ir/ets/etsNullishTypes.cpp @@ -21,12 +21,7 @@ namespace ark::es2panda::ir { void ETSUndefinedType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSUndefinedType::Iterate([[maybe_unused]] const NodeTraverser &cb) const @@ -92,12 +87,7 @@ ETSUndefinedType *ETSUndefinedType::Clone(ArenaAllocator *allocator, AstNode *pa void ETSNullType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSNullType::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsParameterExpression.cpp b/ets2panda/ir/ets/etsParameterExpression.cpp index 382a8a6f11..672d060e2a 100644 --- a/ets2panda/ir/ets/etsParameterExpression.cpp +++ b/ets2panda/ir/ets/etsParameterExpression.cpp @@ -22,8 +22,29 @@ namespace ark::es2panda::ir { +void ETSParameterExpression::SetRequiredParams(size_t extraValue) +{ + this->GetOrCreateHistoryNodeAs()->extraValue_ = extraValue; +} + +void ETSParameterExpression::SetLexerSaved(util::StringView savedLexer) +{ + this->GetOrCreateHistoryNodeAs()->savedLexer_ = savedLexer; +} + +void ETSParameterExpression::SetSpread(SpreadElement *spread) +{ + this->GetOrCreateHistoryNodeAs()->spread_ = spread; +} + ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identOrSpread, bool isOptional, ArenaAllocator *const allocator) + : ETSParameterExpression(identOrSpread, isOptional, allocator, nullptr) +{ +} + +ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identOrSpread, bool isOptional, + ArenaAllocator *const allocator, AstNodeHistory *history) : AnnotationAllowed(AstNodeType::ETS_PARAMETER_EXPRESSION, allocator) { SetOptional(isOptional); @@ -43,125 +64,140 @@ ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identO } else { ES2PANDA_UNREACHABLE(); } + + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identOrSpread, ir::Expression *initializer, ArenaAllocator *const allocator) + : ETSParameterExpression(identOrSpread, initializer, allocator, nullptr) +{ +} + +ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identOrSpread, ir::Expression *initializer, + ArenaAllocator *const allocator, AstNodeHistory *history) : ETSParameterExpression(identOrSpread, true, allocator) { SetInitializer(initializer); + + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } const util::StringView &ETSParameterExpression::Name() const noexcept { - return ident_->Name(); + return Ident()->Name(); } const Identifier *ETSParameterExpression::Ident() const noexcept { - return ident_; + return GetHistoryNodeAs()->ident_; } Identifier *ETSParameterExpression::Ident() noexcept { - return ident_; + return GetHistoryNodeAs()->ident_; } const SpreadElement *ETSParameterExpression::RestParameter() const noexcept { - return spread_; + return GetHistoryNodeAs()->spread_; } SpreadElement *ETSParameterExpression::RestParameter() noexcept { - return spread_; + return GetHistoryNodeAs()->spread_; } const Expression *ETSParameterExpression::Initializer() const noexcept { - return initializer_; + return GetHistoryNodeAs()->initializer_; } Expression *ETSParameterExpression::Initializer() noexcept { - return initializer_; + return GetHistoryNodeAs()->initializer_; } varbinder::Variable *ETSParameterExpression::Variable() const noexcept { - return ident_->Variable(); + return Ident()->Variable(); } TypeNode const *ETSParameterExpression::TypeAnnotation() const noexcept { - return !IsRestParameter() ? ident_->TypeAnnotation() : spread_->TypeAnnotation(); + return !IsRestParameter() ? Ident()->TypeAnnotation() : Spread()->TypeAnnotation(); } TypeNode *ETSParameterExpression::TypeAnnotation() noexcept { - return !IsRestParameter() ? ident_->TypeAnnotation() : spread_->TypeAnnotation(); + return !IsRestParameter() ? Ident()->TypeAnnotation() : Spread()->TypeAnnotation(); } void ETSParameterExpression::SetTypeAnnotation(TypeNode *typeNode) noexcept { - !IsRestParameter() ? ident_->SetTsTypeAnnotation(typeNode) : spread_->SetTsTypeAnnotation(typeNode); + !IsRestParameter() ? Ident()->SetTsTypeAnnotation(typeNode) : Spread()->SetTsTypeAnnotation(typeNode); } void ETSParameterExpression::SetVariable(varbinder::Variable *const variable) noexcept { - ident_->SetVariable(variable); -} - -void ETSParameterExpression::SetLexerSaved(util::StringView s) noexcept -{ - savedLexer_ = s; + Ident()->SetVariable(variable); } util::StringView ETSParameterExpression::LexerSaved() const noexcept { - return savedLexer_; + return GetHistoryNodeAs()->savedLexer_; } void ETSParameterExpression::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { + auto const spread = Spread(); + auto const ident = Ident(); + auto newNode = GetOrCreateHistoryNodeAs(); if (IsRestParameter()) { - if (auto *transformedNode = cb(spread_); spread_ != transformedNode) { - spread_->SetTransformedNode(transformationName, transformedNode); - spread_ = transformedNode->AsRestElement(); + if (auto *transformedNode = cb(spread); spread != transformedNode) { + spread->SetTransformedNode(transformationName, transformedNode); + SetSpread(transformedNode->AsRestElement()); } - ident_ = spread_->Argument()->AsIdentifier(); + newNode->ident_ = Spread()->Argument()->AsIdentifier(); } else { - if (auto *transformedNode = cb(ident_); ident_ != transformedNode) { - ident_->SetTransformedNode(transformationName, transformedNode); - ident_ = transformedNode->AsIdentifier(); + if (auto *transformedNode = cb(ident); ident != transformedNode) { + ident->SetTransformedNode(transformationName, transformedNode); + SetIdent(transformedNode->AsIdentifier()); } } - if (initializer_ != nullptr) { - if (auto *transformedNode = cb(initializer_); initializer_ != transformedNode) { - initializer_->SetTransformedNode(transformationName, transformedNode); - initializer_ = transformedNode->AsExpression(); + auto const initializer = Initializer(); + if (initializer != nullptr) { + if (auto *transformedNode = cb(initializer); initializer != transformedNode) { + initializer->SetTransformedNode(transformationName, transformedNode); + SetInitializer(transformedNode->AsExpression()); } } - for (auto *&it : Annotations()) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSParameterExpression::Iterate(const NodeTraverser &cb) const { if (IsRestParameter()) { - cb(spread_); + auto const spread = GetHistoryNode()->AsETSParameterExpression()->spread_; + cb(spread); } else { - cb(ident_); + auto const ident = GetHistoryNode()->AsETSParameterExpression()->ident_; + cb(ident); } - if (initializer_ != nullptr) { - cb(initializer_); + auto const initializer = GetHistoryNode()->AsETSParameterExpression()->initializer_; + if (initializer != nullptr) { + cb(initializer); } for (auto *it : Annotations()) { @@ -173,12 +209,12 @@ void ETSParameterExpression::Dump(ir::AstDumper *const dumper) const { if (!IsRestParameter()) { dumper->Add({{"type", "ETSParameterExpression"}, - {"name", ident_}, - {"initializer", AstDumper::Optional(initializer_)}, + {"name", Ident()}, + {"initializer", AstDumper::Optional(Initializer())}, {"annotations", AstDumper::Optional(Annotations())}}); } else { dumper->Add({{"type", "ETSParameterExpression"}, - {"rest parameter", spread_}, + {"rest parameter", Spread()}, {"annotations", AstDumper::Optional(Annotations())}}); } } @@ -190,23 +226,25 @@ void ETSParameterExpression::Dump(ir::SrcDumper *const dumper) const } if (IsRestParameter()) { - spread_->Dump(dumper); + Spread()->Dump(dumper); } else { - if (ident_ != nullptr) { + auto const ident = Ident(); + auto const initializer = Initializer(); + if (ident != nullptr) { ES2PANDA_ASSERT(ident_->IsAnnotatedExpression()); - ident_->Dump(dumper); - if (isOptional_ && initializer_ == nullptr) { + ident->Dump(dumper); + if (IsOptional() && initializer == nullptr) { dumper->Add("?"); } - auto typeAnnotation = ident_->AsAnnotatedExpression()->TypeAnnotation(); + auto typeAnnotation = ident->AsAnnotatedExpression()->TypeAnnotation(); if (typeAnnotation != nullptr) { dumper->Add(": "); typeAnnotation->Dump(dumper); } } - if (initializer_ != nullptr) { + if (initializer != nullptr) { dumper->Add(" = "); - initializer_->Dump(dumper); + initializer->Dump(dumper); } } } @@ -233,14 +271,15 @@ checker::VerifiedType ETSParameterExpression::Check(checker::ETSChecker *const c ETSParameterExpression *ETSParameterExpression::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const identOrSpread = spread_ != nullptr ? spread_->Clone(allocator, nullptr)->AsAnnotatedExpression() - : ident_->Clone(allocator, nullptr)->AsAnnotatedExpression(); + auto *const identOrSpread = Spread() != nullptr ? Spread()->Clone(allocator, nullptr)->AsAnnotatedExpression() + : Ident()->Clone(allocator, nullptr)->AsAnnotatedExpression(); auto *const initializer = - initializer_ != nullptr ? initializer_->Clone(allocator, nullptr)->AsExpression() : nullptr; + Initializer() != nullptr ? Initializer()->Clone(allocator, nullptr)->AsExpression() : nullptr; - auto *const clone = initializer_ != nullptr + auto *const clone = Initializer() != nullptr ? allocator->New(identOrSpread, initializer, allocator) - : allocator->New(identOrSpread, isOptional_, allocator); + : allocator->New(identOrSpread, IsOptional(), allocator); + ES2PANDA_ASSERT(identOrSpread != nullptr); identOrSpread->SetParent(clone); if (initializer != nullptr) { @@ -251,7 +290,7 @@ ETSParameterExpression *ETSParameterExpression::Clone(ArenaAllocator *const allo clone->SetParent(parent); } - clone->SetRequiredParams(extraValue_); + clone->SetRequiredParams(GetRequiredParams()); if (!Annotations().empty()) { ArenaVector annotationUsages {allocator->Adapter()}; diff --git a/ets2panda/ir/ets/etsParameterExpression.h b/ets2panda/ir/ets/etsParameterExpression.h index a38f760c79..976e54149f 100644 --- a/ets2panda/ir/ets/etsParameterExpression.h +++ b/ets2panda/ir/ets/etsParameterExpression.h @@ -38,9 +38,15 @@ public: explicit ETSParameterExpression(AnnotatedExpression *identOrSpread, bool isOptional, ArenaAllocator *const allocator); + explicit ETSParameterExpression(AnnotatedExpression *identOrSpread, bool isOptional, + ArenaAllocator *const allocator, AstNodeHistory *history); + explicit ETSParameterExpression(AnnotatedExpression *identOrSpread, ir::Expression *initializer, ArenaAllocator *const allocator); + explicit ETSParameterExpression(AnnotatedExpression *identOrSpread, ir::Expression *initializer, + ArenaAllocator *const allocator, AstNodeHistory *history); + [[nodiscard]] const util::StringView &Name() const noexcept; [[nodiscard]] const Identifier *Ident() const noexcept; @@ -48,8 +54,8 @@ public: void SetIdent(Identifier *ident) noexcept { - ident_ = ident; - ident_->SetParent(this); + this->GetOrCreateHistoryNodeAs()->ident_ = ident; + ident->SetParent(this); } [[nodiscard]] const SpreadElement *RestParameter() const noexcept; @@ -58,7 +64,7 @@ public: [[nodiscard]] const Expression *Initializer() const noexcept; [[nodiscard]] Expression *Initializer() noexcept; - void SetLexerSaved(util::StringView s) noexcept; + void SetLexerSaved(util::StringView savedLexer); [[nodiscard]] util::StringView LexerSaved() const noexcept; [[nodiscard]] varbinder::Variable *Variable() const noexcept; @@ -71,35 +77,32 @@ public: [[nodiscard]] bool IsOptional() const noexcept { - return isOptional_; + return GetHistoryNodeAs()->isOptional_; } void SetOptional(bool value) noexcept { - isOptional_ = value; - ES2PANDA_ASSERT(isOptional_ || initializer_ == nullptr); + this->GetOrCreateHistoryNodeAs()->isOptional_ = value; + ES2PANDA_ASSERT(IsOptional() || Initializer() == nullptr); } void SetInitializer(Expression *initExpr) noexcept { - initializer_ = initExpr; - ES2PANDA_ASSERT(isOptional_ || initializer_ == nullptr); + this->GetOrCreateHistoryNodeAs()->initializer_ = initExpr; + ES2PANDA_ASSERT(IsOptional() || Initializer() == nullptr); } [[nodiscard]] bool IsRestParameter() const noexcept { - return spread_ != nullptr; + return Spread() != nullptr; } [[nodiscard]] std::size_t GetRequiredParams() const noexcept { - return extraValue_; + return GetHistoryNodeAs()->extraValue_; } - void SetRequiredParams(std::size_t const value) noexcept - { - extraValue_ = value; - } + void SetRequiredParams(std::size_t const extraValue); [[nodiscard]] ETSParameterExpression *Clone(ArenaAllocator *allocator, AstNode *parent) override; @@ -122,6 +125,18 @@ public: private: friend class SizeOfNodeTest; + SpreadElement *Spread() noexcept + { + return GetHistoryNodeAs()->spread_; + } + + const SpreadElement *Spread() const noexcept + { + return GetHistoryNodeAs()->spread_; + } + + void SetSpread(SpreadElement *spread); + Identifier *ident_; Expression *initializer_ = nullptr; SpreadElement *spread_ = nullptr; diff --git a/ets2panda/ir/ets/etsPrimitiveType.cpp b/ets2panda/ir/ets/etsPrimitiveType.cpp index c18f743502..c4d18a628d 100644 --- a/ets2panda/ir/ets/etsPrimitiveType.cpp +++ b/ets2panda/ir/ets/etsPrimitiveType.cpp @@ -24,12 +24,7 @@ namespace ark::es2panda::ir { void ETSPrimitiveType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSPrimitiveType::Iterate([[maybe_unused]] const NodeTraverser &cb) const @@ -109,7 +104,7 @@ checker::VerifiedType ETSPrimitiveType::Check(checker::ETSChecker *checker) checker::Type *ETSPrimitiveType::GetType([[maybe_unused]] checker::ETSChecker *checker) { - switch (type_) { + switch (GetPrimitiveType()) { case PrimitiveType::BYTE: { SetTsType(checker->GlobalByteType()); return TsType(); @@ -158,7 +153,7 @@ checker::Type *ETSPrimitiveType::GetType([[maybe_unused]] checker::ETSChecker *c ETSPrimitiveType *ETSPrimitiveType::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const clone = allocator->New(type_, allocator); + auto *const clone = allocator->New(GetPrimitiveType(), allocator); if (parent != nullptr) { clone->SetParent(parent); diff --git a/ets2panda/ir/ets/etsPrimitiveType.h b/ets2panda/ir/ets/etsPrimitiveType.h index 49e9d73cc3..e26ae82974 100644 --- a/ets2panda/ir/ets/etsPrimitiveType.h +++ b/ets2panda/ir/ets/etsPrimitiveType.h @@ -16,6 +16,7 @@ #ifndef ES2PANDA_IR_ETS_PRIMITIVE_TYPE_H #define ES2PANDA_IR_ETS_PRIMITIVE_TYPE_H +#include "ir/base/methodDefinition.h" #include "ir/typeNode.h" namespace ark::es2panda::ir { @@ -26,11 +27,12 @@ public: explicit ETSPrimitiveType(PrimitiveType type, ArenaAllocator *const allocator) : TypeNode(AstNodeType::ETS_PRIMITIVE_TYPE, allocator), type_(type) { + InitHistory(); } PrimitiveType GetPrimitiveType() const { - return type_; + return GetHistoryNodeAs()->type_; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -51,6 +53,21 @@ public: [[nodiscard]] ETSPrimitiveType *Clone(ArenaAllocator *allocator, AstNode *parent) override; +protected: + ETSPrimitiveType *Construct(ArenaAllocator *allocator) override + { + return allocator->New(PrimitiveType::VOID, allocator); + } + + void CopyTo(AstNode *other) const override + { + auto otherImpl = reinterpret_cast(other); + + otherImpl->type_ = type_; + + TypeNode::CopyTo(other); + } + private: PrimitiveType type_; }; diff --git a/ets2panda/ir/ets/etsReExportDeclaration.cpp b/ets2panda/ir/ets/etsReExportDeclaration.cpp index c5df1d644b..4475c8b08c 100644 --- a/ets2panda/ir/ets/etsReExportDeclaration.cpp +++ b/ets2panda/ir/ets/etsReExportDeclaration.cpp @@ -19,6 +19,11 @@ namespace ark::es2panda::ir { +void ETSReExportDeclaration::SetETSImportDeclarations(ETSImportDeclaration *etsImportDeclarations) +{ + this->GetOrCreateHistoryNodeAs()->etsImportDeclarations_ = etsImportDeclarations; +} + ETSReExportDeclaration::ETSReExportDeclaration(ETSImportDeclaration *etsImportDeclarations, const std::vector &userPaths, util::StringView programPath, ArenaAllocator *allocator) @@ -30,26 +35,29 @@ ETSReExportDeclaration::ETSReExportDeclaration(ETSImportDeclaration *etsImportDe for (const auto &path : userPaths) { userPaths_.emplace_back(util::UString(path, allocator).View()); } + InitHistory(); } void ETSReExportDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (etsImportDeclarations_ != nullptr) { - if (auto *transformedNode = cb(etsImportDeclarations_); etsImportDeclarations_ != transformedNode) { - etsImportDeclarations_->SetTransformedNode(transformationName, transformedNode); - etsImportDeclarations_ = transformedNode->AsETSImportDeclaration(); + auto const etsImportDecl = GetETSImportDeclarations(); + if (etsImportDecl != nullptr) { + if (auto *transformedNode = cb(etsImportDecl); etsImportDecl != transformedNode) { + etsImportDecl->SetTransformedNode(transformationName, transformedNode); + SetETSImportDeclarations(transformedNode->AsETSImportDeclaration()); } } + InitHistory(); } void ETSReExportDeclaration::Iterate(const NodeTraverser &cb) const { - etsImportDeclarations_->Iterate(cb); + GetETSImportDeclarations()->Iterate(cb); } void ETSReExportDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ETSReExportDeclaration"}, {"ets_import_declarations", etsImportDeclarations_}}); + dumper->Add({{"type", "ETSReExportDeclaration"}, {"ets_import_declarations", GetETSImportDeclarations()}}); } void ETSReExportDeclaration::Dump([[maybe_unused]] ir::SrcDumper *dumper) const @@ -82,14 +90,16 @@ checker::VerifiedType ETSReExportDeclaration::Check(checker::ETSChecker * /*chec return {this, nullptr}; } -AstNode *ETSReExportDeclaration::Construct(ArenaAllocator *allocator) +ETSReExportDeclaration *ETSReExportDeclaration::Construct(ArenaAllocator *allocator) { - return allocator->New(nullptr, std::vector {}, util::StringView {}, allocator); + std::vector userPaths; + return allocator->New(nullptr, std::move(userPaths), + util::UString(std::string(), allocator).View(), allocator); } void ETSReExportDeclaration::CopyTo(AstNode *other) const { - auto otherImpl = other->AsETSReExportDeclaration(); + auto otherImpl = reinterpret_cast(other); otherImpl->etsImportDeclarations_ = etsImportDeclarations_; otherImpl->userPaths_ = userPaths_; diff --git a/ets2panda/ir/ets/etsReExportDeclaration.h b/ets2panda/ir/ets/etsReExportDeclaration.h index 48d7e65459..cb43dc8708 100644 --- a/ets2panda/ir/ets/etsReExportDeclaration.h +++ b/ets2panda/ir/ets/etsReExportDeclaration.h @@ -31,22 +31,22 @@ public: ETSImportDeclaration *GetETSImportDeclarations() const { - return etsImportDeclarations_; + return GetHistoryNodeAs()->etsImportDeclarations_; } ETSImportDeclaration *GetETSImportDeclarations() { - return etsImportDeclarations_; + return GetHistoryNodeAs()->etsImportDeclarations_; } const ArenaVector &GetUserPaths() const { - return userPaths_; + return GetHistoryNodeAs()->userPaths_; } util::StringView const &GetProgramPath() const { - return programPath_; + return GetHistoryNodeAs()->programPath_; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -73,8 +73,9 @@ public: } protected: - AstNode *Construct(ArenaAllocator *allocator) override; + ETSReExportDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + void SetETSImportDeclarations(ETSImportDeclaration *etsImportDeclarations); private: friend class SizeOfNodeTest; diff --git a/ets2panda/ir/ets/etsStringLiteralType.cpp b/ets2panda/ir/ets/etsStringLiteralType.cpp index d6227f2673..178160de40 100644 --- a/ets2panda/ir/ets/etsStringLiteralType.cpp +++ b/ets2panda/ir/ets/etsStringLiteralType.cpp @@ -21,12 +21,7 @@ namespace ark::es2panda::ir { void ETSStringLiteralType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSStringLiteralType::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsStructDeclaration.h b/ets2panda/ir/ets/etsStructDeclaration.h index 538797da5d..1ee72040a3 100644 --- a/ets2panda/ir/ets/etsStructDeclaration.h +++ b/ets2panda/ir/ets/etsStructDeclaration.h @@ -30,6 +30,17 @@ public: explicit ETSStructDeclaration(ClassDefinition *const def, ArenaAllocator *const allocator) : ClassDeclaration(AstNodeType::STRUCT_DECLARATION, def, allocator) { + InitHistory(); + } + + explicit ETSStructDeclaration(ClassDefinition *const def, ArenaAllocator *const allocator, AstNodeHistory *history) + : ClassDeclaration(AstNodeType::STRUCT_DECLARATION, def, allocator) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } void Dump(ir::AstDumper *dumper) const override; @@ -42,6 +53,16 @@ public: { v->Accept(this); } + + ETSStructDeclaration *Construct(ArenaAllocator *allocator) override + { + return allocator->New(nullptr, allocator); + } + + void CopyTo(AstNode *other) const override + { + ClassDeclaration::CopyTo(other); + }; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ets/etsTuple.cpp b/ets2panda/ir/ets/etsTuple.cpp index b79654c62e..79b9e906fb 100644 --- a/ets2panda/ir/ets/etsTuple.cpp +++ b/ets2panda/ir/ets/etsTuple.cpp @@ -29,12 +29,7 @@ void ETSTuple::TransformChildren(const NodeTransformer &cb, std::string_view con } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSTuple::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsTypeReference.cpp b/ets2panda/ir/ets/etsTypeReference.cpp index 21db7e1814..7986198c72 100644 --- a/ets2panda/ir/ets/etsTypeReference.cpp +++ b/ets2panda/ir/ets/etsTypeReference.cpp @@ -21,23 +21,27 @@ #include "compiler/core/pandagen.h" namespace ark::es2panda::ir { + +void ETSTypeReference::SetPart(ETSTypeReferencePart *part) +{ + this->GetOrCreateHistoryNodeAs()->part_ = part; +} + void ETSTypeReference::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (auto *transformedNode = cb(part_); part_ != transformedNode) { - part_->SetTransformedNode(transformationName, transformedNode); - part_ = transformedNode->AsETSTypeReferencePart(); - } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } + auto const part = Part(); + if (auto *transformedNode = cb(part); part != transformedNode) { + part->SetTransformedNode(transformationName, transformedNode); + SetPart(transformedNode->AsETSTypeReferencePart()); } + + TransformAnnotations(cb, transformationName); } void ETSTypeReference::Iterate(const NodeTraverser &cb) const { - cb(part_); + auto const part = GetHistoryNodeAs()->part_; + cb(part); for (auto *it : VectorIterationGuard(Annotations())) { cb(it); } @@ -45,7 +49,7 @@ void ETSTypeReference::Iterate(const NodeTraverser &cb) const ir::Identifier *ETSTypeReference::BaseName() const { - ir::ETSTypeReferencePart *partIter = part_; + ir::ETSTypeReferencePart *partIter = Part(); while (partIter->Previous() != nullptr) { partIter = partIter->Previous(); @@ -68,7 +72,7 @@ ir::Identifier *ETSTypeReference::BaseName() const void ETSTypeReference::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ETSTypeReference"}, {"part", part_}, {"annotations", AstDumper::Optional(Annotations())}}); + dumper->Add({{"type", "ETSTypeReference"}, {"part", Part()}, {"annotations", AstDumper::Optional(Annotations())}}); } void ETSTypeReference::Dump(ir::SrcDumper *dumper) const @@ -76,8 +80,8 @@ void ETSTypeReference::Dump(ir::SrcDumper *dumper) const for (auto *anno : Annotations()) { anno->Dump(dumper); } - ES2PANDA_ASSERT(part_ != nullptr); - part_->Dump(dumper); + ES2PANDA_ASSERT(Part() != nullptr); + Part()->Dump(dumper); } void ETSTypeReference::Compile(compiler::PandaGen *pg) const @@ -103,7 +107,7 @@ checker::Type *ETSTypeReference::GetType(checker::ETSChecker *checker) if (TsType() != nullptr) { return TsType(); } - auto *type = part_->GetType(checker); + auto *type = Part()->GetType(checker); if (IsReadonlyType()) { type = checker->GetReadonlyType(type); } @@ -112,14 +116,14 @@ checker::Type *ETSTypeReference::GetType(checker::ETSChecker *checker) ETSTypeReference *ETSTypeReference::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const partClone = part_ != nullptr ? part_->Clone(allocator, nullptr)->AsETSTypeReferencePart() : nullptr; + auto *const partClone = Part() != nullptr ? Part()->Clone(allocator, nullptr)->AsETSTypeReferencePart() : nullptr; auto *const clone = allocator->New(partClone, allocator); if (partClone != nullptr) { partClone->SetParent(clone); } - clone->flags_ = flags_; + clone->flags_ = Modifiers(); if (parent != nullptr) { clone->SetParent(parent); diff --git a/ets2panda/ir/ets/etsTypeReference.h b/ets2panda/ir/ets/etsTypeReference.h index f100af2e56..a69e3679fe 100644 --- a/ets2panda/ir/ets/etsTypeReference.h +++ b/ets2panda/ir/ets/etsTypeReference.h @@ -25,16 +25,27 @@ public: explicit ETSTypeReference(ir::ETSTypeReferencePart *part, ArenaAllocator *const allocator) : TypeNode(AstNodeType::ETS_TYPE_REFERENCE, allocator), part_(part) { + InitHistory(); + } + + explicit ETSTypeReference(ir::ETSTypeReferencePart *part, ArenaAllocator *const allocator, AstNodeHistory *history) + : TypeNode(AstNodeType::ETS_TYPE_REFERENCE, allocator), part_(part) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } ir::ETSTypeReferencePart *Part() { - return part_; + return GetHistoryNodeAs()->part_; } ir::ETSTypeReferencePart *Part() const { - return part_; + return GetHistoryNodeAs()->part_; } ir::Identifier *BaseName() const; @@ -61,6 +72,8 @@ public: private: friend class SizeOfNodeTest; + void SetPart(ETSTypeReferencePart *part); + ir::ETSTypeReferencePart *part_; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ets/etsTypeReferencePart.cpp b/ets2panda/ir/ets/etsTypeReferencePart.cpp index e0686ef076..befb996682 100644 --- a/ets2panda/ir/ets/etsTypeReferencePart.cpp +++ b/ets2panda/ir/ets/etsTypeReferencePart.cpp @@ -22,55 +22,79 @@ #include "compiler/core/pandagen.h" namespace ark::es2panda::ir { + +void ETSTypeReferencePart::SetName(Expression *name) +{ + this->GetOrCreateHistoryNodeAs()->name_ = name; +} + +void ETSTypeReferencePart::SetTypeParams(TSTypeParameterInstantiation *typeParams) +{ + this->GetOrCreateHistoryNodeAs()->typeParams_ = typeParams; +} + +void ETSTypeReferencePart::SetPrevious(ETSTypeReferencePart *prev) +{ + this->GetOrCreateHistoryNodeAs()->prev_ = prev; +} + void ETSTypeReferencePart::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (auto *transformedNode = cb(name_); name_ != transformedNode) { - name_->SetTransformedNode(transformationName, transformedNode); - name_ = transformedNode->AsExpression(); + auto const name = Name(); + if (name != nullptr) { + if (auto *transformedNode = cb(name); name != transformedNode) { + name->SetTransformedNode(transformationName, transformedNode); + SetName(transformedNode->AsExpression()); + } } - if (typeParams_ != nullptr) { - if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) { - typeParams_->SetTransformedNode(transformationName, transformedNode); - typeParams_ = transformedNode->AsTSTypeParameterInstantiation(); + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { + if (auto *transformedNode = cb(typeParams); typeParams != transformedNode) { + typeParams->SetTransformedNode(transformationName, transformedNode); + SetTypeParams(transformedNode->AsTSTypeParameterInstantiation()); } } - if (prev_ != nullptr) { - if (auto *transformedNode = cb(prev_); prev_ != transformedNode) { - prev_->SetTransformedNode(transformationName, transformedNode); - prev_ = transformedNode->AsETSTypeReferencePart(); + auto const prev = Previous(); + if (prev != nullptr) { + if (auto *transformedNode = cb(prev); prev != transformedNode) { + prev->SetTransformedNode(transformationName, transformedNode); + SetPrevious(transformedNode->AsETSTypeReferencePart()); } } } void ETSTypeReferencePart::Iterate(const NodeTraverser &cb) const { - cb(name_); + auto const name = GetHistoryNodeAs()->name_; + cb(name); - if (typeParams_ != nullptr) { - cb(typeParams_); + auto const typeParams = GetHistoryNodeAs()->typeParams_; + if (typeParams != nullptr) { + cb(typeParams); } - if (prev_ != nullptr) { - cb(prev_); + auto const prev = GetHistoryNodeAs()->prev_; + if (prev != nullptr) { + cb(prev); } } void ETSTypeReferencePart::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "ETSTypeReferencePart"}, - {"name", name_}, - {"typeParams", AstDumper::Optional(typeParams_)}, - {"previous", AstDumper::Optional(prev_)}}); + {"name", Name()}, + {"typeParams", AstDumper::Optional(TypeParams())}, + {"previous", AstDumper::Optional(Previous())}}); } void ETSTypeReferencePart::Dump(ir::SrcDumper *dumper) const { - ES2PANDA_ASSERT(name_ != nullptr); - name_->Dump(dumper); - if (typeParams_ != nullptr) { - typeParams_->Dump(dumper); + ES2PANDA_ASSERT(Name() != nullptr); + Name()->Dump(dumper); + if (TypeParams() != nullptr) { + TypeParams()->Dump(dumper); } } @@ -95,24 +119,25 @@ checker::VerifiedType ETSTypeReferencePart::Check(checker::ETSChecker *checker) checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *const checker) { - ES2PANDA_ASSERT(name_->IsIdentifier() || name_->IsTSQualifiedName()); + auto const name = Name(); + ES2PANDA_ASSERT(name->IsIdentifier() || name->IsTSQualifiedName()); Identifier *ident = GetIdent(); varbinder::Variable *variable = nullptr; - if (name_->IsIdentifier()) { + if (name->IsIdentifier()) { variable = ident->Variable(); } else { - if (name_->AsTSQualifiedName()->Left()->Variable() != nullptr && - name_->AsTSQualifiedName()->Left()->Variable()->TsType() != nullptr && - name_->AsTSQualifiedName()->Left()->Variable()->TsType()->IsETSObjectType()) { - variable = name_->AsTSQualifiedName()->Left()->Variable()->TsType()->AsETSObjectType()->GetProperty( + if (name->AsTSQualifiedName()->Left()->Variable() != nullptr && + name->AsTSQualifiedName()->Left()->Variable()->TsType() != nullptr && + name->AsTSQualifiedName()->Left()->Variable()->TsType()->IsETSObjectType()) { + variable = name->AsTSQualifiedName()->Left()->Variable()->TsType()->AsETSObjectType()->GetProperty( ident->Name(), checker::PropertySearchFlags::SEARCH_DECL); } } if (variable != nullptr && variable->Declaration()->IsTypeAliasDecl()) { - return checker->HandleTypeAlias(name_, typeParams_, + return checker->HandleTypeAlias(name, TypeParams(), variable->Declaration()->AsTypeAliasDecl()->Node()->AsTSTypeAliasDeclaration()); } @@ -130,7 +155,7 @@ checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *co if (ident->Name() == compiler::Signatures::READONLY_TYPE_NAME || ident->Name() == compiler::Signatures::REQUIRED_TYPE_NAME) { - return checker->HandleUtilityTypeParameterNode(typeParams_, ident); + return checker->HandleUtilityTypeParameterNode(TypeParams(), ident); } if (ident->Name() == compiler::Signatures::PARTIAL_TYPE_NAME) { @@ -150,11 +175,12 @@ checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *co checker::Type *ETSTypeReferencePart::HandleFixedArrayType(checker::ETSChecker *const checker) { - if (typeParams_ == nullptr || typeParams_->Params().size() != 1) { + auto const typeParams = TypeParams(); + if (typeParams == nullptr || typeParams->Params().size() != 1) { checker->LogError(diagnostic::FIXED_ARRAY_PARAM_ERROR, {}, Start()); return checker->GlobalTypeError(); } - checker::Type *type = checker->CreateETSArrayType(typeParams_->Params()[0]->GetType(checker), IsReadonlyType()); + checker::Type *type = checker->CreateETSArrayType(typeParams->Params()[0]->GetType(checker), IsReadonlyType()); SetTsType(type); return type; } @@ -162,14 +188,15 @@ checker::Type *ETSTypeReferencePart::HandleFixedArrayType(checker::ETSChecker *c checker::Type *ETSTypeReferencePart::HandlePartialType(checker::ETSChecker *const checker, const Identifier *const ident) { - auto *baseType = checker->HandleUtilityTypeParameterNode(typeParams_, ident); + auto const typeParams = TypeParams(); + auto *baseType = checker->HandleUtilityTypeParameterNode(typeParams, ident); if (baseType != nullptr && baseType->IsETSObjectType() && !baseType->AsETSObjectType()->TypeArguments().empty()) { // we treat Partial> class as a different copy from A now, // but not a generic type param for Partial<> - if (typeParams_ != nullptr) { - for (auto &typeRef : typeParams_->Params()) { + if (typeParams != nullptr) { + for (auto &typeRef : typeParams->Params()) { checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), - typeRef->AsETSTypeReference()->Part()->typeParams_, Start()); + typeRef->AsETSTypeReference()->Part()->TypeParams(), Start()); baseType = ctx.Result(); } } @@ -187,35 +214,37 @@ checker::Type *ETSTypeReferencePart::GetType(checker::ETSChecker *checker) } } } - if (prev_ == nullptr) { - if (name_->IsIdentifier() || name_->IsTSQualifiedName()) { + auto const name = Name(); + if (Previous() == nullptr) { + if (name->IsIdentifier() || name->IsTSQualifiedName()) { SetTsType(HandleInternalTypes(checker)); } if (TsType() == nullptr) { - checker::Type *baseType = checker->GetReferencedTypeBase(name_); + checker::Type *baseType = checker->GetReferencedTypeBase(name); ES2PANDA_ASSERT(baseType != nullptr); if (baseType->IsETSObjectType()) { - checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), typeParams_, Start()); + checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), TypeParams(), Start()); SetTsType(ctx.Result()); } else { SetTsType(baseType); } } } else { - checker::Type *baseType = prev_->GetType(checker); - SetTsType(checker->GetReferencedTypeFromBase(baseType, name_)); + checker::Type *baseType = Previous()->GetType(checker); + SetTsType(checker->GetReferencedTypeFromBase(baseType, name)); } return TsType(); } ETSTypeReferencePart *ETSTypeReferencePart::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const nameClone = name_ != nullptr ? name_->Clone(allocator, nullptr)->AsExpression() : nullptr; + auto *const nameClone = Name() != nullptr ? Name()->Clone(allocator, nullptr)->AsExpression() : nullptr; auto *const typeParamsClone = - typeParams_ != nullptr ? typeParams_->Clone(allocator, nullptr)->AsTSTypeParameterInstantiation() : nullptr; - auto *const prevClone = prev_ != nullptr ? prev_->Clone(allocator, nullptr)->AsETSTypeReferencePart() : nullptr; + TypeParams() != nullptr ? TypeParams()->Clone(allocator, nullptr)->AsTSTypeParameterInstantiation() : nullptr; + auto *const prevClone = + Previous() != nullptr ? Previous()->Clone(allocator, nullptr)->AsETSTypeReferencePart() : nullptr; auto *const clone = allocator->New(nameClone, typeParamsClone, prevClone, allocator); if (nameClone != nullptr) { @@ -240,12 +269,13 @@ ETSTypeReferencePart *ETSTypeReferencePart::Clone(ArenaAllocator *const allocato ir::Identifier *ETSTypeReferencePart::GetIdent() { - if (name_->IsTSQualifiedName()) { - auto ident = name_->AsTSQualifiedName()->Right(); + auto const name = Name(); + if (name->IsTSQualifiedName()) { + auto ident = name->AsTSQualifiedName()->Right(); ES2PANDA_ASSERT(ident->IsIdentifier()); return ident->AsIdentifier(); } - return name_->AsIdentifier(); + return name->AsIdentifier(); } ETSTypeReferencePart *ETSTypeReferencePart::Construct(ArenaAllocator *allocator) diff --git a/ets2panda/ir/ets/etsTypeReferencePart.h b/ets2panda/ir/ets/etsTypeReferencePart.h index 4b1e6aba37..54a2156b99 100644 --- a/ets2panda/ir/ets/etsTypeReferencePart.h +++ b/ets2panda/ir/ets/etsTypeReferencePart.h @@ -26,36 +26,65 @@ public: ir::ETSTypeReferencePart *prev, ArenaAllocator *const allocator) : TypeNode(AstNodeType::ETS_TYPE_REFERENCE_PART, allocator), name_(name), typeParams_(typeParams), prev_(prev) { + InitHistory(); } explicit ETSTypeReferencePart(ir::Expression *name, ArenaAllocator *const allocator) : TypeNode(AstNodeType::ETS_TYPE_REFERENCE_PART, allocator), name_(name) { + InitHistory(); + } + + explicit ETSTypeReferencePart(ir::Expression *name, ArenaAllocator *const allocator, AstNodeHistory *history) + : TypeNode(AstNodeType::ETS_TYPE_REFERENCE_PART, allocator), name_(name) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } + } + + explicit ETSTypeReferencePart(ir::Expression *name, ir::TSTypeParameterInstantiation *typeParams, + ir::ETSTypeReferencePart *prev, ArenaAllocator *const allocator, + AstNodeHistory *history) + : TypeNode(AstNodeType::ETS_TYPE_REFERENCE_PART, allocator), name_(name), typeParams_(typeParams), prev_(prev) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } ir::ETSTypeReferencePart *Previous() { - return prev_; + return GetHistoryNodeAs()->prev_; } const ir::ETSTypeReferencePart *Previous() const { - return prev_; + return GetHistoryNodeAs()->prev_; } ir::Expression *Name() { - return name_; + return GetHistoryNodeAs()->name_; } ir::TSTypeParameterInstantiation *TypeParams() { - return typeParams_; + return GetHistoryNodeAs()->typeParams_; + } + + const ir::TSTypeParameterInstantiation *TypeParams() const + { + return GetHistoryNodeAs()->typeParams_; } const ir::Expression *Name() const { - return name_; + return GetHistoryNodeAs()->name_; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -85,6 +114,10 @@ private: checker::Type *HandleFixedArrayType(checker::ETSChecker *const checker); friend class SizeOfNodeTest; + void SetName(ir::Expression *name); + void SetTypeParams(ir::TSTypeParameterInstantiation *typeParams); + void SetPrevious(ir::ETSTypeReferencePart *prev); + ir::Expression *name_; ir::TSTypeParameterInstantiation *typeParams_ {}; ir::ETSTypeReferencePart *prev_ {}; diff --git a/ets2panda/ir/ets/etsUnionType.cpp b/ets2panda/ir/ets/etsUnionType.cpp index 39860832e4..de035bcd61 100644 --- a/ets2panda/ir/ets/etsUnionType.cpp +++ b/ets2panda/ir/ets/etsUnionType.cpp @@ -20,23 +20,20 @@ namespace ark::es2panda::ir { void ETSUnionType::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(types_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = static_cast(transformedNode); - } - } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + auto const &types = Types(); + for (size_t ix = 0; ix < types.size(); ix++) { + if (auto *transformedNode = cb(types[ix]); types[ix] != transformedNode) { + types[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueTypes(static_cast(transformedNode), ix); } } + + TransformAnnotations(cb, transformationName); } void ETSUnionType::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(types_)) { + for (auto *it : VectorIterationGuard(Types())) { cb(it); } @@ -47,7 +44,7 @@ void ETSUnionType::Iterate(const NodeTraverser &cb) const void ETSUnionType::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ETSUnionType"}, {"types", types_}, {"annotations", AstDumper::Optional(Annotations())}}); + dumper->Add({{"type", "ETSUnionType"}, {"types", Types()}, {"annotations", AstDumper::Optional(Annotations())}}); } void ETSUnionType::Dump(ir::SrcDumper *dumper) const @@ -55,9 +52,9 @@ void ETSUnionType::Dump(ir::SrcDumper *dumper) const for (auto *anno : Annotations()) { anno->Dump(dumper); } - for (auto type : types_) { + for (auto type : Types()) { type->Dump(dumper); - if (type != types_.back()) { + if (type != Types().back()) { dumper->Add(" | "); } } @@ -72,7 +69,7 @@ checker::Type *ETSUnionType::Check([[maybe_unused]] checker::TSChecker *checker) checker::VerifiedType ETSUnionType::Check(checker::ETSChecker *checker) { - for (auto *it : types_) { + for (auto *it : Types()) { it->Check(checker); } @@ -98,7 +95,7 @@ checker::Type *ETSUnionType::GetType(checker::ETSChecker *checker) ArenaVector types(checker->Allocator()->Adapter()); - for (auto *it : types_) { + for (auto *it : Types()) { types.push_back(it->GetType(checker)); } @@ -115,7 +112,7 @@ checker::Type *ETSUnionType::GetType(checker::ETSChecker *checker) ETSUnionType *ETSUnionType::Clone(ArenaAllocator *const allocator, AstNode *const parent) { ArenaVector types(allocator->Adapter()); - for (auto *it : types_) { + for (auto *it : Types()) { auto *type = it->Clone(allocator, nullptr); types.push_back(type); } @@ -131,7 +128,7 @@ ETSUnionType *ETSUnionType::Clone(ArenaAllocator *const allocator, AstNode *cons } clone->SetAnnotations(std::move(annotationUsages)); } - for (auto *it : clone->types_) { + for (auto *it : clone->Types()) { it->SetParent(clone); } diff --git a/ets2panda/ir/ets/etsUnionType.h b/ets2panda/ir/ets/etsUnionType.h index 4bc14986b3..21a06d8ef1 100644 --- a/ets2panda/ir/ets/etsUnionType.h +++ b/ets2panda/ir/ets/etsUnionType.h @@ -24,11 +24,17 @@ public: explicit ETSUnionType(ArenaVector &&types, ArenaAllocator *const allocator) : TypeNode(AstNodeType::ETS_UNION_TYPE, allocator), types_(std::move(types)) { + InitHistory(); } const ArenaVector &Types() const { - return types_; + return GetHistoryNodeAs()->types_; + } + + void SetValueTypes(TypeNode *type, size_t index) const + { + GetOrCreateHistoryNodeAs()->types_[index] = type; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -47,6 +53,22 @@ public: [[nodiscard]] ETSUnionType *Clone(ArenaAllocator *allocator, AstNode *parent) override; +protected: + ETSUnionType *Construct(ArenaAllocator *allocator) override + { + ArenaVector types(allocator->Adapter()); + return allocator->New(std::move(types), allocator); + } + + void CopyTo(AstNode *other) const override + { + auto otherImpl = reinterpret_cast(other); + + otherImpl->types_ = types_; + + TypeNode::CopyTo(other); + } + private: ArenaVector types_; }; diff --git a/ets2panda/ir/ets/etsWildcardType.cpp b/ets2panda/ir/ets/etsWildcardType.cpp index 24000a8aa5..ab5ffc9e50 100644 --- a/ets2panda/ir/ets/etsWildcardType.cpp +++ b/ets2panda/ir/ets/etsWildcardType.cpp @@ -32,12 +32,8 @@ void ETSWildcardType::TransformChildren(const NodeTransformer &cb, std::string_v typeReference_ = transformedNode->AsETSTypeReference(); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void ETSWildcardType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/expression.h b/ets2panda/ir/expression.h index 52b74a8329..00c10eaec8 100644 --- a/ets2panda/ir/expression.h +++ b/ets2panda/ir/expression.h @@ -33,24 +33,26 @@ public: [[nodiscard]] bool IsGrouped() const noexcept { - return grouped_; + return AstNode::GetHistoryNodeAs()->grouped_; } void SetGrouped() noexcept { - grouped_ = true; + if (!IsGrouped()) { + AstNode::GetOrCreateHistoryNodeAs()->grouped_ = true; + } } [[nodiscard]] const Literal *AsLiteral() const { ES2PANDA_ASSERT(IsLiteral()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] Literal *AsLiteral() { ES2PANDA_ASSERT(IsLiteral()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] virtual bool IsLiteral() const noexcept @@ -76,25 +78,25 @@ public: [[nodiscard]] TypeNode *AsTypeNode() { ES2PANDA_ASSERT(IsTypeNode()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] const TypeNode *AsTypeNode() const { ES2PANDA_ASSERT(IsTypeNode()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] AnnotatedExpression *AsAnnotatedExpression() { ES2PANDA_ASSERT(IsAnnotatedExpression()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] const AnnotatedExpression *AsAnnotatedExpression() const { ES2PANDA_ASSERT(IsAnnotatedExpression()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } bool IsBrokenExpression() const noexcept; @@ -109,7 +111,7 @@ protected: Expression(Expression const &other) : TypedAstNode(static_cast(other)) { - grouped_ = other.grouped_; + grouped_ = other.IsGrouped(); } private: @@ -150,12 +152,12 @@ public: [[nodiscard]] bool IsOptional() const noexcept { - return optional_; + return GetHistoryNodeAs()->optional_; } void ClearOptional() noexcept { - optional_ = false; + GetOrCreateHistoryNodeAs()->optional_ = false; } protected: diff --git a/ets2panda/ir/expressions/arrayExpression.h b/ets2panda/ir/expressions/arrayExpression.h index 2cc1924a89..2af3767f2b 100644 --- a/ets2panda/ir/expressions/arrayExpression.h +++ b/ets2panda/ir/expressions/arrayExpression.h @@ -119,11 +119,6 @@ public: return decorators_; } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/expressions/arrowFunctionExpression.cpp b/ets2panda/ir/expressions/arrowFunctionExpression.cpp index c4941954ec..772cf69fc0 100644 --- a/ets2panda/ir/expressions/arrowFunctionExpression.cpp +++ b/ets2panda/ir/expressions/arrowFunctionExpression.cpp @@ -28,12 +28,7 @@ void ArrowFunctionExpression::TransformChildren(const NodeTransformer &cb, std:: func_ = transformedNode->AsScriptFunction(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ArrowFunctionExpression::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/expressions/callExpression.h b/ets2panda/ir/expressions/callExpression.h index 3d7f231a15..1dc57dca97 100644 --- a/ets2panda/ir/expressions/callExpression.h +++ b/ets2panda/ir/expressions/callExpression.h @@ -17,7 +17,9 @@ #define ES2PANDA_IR_EXPRESSION_CALL_EXPRESSION_H #include "varbinder/variable.h" +#include "ir/base/scriptFunction.h" #include "ir/expression.h" +#include "ir/expressions/arrowFunctionExpression.h" namespace ark::es2panda::checker { class ETSAnalyzer; @@ -184,6 +186,9 @@ public: AstNode::CleanUp(); signature_ = nullptr; uncheckedType_ = nullptr; + if (IsTransformedFromTrailingCall()) { + RetrieveTrailingBlock(); + } } private: @@ -193,6 +198,19 @@ private: bool isBlockInNewLine {false}; }; + bool IsTransformedFromTrailingCall() + { + return !arguments_.empty() && arguments_.back()->IsArrowFunctionExpression() && + arguments_.back()->AsArrowFunctionExpression()->Function()->IsTrailingLambda(); + } + + void RetrieveTrailingBlock() + { + SetTrailingBlock(arguments_.back()->AsArrowFunctionExpression()->Function()->Body()->AsBlockStatement()); + trailingLambdaInfo_.isTrailingCall = false; + arguments_.pop_back(); + } + protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) Expression *callee_; diff --git a/ets2panda/ir/expressions/identifier.cpp b/ets2panda/ir/expressions/identifier.cpp index ad06be7bfb..b5c0e1b6ed 100644 --- a/ets2panda/ir/expressions/identifier.cpp +++ b/ets2panda/ir/expressions/identifier.cpp @@ -30,11 +30,13 @@ Identifier::Identifier([[maybe_unused]] Tag const tag, Identifier const &other, for (auto *decorator : other.decorators_) { decorators_.emplace_back(decorator->Clone(allocator, this)); } + InitHistory(); } Identifier::Identifier(ArenaAllocator *const allocator) : Identifier(ERROR_LITERAL, allocator) { flags_ |= IdentifierFlags::ERROR_PLACEHOLDER; + InitHistory(); } Identifier::Identifier(util::StringView const name, ArenaAllocator *const allocator) @@ -43,6 +45,7 @@ Identifier::Identifier(util::StringView const name, ArenaAllocator *const alloca if (name == ERROR_LITERAL) { flags_ |= IdentifierFlags::ERROR_PLACEHOLDER; } + InitHistory(); } Identifier::Identifier(util::StringView const name, TypeNode *const typeAnnotation, ArenaAllocator *const allocator) @@ -51,12 +54,13 @@ Identifier::Identifier(util::StringView const name, TypeNode *const typeAnnotati if (name == ERROR_LITERAL) { flags_ |= IdentifierFlags::ERROR_PLACEHOLDER; } + InitHistory(); } void Identifier::SetName(const util::StringView &newName) noexcept { ES2PANDA_ASSERT(newName != ERROR_LITERAL); - name_ = newName; + GetOrCreateHistoryNodeAs()->name_ = newName; } Identifier *Identifier::Clone(ArenaAllocator *const allocator, AstNode *const parent) @@ -72,6 +76,13 @@ Identifier *Identifier::Clone(ArenaAllocator *const allocator, AstNode *const pa return clone; } +void Identifier::SetValueDecorators(Decorator *source, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->decorators_; + arenaVector[index] = source; +} + Identifier *Identifier::CloneReference(ArenaAllocator *const allocator, AstNode *const parent) { auto *const clone = Clone(allocator, parent); @@ -90,10 +101,11 @@ void Identifier::TransformChildren(const NodeTransformer &cb, std::string_view c } } - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } } @@ -104,14 +116,14 @@ void Identifier::Iterate(const NodeTraverser &cb) const cb(TypeAnnotation()); } - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } } ValidationInfo Identifier::ValidateExpression() { - if ((flags_ & IdentifierFlags::OPTIONAL) != 0U) { + if ((IdFlags() & IdentifierFlags::OPTIONAL) != 0U) { return {"Unexpected token '?'.", Start()}; } @@ -126,10 +138,10 @@ ValidationInfo Identifier::ValidateExpression() void Identifier::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", IsPrivateIdent() ? "PrivateIdentifier" : "Identifier"}, - {"name", name_}, + {"name", Name()}, {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}, {"optional", AstDumper::Optional(IsOptional())}, - {"decorators", decorators_}}); + {"decorators", Decorators()}}); } void Identifier::Dump(ir::SrcDumper *dumper) const @@ -143,7 +155,7 @@ void Identifier::Dump(ir::SrcDumper *dumper) const dumper->Add("private "); } - auto name = std::string(name_); + auto name = std::string(Name()); std::string propertyStr = compiler::Signatures::PROPERTY.data(); if (UNLIKELY(name.find(propertyStr) != std::string::npos)) { name.replace(name.find(propertyStr), propertyStr.length(), "_$property$_"); diff --git a/ets2panda/ir/expressions/identifier.h b/ets2panda/ir/expressions/identifier.h index da71df56cc..6f8814018b 100644 --- a/ets2panda/ir/expressions/identifier.h +++ b/ets2panda/ir/expressions/identifier.h @@ -68,42 +68,39 @@ public: [[nodiscard]] const util::StringView &Name() const noexcept { - return name_; + return GetHistoryNodeAs()->name_; } [[nodiscard]] util::StringView &Name() noexcept { - return name_; + return GetHistoryNodeAs()->name_; } void SetName(const util::StringView &newName) noexcept; - [[nodiscard]] const ArenaVector &Decorators() const noexcept - { - return decorators_; - } + void SetValueDecorators(Decorator *source, size_t index); - const ArenaVector *DecoratorsPtr() const override + [[nodiscard]] const ArenaVector &Decorators() const noexcept { - return &Decorators(); + return GetHistoryNodeAs()->decorators_; } bool IsErrorPlaceHolder() const noexcept { - return (flags_ & IdentifierFlags::ERROR_PLACEHOLDER) != 0; + return (IdFlags() & IdentifierFlags::ERROR_PLACEHOLDER) != 0; } [[nodiscard]] bool IsOptional() const noexcept { - return (flags_ & IdentifierFlags::OPTIONAL) != 0; + return (IdFlags() & IdentifierFlags::OPTIONAL) != 0; } void SetOptional(bool const optional) noexcept { if (optional) { - flags_ |= IdentifierFlags::OPTIONAL; + AddIdFlags(IdentifierFlags::OPTIONAL); } else { - flags_ &= ~IdentifierFlags::OPTIONAL; + ClearIdFlags(IdentifierFlags::OPTIONAL); } } @@ -114,86 +111,86 @@ public: [[nodiscard]] bool IsTdz() const noexcept { - return (flags_ & IdentifierFlags::TDZ) != 0; + return (IdFlags() & IdentifierFlags::TDZ) != 0; } void SetTdz() noexcept { - flags_ |= IdentifierFlags::TDZ; + AddIdFlags(IdentifierFlags::TDZ); } void SetAccessor() noexcept { - flags_ |= IdentifierFlags::GET; + AddIdFlags(IdentifierFlags::GET); } [[nodiscard]] bool IsAccessor() const noexcept { - return (flags_ & IdentifierFlags::GET) != 0; + return (IdFlags() & IdentifierFlags::GET) != 0; } void SetMutator() noexcept { - flags_ |= IdentifierFlags::SET; + AddIdFlags(IdentifierFlags::SET); } [[nodiscard]] bool IsMutator() const noexcept { - return (flags_ & IdentifierFlags::SET) != 0; + return (IdFlags() & IdentifierFlags::SET) != 0; } [[nodiscard]] bool IsReceiver() const noexcept { - return name_ == varbinder::VarBinder::MANDATORY_PARAM_THIS; + return Name() == varbinder::VarBinder::MANDATORY_PARAM_THIS; } [[nodiscard]] bool IsPrivateIdent() const noexcept { - return (flags_ & IdentifierFlags::PRIVATE) != 0; + return (IdFlags() & IdentifierFlags::PRIVATE) != 0; } void SetPrivate(bool const isPrivate) noexcept { if (isPrivate) { - flags_ |= IdentifierFlags::PRIVATE; + AddIdFlags(IdentifierFlags::PRIVATE); } else { - flags_ &= ~IdentifierFlags::PRIVATE; + ClearIdFlags(IdentifierFlags::PRIVATE); } } [[nodiscard]] bool IsIgnoreBox() const noexcept { - return (flags_ & IdentifierFlags::IGNORE_BOX) != 0; + return (IdFlags() & IdentifierFlags::IGNORE_BOX) != 0; } void SetIgnoreBox() noexcept { - flags_ |= IdentifierFlags::IGNORE_BOX; + AddIdFlags(IdentifierFlags::IGNORE_BOX); } [[nodiscard]] bool IsAnnotationDecl() const noexcept { - return (flags_ & IdentifierFlags::ANNOTATIONDECL) != 0; + return (IdFlags() & IdentifierFlags::ANNOTATIONDECL) != 0; } void SetAnnotationDecl() noexcept { - flags_ |= IdentifierFlags::ANNOTATIONDECL; + AddIdFlags(IdentifierFlags::ANNOTATIONDECL); } [[nodiscard]] bool IsAnnotationUsage() const noexcept { - return (flags_ & IdentifierFlags::ANNOTATIONUSAGE) != 0; + return (IdFlags() & IdentifierFlags::ANNOTATIONUSAGE) != 0; } void SetAnnotationUsage() noexcept { - flags_ |= IdentifierFlags::ANNOTATIONUSAGE; + AddIdFlags(IdentifierFlags::ANNOTATIONUSAGE); } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + GetOrCreateHistoryNodeAs()->decorators_ = std::move(decorators); } [[nodiscard]] Identifier *Clone(ArenaAllocator *allocator, AstNode *parent) override; @@ -222,7 +219,42 @@ public: v->Accept(this); } + Identifier *Construct(ArenaAllocator *allocator) override + { + return allocator->New(allocator); + } + + void CopyTo(AstNode *other) const override + { + auto otherImpl = other->AsIdentifier(); + + otherImpl->name_ = name_; + otherImpl->flags_ = flags_; + otherImpl->decorators_ = decorators_; + + AnnotatedExpression::CopyTo(other); + }; + private: + IdentifierFlags IdFlags() const + { + return GetHistoryNodeAs()->flags_; + } + + void AddIdFlags(IdentifierFlags const flags) noexcept + { + if (!All(IdFlags(), flags)) { + GetOrCreateHistoryNodeAs()->flags_ |= flags; + } + } + + void ClearIdFlags(IdentifierFlags const flags) noexcept + { + if (Any(IdFlags(), flags)) { + GetOrCreateHistoryNodeAs()->flags_ &= ~flags; + } + } + bool CheckDeclarationsPart2(const ir::AstNode *parent, ScriptExtension ext) const; bool CheckDeclarationsPart1(const ir::AstNode *parent, ScriptExtension ext) const; bool CheckNotDeclarations(const ir::AstNode *parent, ScriptExtension ext) const; diff --git a/ets2panda/ir/expressions/objectExpression.h b/ets2panda/ir/expressions/objectExpression.h index 7f7e05007f..45e893cb51 100644 --- a/ets2panda/ir/expressions/objectExpression.h +++ b/ets2panda/ir/expressions/objectExpression.h @@ -81,11 +81,6 @@ public: return decorators_; } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/module/importDeclaration.cpp b/ets2panda/ir/module/importDeclaration.cpp index d48246d887..161970f5f5 100644 --- a/ets2panda/ir/module/importDeclaration.cpp +++ b/ets2panda/ir/module/importDeclaration.cpp @@ -24,46 +24,55 @@ namespace ark::es2panda::ir { +void ImportDeclaration::SetSource(StringLiteral *source) +{ + this->GetOrCreateHistoryNodeAs()->source_ = source; +} + void ImportDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - if (auto *transformedNode = cb(source_); source_ != transformedNode) { - source_->SetTransformedNode(transformationName, transformedNode); - source_ = transformedNode->AsStringLiteral(); + auto const source = Source(); + if (auto *transformedNode = cb(source); source != transformedNode) { + source->SetTransformedNode(transformationName, transformedNode); + SetSource(transformedNode->AsStringLiteral()); } - for (auto *&it : VectorIterationGuard(specifiers_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode; + auto const &specifiers = Specifiers(); + for (size_t index = 0; index < specifiers.size(); ++index) { + if (auto *transformedNode = cb(specifiers[index]); specifiers[index] != transformedNode) { + specifiers[index]->SetTransformedNode(transformationName, transformedNode); + SetValueSpecifiers(transformedNode, index); } } } void ImportDeclaration::Iterate(const NodeTraverser &cb) const { - cb(source_); + auto source = GetHistoryNodeAs()->source_; + cb(source); - for (auto *it : VectorIterationGuard(specifiers_)) { + for (auto *it : VectorIterationGuard(Specifiers())) { cb(it); } } void ImportDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ImportDeclaration"}, {"source", source_}, {"specifiers", specifiers_}}); + dumper->Add({{"type", "ImportDeclaration"}, {"source", Source()}, {"specifiers", Specifiers()}}); } void ImportDeclaration::Dump(ir::SrcDumper *dumper) const { dumper->Add("import "); - if (specifiers_.size() == 1 && - (specifiers_[0]->IsImportNamespaceSpecifier() || specifiers_[0]->IsImportDefaultSpecifier())) { - specifiers_[0]->Dump(dumper); + auto const &specifiers = Specifiers(); + if (specifiers.size() == 1 && + (specifiers[0]->IsImportNamespaceSpecifier() || specifiers[0]->IsImportDefaultSpecifier())) { + specifiers[0]->Dump(dumper); } else { dumper->Add("{ "); - for (auto specifier : specifiers_) { + for (auto specifier : specifiers) { specifier->Dump(dumper); - if (specifier != specifiers_.back()) { + if (specifier != specifiers.back()) { dumper->Add(", "); } } @@ -71,7 +80,7 @@ void ImportDeclaration::Dump(ir::SrcDumper *dumper) const } dumper->Add(" from "); - source_->Dump(dumper); + Source()->Dump(dumper); dumper->Add(";"); dumper->Endl(); } @@ -104,7 +113,7 @@ ImportDeclaration *ImportDeclaration::Construct(ArenaAllocator *allocator) void ImportDeclaration::CopyTo(AstNode *other) const { - auto otherImpl = other->AsImportDeclaration(); + auto otherImpl = static_cast(other); otherImpl->source_ = source_; otherImpl->specifiers_ = specifiers_; @@ -113,4 +122,30 @@ void ImportDeclaration::CopyTo(AstNode *other) const Statement::CopyTo(other); } +void ImportDeclaration::EmplaceSpecifiers(AstNode *source) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->specifiers_.emplace_back(source); +} + +void ImportDeclaration::ClearSpecifiers() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->specifiers_.clear(); +} + +void ImportDeclaration::SetValueSpecifiers(AstNode *source, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->specifiers_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = source; +} + +[[nodiscard]] ArenaVector &ImportDeclaration::SpecifiersForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->specifiers_; +} + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/module/importDeclaration.h b/ets2panda/ir/module/importDeclaration.h index c3f28438e2..2da6374989 100644 --- a/ets2panda/ir/module/importDeclaration.h +++ b/ets2panda/ir/module/importDeclaration.h @@ -25,6 +25,11 @@ enum class ImportKinds { ALL, TYPES }; class ImportDeclaration : public Statement { public: + void EmplaceSpecifiers(AstNode *source); + void ClearSpecifiers(); + void SetValueSpecifiers(AstNode *source, size_t index); + [[nodiscard]] ArenaVector &SpecifiersForUpdate(); + explicit ImportDeclaration(StringLiteral *source, ArenaVector &&specifiers, const ImportKinds importKinds = ImportKinds::ALL) : Statement(AstNodeType::IMPORT_DECLARATION), @@ -32,26 +37,36 @@ public: specifiers_(std::move(specifiers)), importKinds_(importKinds) { + InitHistory(); } - const StringLiteral *Source() const + explicit ImportDeclaration(StringLiteral *source, ArenaVector &&specifiers, + const ImportKinds importKinds, AstNodeHistory *history) + : Statement(AstNodeType::IMPORT_DECLARATION), + source_(source), + specifiers_(std::move(specifiers)), + importKinds_(importKinds) { - return source_; + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } - StringLiteral *Source() + const StringLiteral *Source() const { - return source_; + return GetHistoryNodeAs()->source_; } - const ArenaVector &Specifiers() const + StringLiteral *Source() { - return specifiers_; + return GetHistoryNodeAs()->source_; } - ArenaVector &Specifiers() + const ArenaVector &Specifiers() const { - return specifiers_; + return GetHistoryNodeAs()->specifiers_; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -70,7 +85,7 @@ public: bool IsTypeKind() const { - return importKinds_ == ImportKinds::TYPES; + return GetHistoryNodeAs()->importKinds_ == ImportKinds::TYPES; } ImportDeclaration *Construct(ArenaAllocator *allocator) override; @@ -78,6 +93,8 @@ public: private: friend class SizeOfNodeTest; + void SetSource(StringLiteral *source); + StringLiteral *source_; ArenaVector specifiers_; ImportKinds importKinds_; diff --git a/ets2panda/ir/opaqueTypeNode.cpp b/ets2panda/ir/opaqueTypeNode.cpp index b76b69d868..4a74b38975 100644 --- a/ets2panda/ir/opaqueTypeNode.cpp +++ b/ets2panda/ir/opaqueTypeNode.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void OpaqueTypeNode::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void OpaqueTypeNode::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/statements/annotationDeclaration.cpp b/ets2panda/ir/statements/annotationDeclaration.cpp index aab66f2db2..f353444a46 100644 --- a/ets2panda/ir/statements/annotationDeclaration.cpp +++ b/ets2panda/ir/statements/annotationDeclaration.cpp @@ -21,36 +21,77 @@ #include "ir/srcDump.h" namespace ark::es2panda::ir { + +void AnnotationDeclaration::SetInternalName(util::StringView internalName) +{ + this->GetOrCreateHistoryNodeAs()->internalName_ = internalName; +} + +void AnnotationDeclaration::SetExpr(Expression *expr) +{ + this->GetOrCreateHistoryNodeAs()->expr_ = expr; +} + +void AnnotationDeclaration::EmplaceProperties(AstNode *properties) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->properties_.emplace_back(properties); +} + +void AnnotationDeclaration::ClearProperties() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->properties_.clear(); +} + +void AnnotationDeclaration::SetValueProperties(AstNode *properties, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->properties_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = properties; +} + +[[nodiscard]] const ArenaVector &AnnotationDeclaration::Properties() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->properties_; +} + +[[nodiscard]] ArenaVector &AnnotationDeclaration::PropertiesForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->properties_; +} + void AnnotationDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(properties_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode; + auto const &properties = Properties(); + for (size_t ix = 0; ix < properties.size(); ix++) { + if (auto *transformedNode = cb(properties[ix]); properties[ix] != transformedNode) { + properties[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueProperties(transformedNode->AsTSClassImplements(), ix); } } - if (expr_ != nullptr) { - if (auto *transformedNode = cb(expr_); expr_ != transformedNode) { - expr_->SetTransformedNode(transformationName, transformedNode); - expr_ = transformedNode->AsIdentifier(); + auto const expr = Expr(); + if (expr != nullptr) { + if (auto *transformedNode = cb(expr); expr != transformedNode) { + expr->SetTransformedNode(transformationName, transformedNode); + SetExpr(transformedNode->AsIdentifier()); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void AnnotationDeclaration::Iterate(const NodeTraverser &cb) const { - if (expr_ != nullptr) { - cb(expr_); + auto const expr = GetHistoryNodeAs()->expr_; + if (expr != nullptr) { + cb(expr); } - for (auto *it : VectorIterationGuard(properties_)) { + for (auto *it : VectorIterationGuard(Properties())) { cb(it); } @@ -61,24 +102,25 @@ void AnnotationDeclaration::Iterate(const NodeTraverser &cb) const void AnnotationDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"Expr", expr_}, {"properties", properties_}, {"annotations", AstDumper::Optional(Annotations())}}); + dumper->Add({{"Expr", Expr()}, {"properties", Properties()}, {"annotations", AstDumper::Optional(Annotations())}}); } void AnnotationDeclaration::Dump(ir::SrcDumper *dumper) const { // re-understand for (auto *anno : Annotations()) { anno->Dump(dumper); } - ES2PANDA_ASSERT(expr_ != nullptr); + ES2PANDA_ASSERT(Expr() != nullptr); dumper->Add("@interface "); - expr_->Dump(dumper); + Expr()->Dump(dumper); dumper->Add(" {"); - if (!properties_.empty()) { + auto const properties = Properties(); + if (!properties.empty()) { dumper->IncrIndent(); dumper->Endl(); - for (auto elem : properties_) { + for (auto elem : properties) { elem->Dump(dumper); - if (elem == properties_.back()) { + if (elem == properties.back()) { dumper->DecrIndent(); } } @@ -108,14 +150,13 @@ checker::VerifiedType AnnotationDeclaration::Check(checker::ETSChecker *checker) Identifier *AnnotationDeclaration::GetBaseName() const { - if (expr_->IsIdentifier()) { - return expr_->AsIdentifier(); + if (Expr()->IsIdentifier()) { + return GetHistoryNodeAs()->expr_->AsIdentifier(); } - auto *part = expr_->AsETSTypeReference()->Part(); + auto *part = Expr()->AsETSTypeReference()->Part(); return part->Name()->AsTSQualifiedName()->Right(); } - -AstNode *AnnotationDeclaration::Construct(ArenaAllocator *allocator) +AnnotationDeclaration *AnnotationDeclaration::Construct(ArenaAllocator *allocator) { return allocator->New(nullptr, allocator); } diff --git a/ets2panda/ir/statements/annotationDeclaration.h b/ets2panda/ir/statements/annotationDeclaration.h index f55f591444..c3d3b8f2f2 100644 --- a/ets2panda/ir/statements/annotationDeclaration.h +++ b/ets2panda/ir/statements/annotationDeclaration.h @@ -42,42 +42,39 @@ public: expr_(expr), properties_(allocator->Adapter()) { + InitHistory(); } explicit AnnotationDeclaration(Expression *expr, ArenaVector &&properties, ArenaAllocator *allocator) : AnnotationAllowed(AstNodeType::ANNOTATION_DECLARATION, allocator), expr_(expr), properties_(std::move(properties)) { + InitHistory(); } const util::StringView &InternalName() const { - return internalName_; + return GetHistoryNodeAs()->internalName_; } - void SetInternalName(util::StringView internalName) - { - internalName_ = internalName; - } + void SetInternalName(util::StringView internalName); [[nodiscard]] const Expression *Expr() const noexcept { - return expr_; + return GetHistoryNodeAs()->expr_; } [[nodiscard]] Expression *Expr() noexcept { - return expr_; + return GetHistoryNodeAs()->expr_; } - [[nodiscard]] ArenaVector &Properties() noexcept - { - return properties_; - } + [[nodiscard]] const ArenaVector &Properties(); + [[nodiscard]] ArenaVector &PropertiesForUpdate(); [[nodiscard]] const ArenaVector &Properties() const noexcept { - return properties_; + return GetHistoryNodeAs()->properties_; } [[nodiscard]] const ArenaVector *PropertiesPtr() const @@ -87,37 +84,38 @@ public: void AddProperties(ArenaVector &&properties) { - properties_ = std::move(properties); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + newNode->properties_ = std::move(properties); } [[nodiscard]] bool IsSourceRetention() const noexcept { - return (policy_ & RetentionPolicy::SOURCE) != 0; + return (Policy() & RetentionPolicy::SOURCE) != 0; } [[nodiscard]] bool IsBytecodeRetention() const noexcept { - return (policy_ & RetentionPolicy::BYTECODE) != 0; + return (Policy() & RetentionPolicy::BYTECODE) != 0; } [[nodiscard]] bool IsRuntimeRetention() const noexcept { - return (policy_ & RetentionPolicy::RUNTIME) != 0; + return (Policy() & RetentionPolicy::RUNTIME) != 0; } void SetSourceRetention() noexcept { - policy_ = RetentionPolicy::SOURCE; + GetOrCreateHistoryNodeAs()->policy_ = RetentionPolicy::SOURCE; } void SetBytecodeRetention() noexcept { - policy_ = RetentionPolicy::BYTECODE; + GetOrCreateHistoryNodeAs()->policy_ = RetentionPolicy::BYTECODE; } void SetRuntimeRetention() noexcept { - policy_ = RetentionPolicy::RUNTIME; + GetOrCreateHistoryNodeAs()->policy_ = RetentionPolicy::RUNTIME; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -141,28 +139,38 @@ public: [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - return scope_; + return GetHistoryNodeAs()->scope_; } void SetScope(varbinder::LocalScope *scope) { ES2PANDA_ASSERT(scope_ == nullptr); - scope_ = scope; + GetOrCreateHistoryNodeAs()->scope_ = scope; } void ClearScope() noexcept override { - scope_ = nullptr; + GetOrCreateHistoryNodeAs()->scope_ = nullptr; } Identifier *GetBaseName() const; -protected: - AstNode *Construct(ArenaAllocator *allocator) override; + void EmplaceProperties(AstNode *properties); + void ClearProperties(); + void SetValueProperties(AstNode *properties, size_t index); + + AnnotationDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; private: friend class SizeOfNodeTest; + RetentionPolicy Policy() const + { + return GetHistoryNodeAs()->policy_; + } + + void SetExpr(Expression *expr); + util::StringView internalName_ {}; varbinder::LocalScope *scope_ {}; Expression *expr_; diff --git a/ets2panda/ir/statements/blockStatement.cpp b/ets2panda/ir/statements/blockStatement.cpp index 63cc1287f0..abbe7d12b0 100644 --- a/ets2panda/ir/statements/blockStatement.cpp +++ b/ets2panda/ir/statements/blockStatement.cpp @@ -28,11 +28,13 @@ namespace ark::es2panda::ir { void BlockStatement::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { // This will survive pushing element to the back of statements_ in the process - // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < statements_.size(); ix++) { - if (auto *transformedNode = cb(statements_[ix]); statements_[ix] != transformedNode) { - statements_[ix]->SetTransformedNode(transformationName, transformedNode); - statements_[ix] = transformedNode->AsStatement(); + auto const &constStatements = Statements(); + for (size_t index = 0; index < constStatements.size(); index++) { + auto statement = constStatements[index]; + if (auto *transformedNode = cb(statement); statement != transformedNode) { + statement->SetTransformedNode(transformationName, transformedNode); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements[index] = transformedNode->AsStatement(); } } } @@ -41,7 +43,7 @@ AstNode *BlockStatement::Clone(ArenaAllocator *const allocator, AstNode *const p { ArenaVector statements(allocator->Adapter()); - for (auto *statement : this->statements_) { + for (auto *statement : Statements()) { statements.push_back(statement->Clone(allocator, parent)->AsStatement()); } @@ -54,35 +56,37 @@ AstNode *BlockStatement::Clone(ArenaAllocator *const allocator, AstNode *const p void BlockStatement::Iterate(const NodeTraverser &cb) const { // This will survive pushing element to the back of statements_ in the process + auto const &statements = Statements(); // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < statements_.size(); ix++) { - cb(statements_[ix]); + for (size_t ix = 0; ix < statements.size(); ix++) { + cb(statements[ix]); } } void BlockStatement::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", IsProgram() ? "Program" : "BlockStatement"}, {"statements", statements_}}); + dumper->Add({{"type", IsProgram() ? "Program" : "BlockStatement"}, {"statements", Statements()}}); } void BlockStatement::Dump(ir::SrcDumper *dumper) const { + auto const &statements = Statements(); // NOTE(nsizov): trailing blocks if (Parent() != nullptr && (Parent()->IsBlockStatement() || Parent()->IsCallExpression())) { dumper->Add("{"); - if (!statements_.empty()) { + if (!statements.empty()) { dumper->IncrIndent(); dumper->Endl(); } } - for (auto statement : statements_) { + for (auto statement : statements) { statement->Dump(dumper); - if (statement != statements_.back()) { + if (statement != statements.back()) { dumper->Endl(); } } if (Parent() != nullptr && (Parent()->IsBlockStatement() || Parent()->IsCallExpression())) { - if (!statements_.empty()) { + if (!statements.empty()) { dumper->DecrIndent(); dumper->Endl(); } @@ -118,7 +122,7 @@ BlockStatement *BlockStatement::Construct(ArenaAllocator *allocator) void BlockStatement::CopyTo(AstNode *other) const { - auto otherImpl = other->AsBlockStatement(); + auto otherImpl = static_cast(other); otherImpl->scope_ = scope_; otherImpl->statements_ = statements_; diff --git a/ets2panda/ir/statements/blockStatement.h b/ets2panda/ir/statements/blockStatement.h index 81745d7f37..e47670c061 100644 --- a/ets2panda/ir/statements/blockStatement.h +++ b/ets2panda/ir/statements/blockStatement.h @@ -31,11 +31,9 @@ public: statements_(std::move(statementList)), trailingBlocks_(allocator->Adapter()) { + InitHistory(); } - // NOTE (somas): this friend relationship can be removed once there are getters for private fields - friend class checker::ETSAnalyzer; - [[nodiscard]] bool IsScopeBearer() const noexcept override { return true; @@ -43,55 +41,91 @@ public: [[nodiscard]] varbinder::Scope *Scope() const noexcept override { - return scope_; + return AstNode::GetHistoryNodeAs()->scope_; } void SetScope(varbinder::Scope *scope) noexcept { - scope_ = scope; + if (Scope() != scope) { + AstNode::GetOrCreateHistoryNodeAs()->scope_ = scope; + } } void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } - const ArenaVector &Statements() const + ArenaVector &StatementsForUpdates() { - return statements_; + return AstNode::GetOrCreateHistoryNodeAs()->statements_; } - ArenaVector &Statements() + const ArenaVector &Statements() { - return statements_; + return AstNode::GetHistoryNodeAs()->statements_; + } + + const ArenaVector &Statements() const + { + return AstNode::GetHistoryNodeAs()->statements_; } void SetStatements(ArenaVector &&statementList) { - statements_ = std::move(statementList); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements = std::move(statementList); - for (auto *statement : statements_) { + for (auto *statement : Statements()) { statement->SetParent(this); } } - void AddStatement(Statement *stmt) + void AddStatements(const ArenaVector &statementList) { - stmt->SetParent(this); - statements_.emplace_back(stmt); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + + for (auto statement : statementList) { + statement->SetParent(this); + statements.emplace_back(statement); + } } - void AddStatements(ArenaVector &stmts) + void ClearStatements() { - for (auto *stmt : stmts) { - stmt->SetParent(this); - } - statements_.insert(statements_.end(), stmts.begin(), stmts.end()); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements.clear(); + } + + void AddStatement(Statement *statement) + { + statement->SetParent(this); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements.emplace_back(statement); + } + + void AddStatement(std::size_t idx, Statement *statement) + { + statement->SetParent(this); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements.emplace(std::next(statements.begin() + idx), statement); } void AddTrailingBlock(AstNode *stmt, BlockStatement *trailingBlock) { - trailingBlocks_.emplace(stmt, trailingBlock); + AstNode::GetOrCreateHistoryNodeAs()->trailingBlocks_.emplace(stmt, trailingBlock); + } + + BlockStatement *SearchStatementInTrailingBlock(Statement *item) + { + auto &trailingBlock = AstNode::GetHistoryNodeAs()->trailingBlocks_; + auto nowNode = item->GetHistoryNode(); + for (auto &it : trailingBlock) { + if (it.first->GetHistoryNode() == nowNode) { + return it.second; + } + } + return nullptr; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; diff --git a/ets2panda/ir/statements/classDeclaration.cpp b/ets2panda/ir/statements/classDeclaration.cpp index d459bc5e20..398e74f231 100644 --- a/ets2panda/ir/statements/classDeclaration.cpp +++ b/ets2panda/ir/statements/classDeclaration.cpp @@ -24,14 +24,46 @@ namespace ark::es2panda::ir { +void ClassDeclaration::SetDefinition(ClassDefinition *def) +{ + this->GetOrCreateHistoryNodeAs()->def_ = def; +} + ClassDeclaration *ClassDeclaration::Construct(ArenaAllocator *allocator) { return allocator->New(nullptr, allocator); } +void ClassDeclaration::EmplaceDecorators(Decorator *decorators) +{ + this->GetOrCreateHistoryNodeAs()->decorators_.emplace_back(decorators); +} + +void ClassDeclaration::ClearDecorators() +{ + this->GetOrCreateHistoryNodeAs()->decorators_.clear(); +} + +void ClassDeclaration::SetValueDecorators(Decorator *decorators, size_t index) +{ + auto &arenaVector = this->GetOrCreateHistoryNodeAs()->decorators_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = decorators; +} + +[[nodiscard]] const ArenaVector &ClassDeclaration::Decorators() +{ + return this->GetHistoryNodeAs()->decorators_; +} + +[[nodiscard]] ArenaVector &ClassDeclaration::DecoratorsForUpdate() +{ + return this->GetOrCreateHistoryNodeAs()->decorators_; +} + void ClassDeclaration::CopyTo(AstNode *other) const { - auto otherImpl = other->AsClassDeclaration(); + auto otherImpl = reinterpret_cast(other); otherImpl->def_ = def_; otherImpl->decorators_ = decorators_; @@ -41,40 +73,45 @@ void ClassDeclaration::CopyTo(AstNode *other) const void ClassDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - if (auto *transformedNode = cb(def_); def_ != transformedNode) { - def_->SetTransformedNode(transformationName, transformedNode); - def_ = transformedNode->AsClassDefinition(); + auto const def = Definition(); + if (auto *transformedNode = cb(def); def != transformedNode) { + def->SetTransformedNode(transformationName, transformedNode); + SetDefinition(transformedNode->AsClassDefinition()); } } void ClassDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } - cb(def_); + auto def = GetHistoryNodeAs()->def_; + cb(def); } void ClassDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ClassDeclaration"}, {"definition", def_}, {"decorators", AstDumper::Optional(decorators_)}}); + dumper->Add({{"type", "ClassDeclaration"}, + {"definition", Definition()}, + {"decorators", AstDumper::Optional(Decorators())}}); } void ClassDeclaration::Dump(ir::SrcDumper *dumper) const { - if (def_ != nullptr) { - def_->Dump(dumper); + if (Definition() != nullptr) { + Definition()->Dump(dumper); } // NOTE(nsizov): support decorators when supported in ArkTS - ES2PANDA_ASSERT(decorators_.empty()); + ES2PANDA_ASSERT(Decorators().empty()); } void ClassDeclaration::Compile(compiler::PandaGen *pg) const diff --git a/ets2panda/ir/statements/classDeclaration.h b/ets2panda/ir/statements/classDeclaration.h index 72a5afe51f..5ea6d0e8d0 100644 --- a/ets2panda/ir/statements/classDeclaration.h +++ b/ets2panda/ir/statements/classDeclaration.h @@ -24,31 +24,38 @@ public: explicit ClassDeclaration(ClassDefinition *def, ArenaAllocator *allocator) : Statement(AstNodeType::CLASS_DECLARATION), def_(def), decorators_(allocator->Adapter()) { + InitHistory(); } - ClassDefinition *Definition() + explicit ClassDeclaration(ClassDefinition *def, ArenaAllocator *allocator, AstNodeHistory *history) + : Statement(AstNodeType::CLASS_DECLARATION), def_(def), decorators_(allocator->Adapter()) { - return def_; + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } - const ClassDefinition *Definition() const + ClassDefinition *Definition() { - return def_; + return GetHistoryNodeAs()->def_; } - const ArenaVector &Decorators() const + const ClassDefinition *Definition() const { - return decorators_; + return GetHistoryNodeAs()->def_; } - const ArenaVector *DecoratorsPtr() const override + const ArenaVector &Decorators() const { - return &Decorators(); + return GetHistoryNodeAs()->decorators_; } void AddDecorators(ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = GetOrCreateHistoryNodeAs(); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -71,10 +78,19 @@ public: v->Accept(this); } + void EmplaceDecorators(Decorator *decorators); + void ClearDecorators(); + void SetValueDecorators(Decorator *decorators, size_t index); + const ArenaVector &Decorators(); + ArenaVector &DecoratorsForUpdate(); + + void SetDefinition(ClassDefinition *def); + protected: explicit ClassDeclaration(AstNodeType type, ClassDefinition *const def, ArenaAllocator *const allocator) : Statement(type), def_(def), decorators_(allocator->Adapter()) { + InitHistory(); } ClassDeclaration *Construct(ArenaAllocator *allocator) override; diff --git a/ets2panda/ir/statements/functionDeclaration.cpp b/ets2panda/ir/statements/functionDeclaration.cpp index 21fb0d5f85..be0f1341c4 100644 --- a/ets2panda/ir/statements/functionDeclaration.cpp +++ b/ets2panda/ir/statements/functionDeclaration.cpp @@ -23,31 +23,34 @@ #include "compiler/core/pandagen.h" namespace ark::es2panda::ir { + +void FunctionDeclaration::SetFunction(ScriptFunction *func) +{ + this->GetOrCreateHistoryNodeAs()->func_ = func; +} + void FunctionDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); - if (auto *transformedNode = cb(func_); func_ != transformedNode) { - func_->SetTransformedNode(transformationName, transformedNode); - func_ = transformedNode->AsScriptFunction(); + auto const func = Function(); + if (auto *transformedNode = cb(func); func != transformedNode) { + func->SetTransformedNode(transformationName, transformedNode); + SetFunction(transformedNode->AsScriptFunction()); } } void FunctionDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -55,15 +58,16 @@ void FunctionDeclaration::Iterate(const NodeTraverser &cb) const cb(it); } - cb(func_); + auto func = GetHistoryNode()->AsFunctionDeclaration()->func_; + cb(func); } void FunctionDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", func_->IsOverload() ? "TSDeclareFunction" : "FunctionDeclaration"}, - {"decorators", AstDumper::Optional(decorators_)}, + dumper->Add({{"type", Function()->IsOverload() ? "TSDeclareFunction" : "FunctionDeclaration"}, + {"decorators", AstDumper::Optional(Decorators())}, {"annotations", AstDumper::Optional(Annotations())}, - {"function", func_}}); + {"function", Function()}}); } void FunctionDeclaration::Dump(ir::SrcDumper *dumper) const @@ -71,19 +75,20 @@ void FunctionDeclaration::Dump(ir::SrcDumper *dumper) const for (auto *anno : Annotations()) { anno->Dump(dumper); } - if (func_->IsNative()) { + auto func = Function(); + if (func->IsNative()) { dumper->Add("native "); } - if (func_->IsDeclare()) { + if (func->IsDeclare()) { dumper->Add("declare "); } - if (func_->IsAsyncFunc()) { + if (func->IsAsyncFunc()) { dumper->Add("async "); } dumper->Add("function "); - func_->Id()->Dump(dumper); - func_->Dump(dumper); + func->Id()->Dump(dumper); + func->Dump(dumper); } void FunctionDeclaration::Compile(compiler::PandaGen *pg) const @@ -122,4 +127,30 @@ void FunctionDeclaration::CopyTo(AstNode *other) const JsDocAllowed>::CopyTo(other); } +void FunctionDeclaration::EmplaceDecorators(Decorator *decorators) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.emplace_back(decorators); +} + +void FunctionDeclaration::ClearDecorators() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.clear(); +} + +void FunctionDeclaration::SetValueDecorators(Decorator *decorators, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->decorators_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = decorators; +} + +[[nodiscard]] ArenaVector &FunctionDeclaration::DecoratorsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->decorators_; +} + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/statements/functionDeclaration.h b/ets2panda/ir/statements/functionDeclaration.h index 55a3443f02..25a69766e6 100644 --- a/ets2panda/ir/statements/functionDeclaration.h +++ b/ets2panda/ir/statements/functionDeclaration.h @@ -36,7 +36,10 @@ public: func_(func), isAnonymous_(isAnonymous) { - flags_ = func->Modifiers(); + InitHistory(); + if (func != nullptr) { + flags_ = func->Modifiers(); + } } explicit FunctionDeclaration(ArenaAllocator *allocator, ScriptFunction *func, bool isAnonymous = false) @@ -45,27 +48,45 @@ public: func_(func), isAnonymous_(isAnonymous) { - flags_ = func->Modifiers(); + InitHistory(); + if (func != nullptr) { + flags_ = func->Modifiers(); + } + } + + explicit FunctionDeclaration(ArenaAllocator *allocator, ScriptFunction *func, bool isAnonymous, + AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::FUNCTION_DECLARATION, allocator), + decorators_(allocator->Adapter()), + func_(func), + isAnonymous_(isAnonymous) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } ScriptFunction *Function() { - return func_; + return GetHistoryNodeAs()->func_; } bool IsAnonymous() const { - return isAnonymous_; + return GetHistoryNodeAs()->isAnonymous_; } const ScriptFunction *Function() const { - return func_; + return GetHistoryNodeAs()->func_; } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = this->GetOrCreateHistoryNode()->AsFunctionDeclaration(); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -90,8 +111,19 @@ public: FunctionDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + [[nodiscard]] const ArenaVector &Decorators() const + { + return GetHistoryNodeAs()->decorators_; + }; + private: friend class SizeOfNodeTest; + void SetFunction(ScriptFunction *func); + void EmplaceDecorators(Decorator *decorators); + void ClearDecorators(); + void SetValueDecorators(Decorator *decorators, size_t index); + [[nodiscard]] ArenaVector &DecoratorsForUpdate(); + ArenaVector decorators_; ScriptFunction *func_; bool isAnonymous_; diff --git a/ets2panda/ir/statements/variableDeclaration.cpp b/ets2panda/ir/statements/variableDeclaration.cpp index 56934876cf..adbe853c54 100644 --- a/ets2panda/ir/statements/variableDeclaration.cpp +++ b/ets2panda/ir/statements/variableDeclaration.cpp @@ -22,33 +22,101 @@ #include "utils/arena_containers.h" namespace ark::es2panda::ir { + +void VariableDeclaration::EmplaceDecorators(Decorator *source) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.emplace_back(source); +} + +void VariableDeclaration::ClearDecorators() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.clear(); +} + +void VariableDeclaration::SetValueDecorators(Decorator *source, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->decorators_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = source; +} + +[[nodiscard]] const ArenaVector &VariableDeclaration::Decorators() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->decorators_; +} + +[[nodiscard]] ArenaVector &VariableDeclaration::DecoratorsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->decorators_; +} + +void VariableDeclaration::EmplaceDeclarators(VariableDeclarator *source) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->declarators_.emplace_back(source); +} + +void VariableDeclaration::ClearDeclarators() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->declarators_.clear(); +} + +void VariableDeclaration::SetValueDeclarators(VariableDeclarator *source, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->declarators_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = source; +} + +[[nodiscard]] const ArenaVector &VariableDeclaration::Declarators() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->declarators_; +} + +[[nodiscard]] ArenaVector &VariableDeclaration::DeclaratorsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->declarators_; +} + void VariableDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t index = 0; index < decorators.size(); ++index) { + if (auto *transformedNode = cb(decorators[index]); decorators[index] != transformedNode) { + decorators[index]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), index); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + auto const &annotations = Annotations(); + for (size_t index = 0; index < annotations.size(); ++index) { + if (auto *transformedNode = cb(annotations[index]); annotations[index] != transformedNode) { + annotations[index]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), index); } } - for (auto *&it : VectorIterationGuard(declarators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsVariableDeclarator(); + auto const &declarators = Declarators(); + for (size_t index = 0; index < declarators.size(); ++index) { + if (auto *transformedNode = cb(declarators[index]); declarators[index] != transformedNode) { + declarators[index]->SetTransformedNode(transformationName, transformedNode); + SetValueDeclarators(transformedNode->AsVariableDeclarator(), index); } } } void VariableDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -56,7 +124,7 @@ void VariableDeclaration::Iterate(const NodeTraverser &cb) const cb(it); } - for (auto *it : VectorIterationGuard(declarators_)) { + for (auto *it : VectorIterationGuard(Declarators())) { cb(it); } } @@ -65,7 +133,7 @@ void VariableDeclaration::Dump(ir::AstDumper *dumper) const { const char *kind = nullptr; - switch (kind_) { + switch (Kind()) { case VariableDeclarationKind::CONST: { kind = "const"; break; @@ -84,9 +152,9 @@ void VariableDeclaration::Dump(ir::AstDumper *dumper) const } dumper->Add({{"type", "VariableDeclaration"}, - {"declarations", declarators_}, + {"declarations", Declarators()}, {"kind", kind}, - {"decorators", AstDumper::Optional(decorators_)}, + {"decorators", AstDumper::Optional(Decorators())}, {"annotations", AstDumper::Optional(Annotations())}, {"declare", AstDumper::Optional(IsDeclare())}}); } @@ -101,7 +169,7 @@ void VariableDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("declare "); } - switch (kind_) { + switch (Kind()) { case VariableDeclarationKind::CONST: dumper->Add("const "); break; @@ -115,15 +183,16 @@ void VariableDeclaration::Dump(ir::SrcDumper *dumper) const ES2PANDA_UNREACHABLE(); } - for (auto declarator : declarators_) { + for (auto declarator : Declarators()) { declarator->Dump(dumper); - if (declarator != declarators_.back()) { + if (declarator != Declarators().back()) { dumper->Add(", "); } } - if ((parent_ != nullptr) && - (parent_->IsBlockStatement() || parent_->IsBlockExpression() || parent_->IsSwitchCaseStatement())) { + auto const parent = Parent(); + if ((parent != nullptr) && + (parent->IsBlockStatement() || parent->IsBlockExpression() || parent->IsSwitchCaseStatement())) { dumper->Add(";"); } } @@ -145,6 +214,33 @@ VariableDeclaration::VariableDeclaration([[maybe_unused]] Tag const tag, Variabl declarators_.emplace_back(d->Clone(allocator, nullptr)->AsVariableDeclarator()); declarators_.back()->SetParent(this); } + + InitHistory(); +} + +VariableDeclaration::VariableDeclaration([[maybe_unused]] Tag const tag, VariableDeclaration const &other, + ArenaAllocator *const allocator, AstNodeHistory *history) + : JsDocAllowed>( + static_cast> const &>(other)), + kind_(other.kind_), + decorators_(allocator->Adapter()), + declarators_(allocator->Adapter()) +{ + for (auto const &d : other.decorators_) { + decorators_.emplace_back(d->Clone(allocator, nullptr)); + decorators_.back()->SetParent(this); + } + + for (auto const &d : other.declarators_) { + declarators_.emplace_back(d->Clone(allocator, nullptr)->AsVariableDeclarator()); + declarators_.back()->SetParent(this); + } + + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } VariableDeclaration *VariableDeclaration::Clone(ArenaAllocator *const allocator, AstNode *const parent) @@ -153,7 +249,7 @@ VariableDeclaration *VariableDeclaration::Clone(ArenaAllocator *const allocator, if (parent != nullptr) { clone->SetParent(parent); } - clone->SetRange(range_); + clone->SetRange(Range()); return clone; } diff --git a/ets2panda/ir/statements/variableDeclaration.h b/ets2panda/ir/statements/variableDeclaration.h index 7b3f8a5804..cb3703b27d 100644 --- a/ets2panda/ir/statements/variableDeclaration.h +++ b/ets2panda/ir/statements/variableDeclaration.h @@ -40,28 +40,54 @@ public: decorators_(allocator->Adapter()), declarators_(std::move(declarators)) { + InitHistory(); + } + + explicit VariableDeclaration(VariableDeclarationKind kind, ArenaAllocator *allocator, + ArenaVector &&declarators, AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::VARIABLE_DECLARATION, allocator), + kind_(kind), + decorators_(allocator->Adapter()), + declarators_(std::move(declarators)) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } explicit VariableDeclaration(Tag tag, VariableDeclaration const &other, ArenaAllocator *allocator); + explicit VariableDeclaration(Tag const tag, VariableDeclaration const &other, ArenaAllocator *const allocator, + AstNodeHistory *history); + const ArenaVector &Declarators() const { - return declarators_; + return GetHistoryNodeAs()->declarators_; } + [[nodiscard]] const ArenaVector &Declarators(); + + [[nodiscard]] ArenaVector &DeclaratorsForUpdate(); + VariableDeclarationKind Kind() const { - return kind_; + return GetHistoryNodeAs()->kind_; } const ArenaVector &Decorators() const { - return decorators_; + return GetHistoryNodeAs()->decorators_; } + [[nodiscard]] const ArenaVector &Decorators(); + + [[nodiscard]] ArenaVector &DecoratorsForUpdate(); + VariableDeclarator *GetDeclaratorByName(util::StringView name) const { - for (VariableDeclarator *declarator : declarators_) { + for (VariableDeclarator *declarator : Declarators()) { if (declarator->Id()->AsIdentifier()->Name().Compare(name) == 0) { return declarator; } @@ -69,14 +95,10 @@ public: return nullptr; } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -105,6 +127,13 @@ public: private: friend class SizeOfNodeTest; + void SetValueDecorators(Decorator *source, size_t index); + void SetValueDeclarators(VariableDeclarator *source, size_t index); + void EmplaceDecorators(Decorator *source); + void ClearDecorators(); + void EmplaceDeclarators(VariableDeclarator *source); + void ClearDeclarators(); + VariableDeclarationKind kind_; ArenaVector decorators_; ArenaVector declarators_; diff --git a/ets2panda/ir/ts/tsAnyKeyword.cpp b/ets2panda/ir/ts/tsAnyKeyword.cpp index 99f5e085a2..f8cde5748f 100644 --- a/ets2panda/ir/ts/tsAnyKeyword.cpp +++ b/ets2panda/ir/ts/tsAnyKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSAnyKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSAnyKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsArrayType.cpp b/ets2panda/ir/ts/tsArrayType.cpp index 8a1e1abd2c..8ab2361fb9 100644 --- a/ets2panda/ir/ts/tsArrayType.cpp +++ b/ets2panda/ir/ts/tsArrayType.cpp @@ -27,12 +27,8 @@ void TSArrayType::TransformChildren(const NodeTransformer &cb, std::string_view elementType_->SetTransformedNode(transformationName, transformedNode); elementType_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSArrayType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsBigintKeyword.cpp b/ets2panda/ir/ts/tsBigintKeyword.cpp index 7b42542a7d..0e6a288d94 100644 --- a/ets2panda/ir/ts/tsBigintKeyword.cpp +++ b/ets2panda/ir/ts/tsBigintKeyword.cpp @@ -26,12 +26,7 @@ namespace ark::es2panda::ir { void TSBigintKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSBigintKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsBooleanKeyword.cpp b/ets2panda/ir/ts/tsBooleanKeyword.cpp index 4d5b6f018a..bae3ac4ae1 100644 --- a/ets2panda/ir/ts/tsBooleanKeyword.cpp +++ b/ets2panda/ir/ts/tsBooleanKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSBooleanKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSBooleanKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsConditionalType.cpp b/ets2panda/ir/ts/tsConditionalType.cpp index 6a70708b5c..6a166ea3f0 100644 --- a/ets2panda/ir/ts/tsConditionalType.cpp +++ b/ets2panda/ir/ts/tsConditionalType.cpp @@ -43,12 +43,8 @@ void TSConditionalType::TransformChildren(const NodeTransformer &cb, std::string falseType_->SetTransformedNode(transformationName, transformedNode); falseType_ = transformedNode->AsExpression(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSConditionalType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsConstructorType.cpp b/ets2panda/ir/ts/tsConstructorType.cpp index 681161a310..327034616d 100644 --- a/ets2panda/ir/ts/tsConstructorType.cpp +++ b/ets2panda/ir/ts/tsConstructorType.cpp @@ -26,12 +26,7 @@ namespace ark::es2panda::ir { void TSConstructorType::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { signature_.TransformChildren(cb, transformationName); - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSConstructorType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsEnumDeclaration.cpp b/ets2panda/ir/ts/tsEnumDeclaration.cpp index 42603eda1e..c3d9c28f02 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.cpp +++ b/ets2panda/ir/ts/tsEnumDeclaration.cpp @@ -25,37 +25,57 @@ #include "utils/arena_containers.h" namespace ark::es2panda::ir { + +void TSEnumDeclaration::SetInternalName(util::StringView internalName) +{ + this->GetOrCreateHistoryNodeAs()->internalName_ = internalName; +} + +void TSEnumDeclaration::SetBoxedClass(ClassDefinition *boxedClass) +{ + this->GetOrCreateHistoryNodeAs()->boxedClass_ = boxedClass; +} + +void TSEnumDeclaration::SetKey(Identifier *key) +{ + this->GetOrCreateHistoryNodeAs()->key_ = key; +} + void TSEnumDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - if (auto *transformedNode = cb(key_); key_ != transformedNode) { - key_->SetTransformedNode(transformationName, transformedNode); - key_ = transformedNode->AsIdentifier(); + auto const key = Key(); + if (auto *transformedNode = cb(key); key != transformedNode) { + key->SetTransformedNode(transformationName, transformedNode); + SetKey(transformedNode->AsIdentifier()); } - for (auto *&it : VectorIterationGuard(members_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode; + auto const &members = Members(); + for (size_t ix = 0; ix < members.size(); ix++) { + if (auto *transformedNode = cb(members[ix]); members[ix] != transformedNode) { + members[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueMembers(transformedNode->AsDecorator(), ix); } } } void TSEnumDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } - cb(key_); + auto const key = GetHistoryNode()->AsTSEnumDeclaration()->key_; + cb(key); - for (auto *it : VectorIterationGuard(members_)) { + for (auto *it : VectorIterationGuard(Members())) { cb(it); } } @@ -63,10 +83,10 @@ void TSEnumDeclaration::Iterate(const NodeTraverser &cb) const void TSEnumDeclaration::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "TSEnumDeclaration"}, - {"decorators", AstDumper::Optional(decorators_)}, - {"id", key_}, - {"members", members_}, - {"const", isConst_}, + {"decorators", AstDumper::Optional(Decorators())}, + {"id", Key()}, + {"members", Members()}, + {"const", IsConst()}, {"declare", IsDeclare()}}); } @@ -105,14 +125,15 @@ void TSEnumDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("declare "); } dumper->Add("enum "); - key_->Dump(dumper); + Key()->Dump(dumper); dumper->Add(" {"); - if (!members_.empty()) { + auto const members = Members(); + if (!members.empty()) { dumper->IncrIndent(); dumper->Endl(); - for (auto member : members_) { + for (auto member : members) { member->Dump(dumper); - if (member != members_.back()) { + if (member != members.back()) { dumper->Add(","); dumper->Endl(); } @@ -188,4 +209,56 @@ void TSEnumDeclaration::CopyTo(AstNode *other) const TypedStatement::CopyTo(other); } +void TSEnumDeclaration::EmplaceDecorators(Decorator *source) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.emplace_back(source); +} + +void TSEnumDeclaration::ClearDecorators() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.clear(); +} + +void TSEnumDeclaration::SetValueDecorators(Decorator *source, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->decorators_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = source; +} + +[[nodiscard]] ArenaVector &TSEnumDeclaration::DecoratorsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->decorators_; +} + +void TSEnumDeclaration::EmplaceMembers(AstNode *source) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->members_.emplace_back(source); +} + +void TSEnumDeclaration::ClearMembers() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->members_.clear(); +} + +void TSEnumDeclaration::SetValueMembers(AstNode *source, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->members_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = source; +} + +[[nodiscard]] ArenaVector &TSEnumDeclaration::MembersForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->members_; +} + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsEnumDeclaration.h b/ets2panda/ir/ts/tsEnumDeclaration.h index ffb58b6153..87bb7c13fd 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.h +++ b/ets2panda/ir/ts/tsEnumDeclaration.h @@ -52,6 +52,28 @@ public: if (flags.isDeclare) { AddModifier(ModifierFlags::DECLARE); } + InitHistory(); + } + + explicit TSEnumDeclaration(ArenaAllocator *allocator, Identifier *key, ArenaVector &&members, + ConstructorFlags &&flags, AstNodeHistory *history) + : TypedStatement(AstNodeType::TS_ENUM_DECLARATION), + decorators_(allocator->Adapter()), + key_(key), + members_(std::move(members)), + isConst_(flags.isConst) + { + if (flags.isStatic) { + AddModifier(ModifierFlags::STATIC); + } + if (flags.isDeclare) { + AddModifier(ModifierFlags::DECLARE); + } + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } [[nodiscard]] bool IsScopeBearer() const noexcept override @@ -61,73 +83,63 @@ public: [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - return scope_; + return GetHistoryNodeAs()->scope_; } void SetScope(varbinder::LocalScope *scope) { - ES2PANDA_ASSERT(scope_ == nullptr); - scope_ = scope; + ES2PANDA_ASSERT(Scope() == nullptr); + GetOrCreateHistoryNode()->AsTSEnumDeclaration()->scope_ = scope; } void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } const Identifier *Key() const { - return key_; + return GetHistoryNodeAs()->key_; } Identifier *Key() { - return key_; + return GetHistoryNodeAs()->key_; } const ArenaVector &Members() const { - return members_; + return GetHistoryNodeAs()->members_; } const util::StringView &InternalName() const { - return internalName_; + return GetHistoryNodeAs()->internalName_; } - void SetInternalName(util::StringView internalName) - { - internalName_ = internalName; - } + void SetInternalName(util::StringView internalName); ir::ClassDefinition *BoxedClass() const { - return boxedClass_; + return GetHistoryNodeAs()->boxedClass_; } - void SetBoxedClass(ir::ClassDefinition *const wrapperClass) - { - boxedClass_ = wrapperClass; - } + void SetBoxedClass(ir::ClassDefinition *boxedClass); bool IsConst() const { - return isConst_; + return GetHistoryNodeAs()->isConst_; } const ArenaVector &Decorators() const { - return decorators_; - } - - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); + return GetHistoryNodeAs()->decorators_; } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = GetOrCreateHistoryNodeAs(); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -154,9 +166,21 @@ public: TSEnumDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + void EmplaceDecorators(Decorator *source); + void ClearDecorators(); + void SetValueDecorators(Decorator *source, size_t index); + [[nodiscard]] ArenaVector &DecoratorsForUpdate(); + + void EmplaceMembers(AstNode *source); + void ClearMembers(); + void SetValueMembers(AstNode *source, size_t index); + [[nodiscard]] ArenaVector &MembersForUpdate(); + private: bool RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const; friend class SizeOfNodeTest; + void SetKey(Identifier *key); + varbinder::LocalScope *scope_ {nullptr}; ArenaVector decorators_; Identifier *key_; diff --git a/ets2panda/ir/ts/tsFunctionType.cpp b/ets2panda/ir/ts/tsFunctionType.cpp index ed1698e0a2..89e4751aeb 100644 --- a/ets2panda/ir/ts/tsFunctionType.cpp +++ b/ets2panda/ir/ts/tsFunctionType.cpp @@ -27,12 +27,7 @@ namespace ark::es2panda::ir { void TSFunctionType::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { signature_.TransformChildren(cb, transformationName); - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSFunctionType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsImportType.cpp b/ets2panda/ir/ts/tsImportType.cpp index 7854c7d3c8..a0f981b892 100644 --- a/ets2panda/ir/ts/tsImportType.cpp +++ b/ets2panda/ir/ts/tsImportType.cpp @@ -44,12 +44,8 @@ void TSImportType::TransformChildren(const NodeTransformer &cb, std::string_view qualifier_ = transformedNode->AsExpression(); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSImportType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsIndexedAccessType.cpp b/ets2panda/ir/ts/tsIndexedAccessType.cpp index f2d897be6e..e1e110231a 100644 --- a/ets2panda/ir/ts/tsIndexedAccessType.cpp +++ b/ets2panda/ir/ts/tsIndexedAccessType.cpp @@ -34,12 +34,8 @@ void TSIndexedAccessType::TransformChildren(const NodeTransformer &cb, std::stri indexType_->SetTransformedNode(transformationName, transformedNode); indexType_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSIndexedAccessType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsInferType.cpp b/ets2panda/ir/ts/tsInferType.cpp index 5db886b2e4..dd9d1746dc 100644 --- a/ets2panda/ir/ts/tsInferType.cpp +++ b/ets2panda/ir/ts/tsInferType.cpp @@ -29,12 +29,8 @@ void TSInferType::TransformChildren(const NodeTransformer &cb, std::string_view typeParam_->SetTransformedNode(transformationName, transformedNode); typeParam_ = transformedNode->AsTSTypeParameter(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSInferType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp index bea508e388..4455a8b776 100644 --- a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp +++ b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp @@ -34,50 +34,139 @@ #include "util/language.h" namespace ark::es2panda::ir { + +void TSInterfaceDeclaration::SetInternalName(util::StringView internalName) +{ + this->GetOrCreateHistoryNodeAs()->internalName_ = internalName; +} + +void TSInterfaceDeclaration::SetAnonClass(ClassDeclaration *anonClass) +{ + this->GetOrCreateHistoryNodeAs()->anonClass_ = anonClass; +} + +void TSInterfaceDeclaration::SetId(Identifier *id) +{ + this->GetOrCreateHistoryNodeAs()->id_ = id; +} + +void TSInterfaceDeclaration::SetTypeParams(TSTypeParameterDeclaration *typeParams) +{ + this->GetOrCreateHistoryNodeAs()->typeParams_ = typeParams; +} + +void TSInterfaceDeclaration::SetBody(TSInterfaceBody *body) +{ + this->GetOrCreateHistoryNodeAs()->body_ = body; +} + +void TSInterfaceDeclaration::EmplaceExtends(TSInterfaceHeritage *extends) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->extends_.emplace_back(extends); +} + +void TSInterfaceDeclaration::ClearExtends() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->extends_.clear(); +} + +void TSInterfaceDeclaration::SetValueExtends(TSInterfaceHeritage *extends, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->extends_; + arenaVector[index] = extends; +} + +[[nodiscard]] const ArenaVector &TSInterfaceDeclaration::Extends() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->extends_; +} + +[[nodiscard]] ArenaVector &TSInterfaceDeclaration::ExtendsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->extends_; +} + +void TSInterfaceDeclaration::EmplaceDecorators(Decorator *decorators) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.emplace_back(decorators); +} + +void TSInterfaceDeclaration::ClearDecorators() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.clear(); +} + +void TSInterfaceDeclaration::SetValueDecorators(Decorator *decorators, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->decorators_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = decorators; +} + +[[nodiscard]] const ArenaVector &TSInterfaceDeclaration::Decorators() +{ + auto newNode = this->GetHistoryNodeAs(); + return newNode->decorators_; +} + +[[nodiscard]] ArenaVector &TSInterfaceDeclaration::DecoratorsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->decorators_; +} + void TSInterfaceDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - for (auto *&it : Annotations()) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); - if (auto *transformedNode = cb(id_); id_ != transformedNode) { - id_->SetTransformedNode(transformationName, transformedNode); - id_ = transformedNode->AsIdentifier(); + auto const id = Id(); + if (auto *transformedNode = cb(id); id != transformedNode) { + id->SetTransformedNode(transformationName, transformedNode); + SetId(transformedNode->AsIdentifier()); } - if (typeParams_ != nullptr) { - if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) { - typeParams_->SetTransformedNode(transformationName, transformedNode); - typeParams_ = transformedNode->AsTSTypeParameterDeclaration(); + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { + if (auto *transformedNode = cb(typeParams); typeParams != transformedNode) { + typeParams->SetTransformedNode(transformationName, transformedNode); + SetTypeParams(transformedNode->AsTSTypeParameterDeclaration()); } } - for (auto *&it : VectorIterationGuard(extends_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsTSInterfaceHeritage(); + auto const &extends = Extends(); + for (size_t ix = 0; ix < extends.size(); ix++) { + if (auto *transformedNode = cb(extends[ix]); extends[ix] != transformedNode) { + extends[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueExtends(transformedNode->AsTSInterfaceHeritage(), ix); } } - if (auto *transformedNode = cb(body_); body_ != transformedNode) { - body_->SetTransformedNode(transformationName, transformedNode); - body_ = transformedNode->AsTSInterfaceBody(); + auto const &body = Body(); + if (auto *transformedNode = cb(body); body != transformedNode) { + body->SetTransformedNode(transformationName, transformedNode); + SetBody(transformedNode->AsTSInterfaceBody()); } } void TSInterfaceDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -85,28 +174,31 @@ void TSInterfaceDeclaration::Iterate(const NodeTraverser &cb) const cb(it); } - cb(id_); + auto const id = GetHistoryNode()->AsTSInterfaceDeclaration()->id_; + cb(id); - if (typeParams_ != nullptr) { - cb(typeParams_); + auto const typeParams = GetHistoryNode()->AsTSInterfaceDeclaration()->typeParams_; + if (typeParams != nullptr) { + cb(typeParams); } - for (auto *it : VectorIterationGuard(extends_)) { + for (auto *it : VectorIterationGuard(Extends())) { cb(it); } - cb(body_); + auto const body = GetHistoryNode()->AsTSInterfaceDeclaration()->body_; + cb(body); } void TSInterfaceDeclaration::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "TSInterfaceDeclaration"}, - {"decorators", AstDumper::Optional(decorators_)}, + {"decorators", AstDumper::Optional(Decorators())}, {"annotations", AstDumper::Optional(Annotations())}, - {"body", body_}, - {"id", id_}, - {"extends", extends_}, - {"typeParameters", AstDumper::Optional(typeParams_)}}); + {"body", Body()}, + {"id", Id()}, + {"extends", Extends()}, + {"typeParameters", AstDumper::Optional(TypeParams())}}); } bool TSInterfaceDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const @@ -149,28 +241,32 @@ void TSInterfaceDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("declare "); } dumper->Add("interface "); - id_->Dump(dumper); + Id()->Dump(dumper); - if (typeParams_ != nullptr) { + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { dumper->Add("<"); - typeParams_->Dump(dumper); + typeParams->Dump(dumper); dumper->Add(">"); } - if (!extends_.empty()) { + + auto const extends = Extends(); + if (!extends.empty()) { dumper->Add(" extends "); - for (auto ext : extends_) { + for (auto ext : extends) { ext->Dump(dumper); - if (ext != extends_.back()) { + if (ext != extends.back()) { dumper->Add(", "); } } } + auto body = Body(); dumper->Add(" {"); - if (body_ != nullptr) { + if (body != nullptr) { dumper->IncrIndent(); dumper->Endl(); - body_->Dump(dumper); + body->Dump(dumper); dumper->DecrIndent(); dumper->Endl(); } diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.h b/ets2panda/ir/ts/tsInterfaceDeclaration.h index fb338b4c96..64e6a30e70 100644 --- a/ets2panda/ir/ts/tsInterfaceDeclaration.h +++ b/ets2panda/ir/ts/tsInterfaceDeclaration.h @@ -58,6 +58,29 @@ public: if (isStatic_) { AddModifier(ir::ModifierFlags::STATIC); } + InitHistory(); + } + + explicit TSInterfaceDeclaration(ArenaAllocator *allocator, ArenaVector &&extends, + ConstructorData &&data, AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::TS_INTERFACE_DECLARATION, allocator), + decorators_(allocator->Adapter()), + id_(data.id), + typeParams_(data.typeParams), + body_(data.body), + extends_(std::move(extends)), + isStatic_(data.isStatic), + isExternal_(data.isExternal), + lang_(data.lang) + { + if (isStatic_) { + AddModifier(ir::ModifierFlags::STATIC); + } + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } [[nodiscard]] bool IsScopeBearer() const noexcept override @@ -67,93 +90,84 @@ public: [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - return scope_; + return GetHistoryNodeAs()->scope_; } void SetScope(varbinder::LocalScope *scope) { - ES2PANDA_ASSERT(scope_ == nullptr); - scope_ = scope; + ES2PANDA_ASSERT(Scope() == nullptr); + GetOrCreateHistoryNode()->AsTSInterfaceDeclaration()->scope_ = scope; } void ClearScope() noexcept override { - scope_ = nullptr; + GetOrCreateHistoryNode()->AsTSInterfaceDeclaration()->scope_ = nullptr; } TSInterfaceBody *Body() { - return body_; + return GetHistoryNodeAs()->body_; } const TSInterfaceBody *Body() const { - return body_; + return GetHistoryNodeAs()->body_; } Identifier *Id() { - return id_; + return GetHistoryNodeAs()->id_; } const Identifier *Id() const { - return id_; + return GetHistoryNodeAs()->id_; } const util::StringView &InternalName() const { - return internalName_; + return GetHistoryNodeAs()->internalName_; } - void SetInternalName(util::StringView internalName) - { - internalName_ = internalName; - } + void SetInternalName(util::StringView internalName); bool IsStatic() const { - return isStatic_; + return GetHistoryNodeAs()->isStatic_; } bool IsFromExternal() const { - return isExternal_; + return GetHistoryNodeAs()->isExternal_; } const TSTypeParameterDeclaration *TypeParams() const { - return typeParams_; + return GetHistoryNodeAs()->typeParams_; } TSTypeParameterDeclaration *TypeParams() { - return typeParams_; + return GetHistoryNodeAs()->typeParams_; } - ArenaVector &Extends() - { - return extends_; - } + [[nodiscard]] const ArenaVector &Extends(); + [[nodiscard]] ArenaVector &ExtendsForUpdate(); const ArenaVector &Extends() const { - return extends_; + return GetHistoryNodeAs()->extends_; } const ArenaVector &Decorators() const { - return decorators_; - } - - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); + return GetHistoryNodeAs()->decorators_; } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -165,23 +179,20 @@ public: es2panda::Language Language() const { - return lang_; + return GetHistoryNodeAs()->lang_; } ClassDeclaration *GetAnonClass() noexcept { - return anonClass_; + return GetHistoryNodeAs()->anonClass_; } ClassDeclaration *GetAnonClass() const noexcept { - return anonClass_; + return GetHistoryNodeAs()->anonClass_; } - void SetAnonClass(ClassDeclaration *anonClass) noexcept - { - anonClass_ = anonClass; - } + void SetAnonClass(ClassDeclaration *anonClass); void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; @@ -200,9 +211,23 @@ public: TSInterfaceDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + void EmplaceExtends(TSInterfaceHeritage *extends); + void ClearExtends(); + void SetValueExtends(TSInterfaceHeritage *extends, size_t index); + + void EmplaceDecorators(Decorator *decorators); + void ClearDecorators(); + void SetValueDecorators(Decorator *decorators, size_t index); + [[nodiscard]] const ArenaVector &Decorators(); + [[nodiscard]] ArenaVector &DecoratorsForUpdate(); + private: bool RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const; friend class SizeOfNodeTest; + void SetId(Identifier *id); + void SetTypeParams(TSTypeParameterDeclaration *typeParams); + void SetBody(TSInterfaceBody *body); + ArenaVector decorators_; varbinder::LocalScope *scope_ {nullptr}; Identifier *id_; diff --git a/ets2panda/ir/ts/tsIntersectionType.cpp b/ets2panda/ir/ts/tsIntersectionType.cpp index 75cf7834dc..6dc630a18a 100644 --- a/ets2panda/ir/ts/tsIntersectionType.cpp +++ b/ets2panda/ir/ts/tsIntersectionType.cpp @@ -31,12 +31,8 @@ void TSIntersectionType::TransformChildren(const NodeTransformer &cb, std::strin it = transformedNode->AsExpression(); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSIntersectionType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsLiteralType.cpp b/ets2panda/ir/ts/tsLiteralType.cpp index 25a998cc17..a679912bf4 100644 --- a/ets2panda/ir/ts/tsLiteralType.cpp +++ b/ets2panda/ir/ts/tsLiteralType.cpp @@ -28,12 +28,8 @@ void TSLiteralType::TransformChildren(const NodeTransformer &cb, std::string_vie literal_->SetTransformedNode(transformationName, transformedNode); literal_ = transformedNode->AsExpression(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSLiteralType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsMappedType.cpp b/ets2panda/ir/ts/tsMappedType.cpp index fef66f0e8c..61da853b75 100644 --- a/ets2panda/ir/ts/tsMappedType.cpp +++ b/ets2panda/ir/ts/tsMappedType.cpp @@ -37,12 +37,8 @@ void TSMappedType::TransformChildren(const NodeTransformer &cb, std::string_view typeAnnotation_ = static_cast(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSMappedType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsNamedTupleMember.cpp b/ets2panda/ir/ts/tsNamedTupleMember.cpp index d07fb3d982..742f9e6cd4 100644 --- a/ets2panda/ir/ts/tsNamedTupleMember.cpp +++ b/ets2panda/ir/ts/tsNamedTupleMember.cpp @@ -34,12 +34,8 @@ void TSNamedTupleMember::TransformChildren(const NodeTransformer &cb, std::strin elementType_->SetTransformedNode(transformationName, transformedNode); elementType_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSNamedTupleMember::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsNeverKeyword.cpp b/ets2panda/ir/ts/tsNeverKeyword.cpp index 9b1386dcad..a48751933c 100644 --- a/ets2panda/ir/ts/tsNeverKeyword.cpp +++ b/ets2panda/ir/ts/tsNeverKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSNeverKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSNeverKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsNullKeyword.cpp b/ets2panda/ir/ts/tsNullKeyword.cpp index d7050a9ff3..6e089e142a 100644 --- a/ets2panda/ir/ts/tsNullKeyword.cpp +++ b/ets2panda/ir/ts/tsNullKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSNullKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSNullKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsNumberKeyword.cpp b/ets2panda/ir/ts/tsNumberKeyword.cpp index 9c9125def9..afcee6e7b5 100644 --- a/ets2panda/ir/ts/tsNumberKeyword.cpp +++ b/ets2panda/ir/ts/tsNumberKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSNumberKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSNumberKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsObjectKeyword.cpp b/ets2panda/ir/ts/tsObjectKeyword.cpp index fd807caf03..3b4ea39d6e 100644 --- a/ets2panda/ir/ts/tsObjectKeyword.cpp +++ b/ets2panda/ir/ts/tsObjectKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSObjectKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSObjectKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsParenthesizedType.cpp b/ets2panda/ir/ts/tsParenthesizedType.cpp index 4ee640455b..4608efb394 100644 --- a/ets2panda/ir/ts/tsParenthesizedType.cpp +++ b/ets2panda/ir/ts/tsParenthesizedType.cpp @@ -28,12 +28,8 @@ void TSParenthesizedType::TransformChildren(const NodeTransformer &cb, std::stri type_->SetTransformedNode(transformationName, transformedNode); type_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSParenthesizedType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsStringKeyword.cpp b/ets2panda/ir/ts/tsStringKeyword.cpp index 825b446bc4..be62a34004 100644 --- a/ets2panda/ir/ts/tsStringKeyword.cpp +++ b/ets2panda/ir/ts/tsStringKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSStringKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSStringKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsThisType.cpp b/ets2panda/ir/ts/tsThisType.cpp index da5e36ad8c..9af97be93c 100644 --- a/ets2panda/ir/ts/tsThisType.cpp +++ b/ets2panda/ir/ts/tsThisType.cpp @@ -24,12 +24,7 @@ namespace ark::es2panda::ir { void TSThisType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSThisType::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTupleType.cpp b/ets2panda/ir/ts/tsTupleType.cpp index cb69e8542c..d98cbd1622 100644 --- a/ets2panda/ir/ts/tsTupleType.cpp +++ b/ets2panda/ir/ts/tsTupleType.cpp @@ -35,12 +35,8 @@ void TSTupleType::TransformChildren(const NodeTransformer &cb, std::string_view it = static_cast(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTupleType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp b/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp index 26bcca0adb..75532d6015 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp @@ -27,31 +27,46 @@ #include "ir/ts/tsTypeParameterDeclaration.h" namespace ark::es2panda::ir { + +void TSTypeAliasDeclaration::SetTypeParameters(TSTypeParameterDeclaration *typeParams) +{ + this->GetOrCreateHistoryNodeAs()->typeParams_ = typeParams; +} + +void TSTypeAliasDeclaration::SetId(Identifier *id) +{ + this->GetOrCreateHistoryNodeAs()->id_ = id; +} + void TSTypeAliasDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - for (auto *&it : Annotations()) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + auto const &annotations = Annotations(); + for (size_t ix = 0; ix < annotations.size(); ix++) { + if (auto *transformedNode = cb(annotations[ix]); annotations[ix] != transformedNode) { + annotations[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), ix); } } - if (auto *transformedNode = cb(id_); id_ != transformedNode) { - id_->SetTransformedNode(transformationName, transformedNode); - id_ = transformedNode->AsIdentifier(); + auto const id = Id(); + if (auto *transformedNode = cb(id); id != transformedNode) { + id->SetTransformedNode(transformationName, transformedNode); + SetId(transformedNode->AsIdentifier()); } - if (typeParams_ != nullptr) { - if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) { - typeParams_->SetTransformedNode(transformationName, transformedNode); - typeParams_ = transformedNode->AsTSTypeParameterDeclaration(); + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { + if (auto *transformedNode = cb(typeParams); typeParams != transformedNode) { + typeParams->SetTransformedNode(transformationName, transformedNode); + SetTypeParameters(transformedNode->AsTSTypeParameterDeclaration()); } } @@ -65,7 +80,7 @@ void TSTypeAliasDeclaration::TransformChildren(const NodeTransformer &cb, std::s void TSTypeAliasDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -73,10 +88,12 @@ void TSTypeAliasDeclaration::Iterate(const NodeTraverser &cb) const cb(it); } - cb(id_); + auto const id = GetHistoryNode()->AsTSTypeAliasDeclaration()->id_; + cb(id); - if (typeParams_ != nullptr) { - cb(typeParams_); + auto typeParams = GetHistoryNode()->AsTSTypeAliasDeclaration()->typeParams_; + if (typeParams != nullptr) { + cb(typeParams); } if (TypeAnnotation() != nullptr) { @@ -87,11 +104,11 @@ void TSTypeAliasDeclaration::Iterate(const NodeTraverser &cb) const void TSTypeAliasDeclaration::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "TSTypeAliasDeclaration"}, - {"decorators", AstDumper::Optional(decorators_)}, + {"decorators", AstDumper::Optional(Decorators())}, {"annotations", AstDumper::Optional(Annotations())}, - {"id", id_}, + {"id", Id()}, {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}, - {"typeParameters", AstDumper::Optional(typeParams_)}}); + {"typeParameters", AstDumper::Optional(TypeParams())}}); } bool TSTypeAliasDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const @@ -126,14 +143,15 @@ void TSTypeAliasDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("export "); } dumper->Add("type "); - id_->Dump(dumper); - if (typeParams_ != nullptr) { + Id()->Dump(dumper); + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { dumper->Add("<"); - typeParams_->Dump(dumper); + typeParams->Dump(dumper); dumper->Add(">"); } dumper->Add(" = "); - if (id_->IsAnnotatedExpression()) { + if (Id()->IsAnnotatedExpression()) { auto type = TypeAnnotation(); ES2PANDA_ASSERT(type); type->Dump(dumper); @@ -180,4 +198,82 @@ void TSTypeAliasDeclaration::CopyTo(AstNode *other) const JsDocAllowed::CopyTo(other); } +void TSTypeAliasDeclaration::EmplaceDecorators(Decorator *decorators) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.emplace_back(decorators); +} + +void TSTypeAliasDeclaration::ClearDecorators() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->decorators_.clear(); +} + +void TSTypeAliasDeclaration::SetValueDecorators(Decorator *decorators, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->decorators_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = decorators; +} + +[[nodiscard]] ArenaVector &TSTypeAliasDeclaration::DecoratorsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->decorators_; +} + +void TSTypeAliasDeclaration::EmplaceTypeParamterTypes(checker::Type *typeParamTypes) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->typeParamTypes_.emplace_back(typeParamTypes); +} + +void TSTypeAliasDeclaration::ClearTypeParamterTypes() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->typeParamTypes_.clear(); +} + +void TSTypeAliasDeclaration::SetValueTypeParamterTypes(checker::Type *typeParamTypes, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->typeParamTypes_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = typeParamTypes; +} + +[[nodiscard]] ArenaVector &TSTypeAliasDeclaration::TypeParamterTypesForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->typeParamTypes_; +} + +void TSTypeAliasDeclaration::EmplaceAnnotations(AnnotationUsage *annotations) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->annotations_.emplace_back(annotations); +} + +void TSTypeAliasDeclaration::ClearAnnotations() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + newNode->annotations_.clear(); +} + +void TSTypeAliasDeclaration::SetValueAnnotations(AnnotationUsage *annotations, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->annotations_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = annotations; +} + +[[nodiscard]] ArenaVector &TSTypeAliasDeclaration::AnnotationsForUpdate() +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + return newNode->annotations_; +} + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.h b/ets2panda/ir/ts/tsTypeAliasDeclaration.h index 4d44e90021..fb9b8c160d 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.h +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.h @@ -40,6 +40,7 @@ public: typeParams_(typeParams), typeParamTypes_(allocator->Adapter()) { + InitHistory(); } explicit TSTypeAliasDeclaration(ArenaAllocator *allocator, Identifier *id) @@ -50,41 +51,35 @@ public: typeParams_(nullptr), typeParamTypes_(allocator->Adapter()) { + InitHistory(); } Identifier *Id() { - return id_; + return GetHistoryNodeAs()->id_; } const Identifier *Id() const { - return id_; + return GetHistoryNodeAs()->id_; } TSTypeParameterDeclaration *TypeParams() const { - return typeParams_; + return GetHistoryNodeAs()->typeParams_; } const ArenaVector &Decorators() const { - return decorators_; + return GetHistoryNodeAs()->decorators_; } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - - void SetTypeParameters(ir::TSTypeParameterDeclaration *typeParams) - { - typeParams_ = typeParams; - } + void SetTypeParameters(ir::TSTypeParameterDeclaration *typeParams); void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -94,28 +89,25 @@ public: void SetTypeParameterTypes(ArenaVector &&typeParamTypes) { - typeParamTypes_ = std::move(typeParamTypes); + auto newNode = reinterpret_cast(GetOrCreateHistoryNode()); + newNode->typeParamTypes_ = std::move(typeParamTypes); } ArenaVector const &TypeParameterTypes() const { - return typeParamTypes_; - } - - [[nodiscard]] ArenaVector &Annotations() noexcept - { - return annotations_; + return GetHistoryNodeAs()->typeParamTypes_; } [[nodiscard]] const ArenaVector &Annotations() const noexcept { - return annotations_; + return GetHistoryNodeAs()->annotations_; } void SetAnnotations(ArenaVector &&annotations) { - annotations_ = std::move(annotations); - for (AnnotationUsage *anno : annotations_) { + auto newNode = reinterpret_cast(GetOrCreateHistoryNode()); + newNode->annotations_ = std::move(annotations); + for (AnnotationUsage *anno : newNode->annotations_) { anno->SetParent(this); } } @@ -137,15 +129,32 @@ public: void CleanUp() override { AstNode::CleanUp(); - typeParamTypes_.clear(); + ClearTypeParamterTypes(); } TSTypeAliasDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + void EmplaceAnnotations(AnnotationUsage *annotations); + void ClearAnnotations(); + void SetValueAnnotations(AnnotationUsage *annotations, size_t index); + [[nodiscard]] ArenaVector &AnnotationsForUpdate(); + + void EmplaceTypeParamterTypes(checker::Type *typeParamTypes); + void ClearTypeParamterTypes(); + void SetValueTypeParamterTypes(checker::Type *typeParamTypes, size_t index); + [[nodiscard]] ArenaVector &TypeParamterTypesForUpdate(); + + void EmplaceDecorators(Decorator *decorators); + void ClearDecorators(); + void SetValueDecorators(Decorator *decorators, size_t index); + [[nodiscard]] ArenaVector &DecoratorsForUpdate(); + private: bool RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const; friend class SizeOfNodeTest; + + void SetId(Identifier *id); ArenaVector decorators_; ArenaVector annotations_; Identifier *id_; diff --git a/ets2panda/ir/ts/tsTypeLiteral.cpp b/ets2panda/ir/ts/tsTypeLiteral.cpp index 418d5aa34d..d13f7662cd 100644 --- a/ets2panda/ir/ts/tsTypeLiteral.cpp +++ b/ets2panda/ir/ts/tsTypeLiteral.cpp @@ -34,12 +34,8 @@ void TSTypeLiteral::TransformChildren(const NodeTransformer &cb, std::string_vie it = transformedNode; } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypeLiteral::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeOperator.cpp b/ets2panda/ir/ts/tsTypeOperator.cpp index 7e66c02843..2fa2ad26ad 100644 --- a/ets2panda/ir/ts/tsTypeOperator.cpp +++ b/ets2panda/ir/ts/tsTypeOperator.cpp @@ -28,12 +28,8 @@ void TSTypeOperator::TransformChildren(const NodeTransformer &cb, std::string_vi type_->SetTransformedNode(transformationName, transformedNode); type_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypeOperator::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeParameter.cpp b/ets2panda/ir/ts/tsTypeParameter.cpp index 88d4b08855..e4a489d111 100644 --- a/ets2panda/ir/ts/tsTypeParameter.cpp +++ b/ets2panda/ir/ts/tsTypeParameter.cpp @@ -25,44 +25,68 @@ #include "utils/arena_containers.h" namespace ark::es2panda::ir { + +void TSTypeParameter::SetConstraint(TypeNode *constraint) +{ + this->GetOrCreateHistoryNodeAs()->constraint_ = constraint; +} + +void TSTypeParameter::SetDefaultType(TypeNode *defaultType) +{ + this->GetOrCreateHistoryNodeAs()->defaultType_ = defaultType; +} + +void TSTypeParameter::SetName(Identifier *name) +{ + this->GetOrCreateHistoryNodeAs()->name_ = name; +} + void TSTypeParameter::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - if (auto *transformedNode = cb(name_); name_ != transformedNode) { - name_->SetTransformedNode(transformationName, transformedNode); - name_ = transformedNode->AsIdentifier(); + auto const name = Name(); + if (auto *transformedNode = cb(name); name != transformedNode) { + name->SetTransformedNode(transformationName, transformedNode); + SetName(transformedNode->AsIdentifier()); } - if (constraint_ != nullptr) { - if (auto *transformedNode = cb(constraint_); constraint_ != transformedNode) { - constraint_->SetTransformedNode(transformationName, transformedNode); - constraint_ = static_cast(transformedNode); + auto const constraint = Constraint(); + if (constraint != nullptr) { + if (auto *transformedNode = cb(constraint); constraint != transformedNode) { + constraint->SetTransformedNode(transformationName, transformedNode); + SetConstraint(static_cast(transformedNode)); } } - if (defaultType_ != nullptr) { - if (auto *transformedNode = cb(defaultType_); defaultType_ != transformedNode) { - defaultType_->SetTransformedNode(transformationName, transformedNode); - defaultType_ = static_cast(transformedNode); + auto const defaultType = DefaultType(); + if (defaultType != nullptr) { + if (auto *transformedNode = cb(defaultType); defaultType != transformedNode) { + defaultType->SetTransformedNode(transformationName, transformedNode); + SetDefaultType(static_cast(transformedNode)); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + + auto const annotations = Annotations(); + for (size_t ix = 0; ix < annotations.size(); ix++) { + if (auto *transformedNode = cb(annotations[ix]); annotations[ix] != transformedNode) { + annotations[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), ix); } } } void TSTypeParameter::Iterate(const NodeTraverser &cb) const { - cb(name_); + auto const name = GetHistoryNodeAs()->name_; + cb(name); - if (constraint_ != nullptr) { - cb(constraint_); + auto const constraint = GetHistoryNodeAs()->constraint_; + if (constraint != nullptr) { + cb(constraint); } - if (defaultType_ != nullptr) { - cb(defaultType_); + auto const defaultType = GetHistoryNodeAs()->defaultType_; + if (defaultType != nullptr) { + cb(defaultType); } for (auto *it : VectorIterationGuard(Annotations())) { cb(it); @@ -72,9 +96,9 @@ void TSTypeParameter::Iterate(const NodeTraverser &cb) const void TSTypeParameter::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "TSTypeParameter"}, - {"name", name_}, - {"constraint", AstDumper::Optional(constraint_)}, - {"default", AstDumper::Optional(defaultType_)}, + {"name", Name()}, + {"constraint", AstDumper::Optional(Constraint())}, + {"default", AstDumper::Optional(DefaultType())}, {"in", AstDumper::Optional(IsIn())}, {"out", AstDumper::Optional(IsOut())}, {"annotations", AstDumper::Optional(Annotations())}}); @@ -92,15 +116,15 @@ void TSTypeParameter::Dump(ir::SrcDumper *dumper) const dumper->Add("out "); } - name_->Dump(dumper); + Name()->Dump(dumper); - if (defaultType_ != nullptr) { + if (DefaultType() != nullptr) { dumper->Add(" = "); - defaultType_->Dump(dumper); + DefaultType()->Dump(dumper); } - if (constraint_ != nullptr) { + if (Constraint() != nullptr) { dumper->Add(" extends "); - constraint_->Dump(dumper); + Constraint()->Dump(dumper); } } diff --git a/ets2panda/ir/ts/tsTypeParameter.h b/ets2panda/ir/ts/tsTypeParameter.h index fff183fc3c..97c92bf6da 100644 --- a/ets2panda/ir/ts/tsTypeParameter.h +++ b/ets2panda/ir/ts/tsTypeParameter.h @@ -31,6 +31,7 @@ public: constraint_(constraint), defaultType_(defaultType) { + InitHistory(); } explicit TSTypeParameter(Identifier *name, TypeNode *constraint, TypeNode *defaultType, ModifierFlags flags, @@ -41,42 +42,67 @@ public: defaultType_(defaultType) { ES2PANDA_ASSERT(flags == ModifierFlags::NONE || flags == ModifierFlags::IN || flags == ModifierFlags::OUT); + InitHistory(); + } + + // CC-OFFNXT(G.FUN.01-CPP) solid logic + explicit TSTypeParameter(Identifier *name, TypeNode *constraint, TypeNode *defaultType, ModifierFlags flags, + ArenaAllocator *const allocator, AstNodeHistory *history) + : AnnotationAllowed(AstNodeType::TS_TYPE_PARAMETER, flags, allocator), + name_(name), + constraint_(constraint), + defaultType_(defaultType) + { + ES2PANDA_ASSERT(flags == ModifierFlags::NONE || flags == ModifierFlags::IN || flags == ModifierFlags::OUT); + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } + } + + explicit TSTypeParameter(Identifier *name, TypeNode *constraint, TypeNode *defaultType, + ArenaAllocator *const allocator, AstNodeHistory *history) + : AnnotationAllowed(AstNodeType::TS_TYPE_PARAMETER, allocator), + name_(name), + constraint_(constraint), + defaultType_(defaultType) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } const Identifier *Name() const { - return name_; + return GetHistoryNodeAs()->name_; } Identifier *Name() { - return name_; + return GetHistoryNodeAs()->name_; } TypeNode *Constraint() { - return constraint_; + return GetHistoryNodeAs()->constraint_; } const TypeNode *Constraint() const { - return constraint_; + return GetHistoryNodeAs()->constraint_; } - void SetConstraint(TypeNode *constraint) - { - constraint_ = constraint; - } + void SetConstraint(TypeNode *constraint); TypeNode *DefaultType() const { - return defaultType_; + return GetHistoryNodeAs()->defaultType_; } - void SetDefaultType(TypeNode *defaultType) - { - defaultType_ = defaultType; - } + void SetDefaultType(TypeNode *defaultType); void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; void Iterate(const NodeTraverser &cb) const override; @@ -97,6 +123,8 @@ public: private: friend class SizeOfNodeTest; + void SetName(Identifier *name); + Identifier *name_; TypeNode *constraint_; TypeNode *defaultType_; diff --git a/ets2panda/ir/ts/tsTypeParameterDeclaration.cpp b/ets2panda/ir/ts/tsTypeParameterDeclaration.cpp index a236ed060c..1ae682e17f 100644 --- a/ets2panda/ir/ts/tsTypeParameterDeclaration.cpp +++ b/ets2panda/ir/ts/tsTypeParameterDeclaration.cpp @@ -23,33 +23,45 @@ #include "ir/ts/tsTypeParameter.h" namespace ark::es2panda::ir { + +void TSTypeParameterDeclaration::SetScope(varbinder::LocalScope *source) +{ + this->GetOrCreateHistoryNodeAs()->scope_ = source; +} + +void TSTypeParameterDeclaration::SetRequiredParams(size_t source) +{ + this->GetOrCreateHistoryNodeAs()->requiredParams_ = source; +} + void TSTypeParameterDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(params_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsTSTypeParameter(); + auto const params = Params(); + for (size_t ix = 0; ix < params.size(); ix++) { + if (auto *transformedNode = cb(params[ix]); params[ix] != transformedNode) { + params[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueParams(transformedNode->AsTSTypeParameter(), ix); } } } void TSTypeParameterDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(params_)) { + for (auto *it : VectorIterationGuard(Params())) { cb(it); } } void TSTypeParameterDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "TSTypeParameterDeclaration"}, {"params", params_}}); + dumper->Add({{"type", "TSTypeParameterDeclaration"}, {"params", Params()}}); } void TSTypeParameterDeclaration::Dump(ir::SrcDumper *dumper) const { - for (auto param : params_) { + for (auto param : Params()) { param->Dump(dumper); - if (param != params_.back()) { + if (param != Params().back()) { dumper->Add(", "); } } diff --git a/ets2panda/ir/ts/tsTypeParameterDeclaration.h b/ets2panda/ir/ts/tsTypeParameterDeclaration.h index 9fef5c44ff..a72497e5ce 100644 --- a/ets2panda/ir/ts/tsTypeParameterDeclaration.h +++ b/ets2panda/ir/ts/tsTypeParameterDeclaration.h @@ -29,6 +29,20 @@ public: params_(std::move(params)), requiredParams_(requiredParams) { + InitHistory(); + } + + explicit TSTypeParameterDeclaration(ArenaVector &¶ms, size_t requiredParams, + AstNodeHistory *history) + : Expression(AstNodeType::TS_TYPE_PARAMETER_DECLARATION), + params_(std::move(params)), + requiredParams_(requiredParams) + { + if (history != nullptr) { + history_ = history; + } else { + InitHistory(); + } } [[nodiscard]] bool IsScopeBearer() const noexcept override @@ -38,35 +52,41 @@ public: [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - return scope_; + return GetHistoryNodeAs()->scope_; } - void SetScope(varbinder::LocalScope *scope) - { - scope_ = scope; - } + void SetScope(varbinder::LocalScope *source); void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } const ArenaVector &Params() const { - return params_; + return GetHistoryNodeAs()->params_; } void AddParam(TSTypeParameter *param) { - if (requiredParams_ == params_.size() && param->DefaultType() == nullptr) { - requiredParams_++; + if (RequiredParams() == Params().size() && param->DefaultType() == nullptr) { + SetRequiredParams(RequiredParams() + 1); } - params_.push_back(param); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + newNode->params_.emplace_back(param); + } + + void SetValueParams(TSTypeParameter *source, size_t index) + { + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + auto &arenaVector = newNode->params_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = source; } size_t RequiredParams() const { - return requiredParams_; + return GetHistoryNodeAs()->requiredParams_; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -88,6 +108,9 @@ public: private: friend class SizeOfNodeTest; + + void SetRequiredParams(size_t source); + ArenaVector params_; varbinder::LocalScope *scope_ {nullptr}; size_t requiredParams_; diff --git a/ets2panda/ir/ts/tsTypePredicate.cpp b/ets2panda/ir/ts/tsTypePredicate.cpp index a1b253d850..0ab2158429 100644 --- a/ets2panda/ir/ts/tsTypePredicate.cpp +++ b/ets2panda/ir/ts/tsTypePredicate.cpp @@ -37,12 +37,8 @@ void TSTypePredicate::TransformChildren(const NodeTransformer &cb, std::string_v typeAnnotation_ = static_cast(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypePredicate::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeQuery.cpp b/ets2panda/ir/ts/tsTypeQuery.cpp index 70fe7b63fc..5fa24495e8 100644 --- a/ets2panda/ir/ts/tsTypeQuery.cpp +++ b/ets2panda/ir/ts/tsTypeQuery.cpp @@ -29,12 +29,8 @@ void TSTypeQuery::TransformChildren(const NodeTransformer &cb, std::string_view exprName_->SetTransformedNode(transformationName, transformedNode); exprName_ = transformedNode->AsExpression(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypeQuery::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeReference.cpp b/ets2panda/ir/ts/tsTypeReference.cpp index 459789b718..57b8f7d2ae 100644 --- a/ets2panda/ir/ts/tsTypeReference.cpp +++ b/ets2panda/ir/ts/tsTypeReference.cpp @@ -44,12 +44,8 @@ void TSTypeReference::TransformChildren(const NodeTransformer &cb, std::string_v typeName_->SetTransformedNode(transformationName, transformedNode); typeName_ = transformedNode->AsExpression(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypeReference::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsUndefinedKeyword.cpp b/ets2panda/ir/ts/tsUndefinedKeyword.cpp index 4070aaf0b2..5053cebca0 100644 --- a/ets2panda/ir/ts/tsUndefinedKeyword.cpp +++ b/ets2panda/ir/ts/tsUndefinedKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSUndefinedKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSUndefinedKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsUnionType.cpp b/ets2panda/ir/ts/tsUnionType.cpp index a25ccceccb..aca8a8aa89 100644 --- a/ets2panda/ir/ts/tsUnionType.cpp +++ b/ets2panda/ir/ts/tsUnionType.cpp @@ -30,12 +30,8 @@ void TSUnionType::TransformChildren(const NodeTransformer &cb, std::string_view it = static_cast(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSUnionType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsUnknownKeyword.cpp b/ets2panda/ir/ts/tsUnknownKeyword.cpp index f1daafebdc..dd0bc5e848 100644 --- a/ets2panda/ir/ts/tsUnknownKeyword.cpp +++ b/ets2panda/ir/ts/tsUnknownKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSUnknownKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSUnknownKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsVoidKeyword.cpp b/ets2panda/ir/ts/tsVoidKeyword.cpp index d5a4341f2c..ff09cc56d8 100644 --- a/ets2panda/ir/ts/tsVoidKeyword.cpp +++ b/ets2panda/ir/ts/tsVoidKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSVoidKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSVoidKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/typed.h b/ets2panda/ir/typed.h index 0c3f32f3ee..cec0ce52c3 100644 --- a/ets2panda/ir/typed.h +++ b/ets2panda/ir/typed.h @@ -38,17 +38,21 @@ public: [[nodiscard]] checker::Type const *TsType() const { - return tsType_; + return AstNode::GetHistoryNodeAs>()->tsType_; } [[nodiscard]] checker::Type *TsType() { - return tsType_; + return AstNode::GetHistoryNodeAs>()->tsType_; } checker::Type *SetTsType(checker::Type *tsType) noexcept { - return (tsType_ = tsType); + auto nowNode = AstNode::GetHistoryNodeAs>(); + if (nowNode->tsType_ != tsType) { + AstNode::GetOrCreateHistoryNodeAs>()->tsType_ = tsType; + } + return tsType; } bool IsTyped() const override diff --git a/ets2panda/lexer/token/sourceLocation.h b/ets2panda/lexer/token/sourceLocation.h index a150a8cfb0..b6557e4d63 100644 --- a/ets2panda/lexer/token/sourceLocation.h +++ b/ets2panda/lexer/token/sourceLocation.h @@ -52,6 +52,11 @@ public: const parser::Program *Program() const; + bool operator!=(const SourcePosition &other) const + { + return index != other.index || line != other.line || program_ != other.program_; + } + private: const parser::Program *program_ {}; }; @@ -68,6 +73,11 @@ public: SourcePosition start {}; SourcePosition end {}; // NOLINTEND(misc-non-private-member-variables-in-classes) + + bool operator!=(const SourceRange &other) const + { + return start != other.start || end != other.end; + } }; class SourceLocation { diff --git a/ets2panda/lsp/src/rename.cpp b/ets2panda/lsp/src/rename.cpp index 10f812d813..e836fb4858 100644 --- a/ets2panda/lsp/src/rename.cpp +++ b/ets2panda/lsp/src/rename.cpp @@ -31,7 +31,7 @@ constexpr size_t QUOTE_START_OFFSET = 1; RenameInfoType GetRenameInfo(es2panda_Context *context, size_t pos) { auto ctx = reinterpret_cast(context); - auto checker = reinterpret_cast(ctx)->checker->AsETSChecker(); + auto checker = reinterpret_cast(ctx)->GetChecker()->AsETSChecker(); auto program = reinterpret_cast(ctx)->parserProgram; auto node = GetAdjustedLocation(GetTouchingPropertyName(context, pos), true, ctx->allocator); if (node.has_value() && NodeIsEligibleForRename(node.value())) { diff --git a/ets2panda/parser/ETSFormattedParser.cpp b/ets2panda/parser/ETSFormattedParser.cpp index 93fac4b3e5..d0b01fdad5 100644 --- a/ets2panda/parser/ETSFormattedParser.cpp +++ b/ets2panda/parser/ETSFormattedParser.cpp @@ -374,7 +374,7 @@ ArenaVector ETSParser::CreateFormattedStatements(std::string_vi ir::AstNode *ETSParser::CreateFormattedClassFieldDefinition(std::string_view sourceCode, std::vector &insertingNodes) { - static ArenaVector const DUMMY_ARRAY {Allocator()->Adapter()}; + thread_local static ArenaVector const DUMMY_ARRAY {Allocator()->Adapter()}; insertingNodes_.swap(insertingNodes); auto *const property = CreateClassElement(sourceCode, DUMMY_ARRAY, ir::ClassDefinitionModifiers::NONE); @@ -390,7 +390,7 @@ ir::AstNode *ETSParser::CreateFormattedClassFieldDefinition(std::string_view sou ir::AstNode *ETSParser::CreateFormattedClassMethodDefinition(std::string_view sourceCode, std::vector &insertingNodes) { - static ArenaVector const DUMMY_ARRAY {Allocator()->Adapter()}; + thread_local static ArenaVector const DUMMY_ARRAY {Allocator()->Adapter()}; insertingNodes_.swap(insertingNodes); auto *const property = CreateClassElement(sourceCode, DUMMY_ARRAY, ir::ClassDefinitionModifiers::NONE); diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 6a1ca88c8b..d5b3151150 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -133,7 +133,7 @@ void ETSParser::ParseProgram(ScriptKind kind) if ((GetContext().Status() & parser::ParserStatus::DEPENDENCY_ANALYZER_MODE) == 0) { script = ParseETSGlobalScript(startLoc, statements); } else { - script = ParseImportsOnly(startLoc, statements); + script = ParseImportsAndReExportOnly(startLoc, statements); } if ((GetContext().Status() & ParserStatus::IN_PACKAGE) != 0) { @@ -167,7 +167,8 @@ ir::ETSModule *ETSParser::ParseETSGlobalScript(lexer::SourcePosition startLoc, A return etsModule; } -ir::ETSModule *ETSParser::ParseImportsOnly(lexer::SourcePosition startLoc, ArenaVector &statements) +ir::ETSModule *ETSParser::ParseImportsAndReExportOnly(lexer::SourcePosition startLoc, + ArenaVector &statements) { ETSNolintParser etsnolintParser(this); etsnolintParser.CollectETSNolints(); @@ -224,11 +225,20 @@ ArenaVector ETSParser::ParseDefaultSources(std::stri std::vector programs; auto *ctx = GetProgram()->VarBinder()->GetContext(); - if (ctx->compilingState != public_lib::CompilingState::MULTI_COMPILING_FOLLOW) { - programs = ParseSources(); - AddExternalSource(programs); + if (ctx->compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW) { + return statements; } + if (!Context()->compiledByCapi) { + AddExternalSource(ParseSources()); + } else { + if (Context()->globalContext != nullptr && Context()->globalContext->stdLibAstCache != nullptr) { + globalProgram_->MergeExternalSource(Context()->globalContext->stdLibAstCache); + importPathManager_->ClearParseList(); + } else { + AddExternalSource(ParseSources()); + } + } return statements; } @@ -279,6 +289,25 @@ static bool SearchImportedExternalSources(ETSParser *parser, const std::string_v return false; } +bool ETSParser::TryMergeFromCache(size_t idx, ArenaVector &parseList) +{ + if (Context()->globalContext == nullptr) { + return false; + } + + auto &importData = parseList[idx].importData; + auto src = importData.HasSpecifiedDeclPath() ? importData.declPath : importData.resolvedSource; + const auto &absPath = std::string {util::Path {src, Allocator()}.GetAbsolutePath()}; + auto cacheExtProgs = Context()->globalContext->cachedExternalPrograms; + if (cacheExtProgs.find(absPath) != cacheExtProgs.end() && cacheExtProgs[absPath] != nullptr) { + if (globalProgram_->MergeExternalSource(cacheExtProgs[absPath])) { + importPathManager_->MarkAsParsed(parseList[idx].importData.resolvedSource); + return true; + } + } + return false; +} + // NOTE (mmartin): Need a more optimal solution here // This is needed, as during a parsing of a file, programs can be re-added to the parseList, which needs to be // re-parsed. This won't change the size of the list, so with only the 'for loop', there can be unparsed files @@ -300,6 +329,11 @@ std::vector ETSParser::SearchForNotParsed(ArenaVectorMarkAsParsed(data.resolvedSource); diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 6c905bafe6..6ca2d6d6c8 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -203,11 +203,13 @@ private: ArenaVector ParseImportDeclarations(); ir::Statement *ParseImportDeclarationHelper(lexer::SourcePosition startLoc, ArenaVector &specifiers, ir::ImportKinds importKind); + bool TryMergeFromCache(size_t idx, ArenaVector &parseList); std::vector SearchForNotParsed(ArenaVector &parseList, ArenaVector &directImportsFromMainSource); parser::Program *ParseSource(const SourceFile &sourceFile); ir::ETSModule *ParseETSGlobalScript(lexer::SourcePosition startLoc, ArenaVector &statements); - ir::ETSModule *ParseImportsOnly(lexer::SourcePosition startLoc, ArenaVector &statements); + ir::ETSModule *ParseImportsAndReExportOnly(lexer::SourcePosition startLoc, + ArenaVector &statements); ir::AstNode *ParseImportDefaultSpecifier(ArenaVector *specifiers) override; void *ApplyAnnotationsToClassElement(ir::AstNode *property, ArenaVector &&annotations, lexer::SourcePosition pos); diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp index c1dc7c92e0..ec767160ae 100644 --- a/ets2panda/parser/ETSparserClasses.cpp +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -821,7 +821,6 @@ ir::MethodDefinition *ETSParser::ParseInterfaceGetterSetterMethod(const ir::Modi return nullptr; } method->AddModifier(ir::ModifierFlags::PUBLIC); - method->SetRange({Lexer()->GetToken().Start(), method->Id()->End()}); if (methodKind == ir::MethodDefinitionKind::GET) { method->Id()->SetAccessor(); method->Function()->AddFlag(ir::ScriptFunctionFlags::GETTER); diff --git a/ets2panda/parser/ETSparserNamespaces.cpp b/ets2panda/parser/ETSparserNamespaces.cpp index ea4a8feb4b..5024059997 100644 --- a/ets2panda/parser/ETSparserNamespaces.cpp +++ b/ets2panda/parser/ETSparserNamespaces.cpp @@ -82,7 +82,7 @@ ir::ETSModule *ETSParser::ParseNamespaceImp(ir::ModifierFlags flags) if ((flags & ir::ModifierFlags::DECLARE) != 0) { child->AddModifier(ir::ModifierFlags::DECLARE); } - parent->Statements().emplace_back(child); + parent->AddStatement(child); parent = child; } ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE); diff --git a/ets2panda/parser/ETSparserTypes.cpp b/ets2panda/parser/ETSparserTypes.cpp index c88b813839..1ee35142fd 100644 --- a/ets2panda/parser/ETSparserTypes.cpp +++ b/ets2panda/parser/ETSparserTypes.cpp @@ -390,7 +390,7 @@ std::pair ETSParser::GetTypeAnnotationFromParentheses(Type return std::make_pair(typeAnnotation, true); } -static bool IsSimpleReturnThis(lexer::Token const &tokenAfterThis) +bool IsSimpleReturnThis(lexer::Token const &tokenAfterThis) { return (tokenAfterThis.Type() == lexer::TokenType::PUNCTUATOR_ARROW) || (tokenAfterThis.Type() == lexer::TokenType::PUNCTUATOR_COMMA) || diff --git a/ets2panda/parser/parserImpl.h b/ets2panda/parser/parserImpl.h index d64de90591..c71ad06628 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -37,6 +37,10 @@ class Options; class SourcePositionHelper; } // namespace ark::es2panda::util +namespace ark::es2panda::public_lib { +struct Context; +} // namespace ark::es2panda::public_lib + namespace ark::es2panda::parser { using ENUMBITOPS_OPERATORS; @@ -101,6 +105,16 @@ public: lexer::SourcePosition GetPositionForDiagnostic() const; + void SetContext(public_lib::Context *ctx) + { + ctx_ = ctx; + } + + public_lib::Context *Context() + { + return ctx_; + } + protected: virtual void ParseProgram(ScriptKind kind); static ExpressionParseFlags CarryExpressionParserFlag(ExpressionParseFlags origin, ExpressionParseFlags carry); @@ -569,6 +583,7 @@ private: lexer::Lexer *lexer_ {}; const util::Options *options_; util::DiagnosticEngine &diagnosticEngine_; + public_lib::Context *ctx_ {nullptr}; }; } // namespace ark::es2panda::parser diff --git a/ets2panda/parser/program/program.cpp b/ets2panda/parser/program/program.cpp index 3d6ecb19e6..572ce976dc 100644 --- a/ets2panda/parser/program/program.cpp +++ b/ets2panda/parser/program/program.cpp @@ -25,18 +25,52 @@ #include "ir/base/classDefinition.h" #include "ir/statements/blockStatement.h" +#include + namespace ark::es2panda::parser { Program::Program(ArenaAllocator *allocator, varbinder::VarBinder *varbinder) : allocator_(allocator), - varbinder_(varbinder), externalSources_(allocator_->Adapter()), directExternalSources_(allocator_->Adapter()), extension_(varbinder->Extension()), etsnolintCollection_(allocator_->Adapter()), cfg_(allocator_->New(allocator_)), - functionScopes_(allocator_->Adapter()) + functionScopes_(allocator_->Adapter()), + varbinders_(allocator_->Adapter()), + checkers_(allocator_->Adapter()) +{ + PushVarBinder(varbinder); +} + +void Program::PushVarBinder(varbinder::VarBinder *varbinder) +{ + varbinders_.insert({compiler::GetPhaseManager()->GetCurrentMajor(), varbinder}); +} + +const varbinder::VarBinder *Program::VarBinder() const +{ + return varbinders_.at(compiler::GetPhaseManager()->GetCurrentMajor()); +} + +varbinder::VarBinder *Program::VarBinder() +{ + return varbinders_.at(compiler::GetPhaseManager()->GetCurrentMajor()); +} + +checker::Checker *Program::Checker() +{ + return checkers_.at(compiler::GetPhaseManager()->GetCurrentMajor()); +} + +void Program::PushChecker(checker::Checker *checker) +{ + checkers_.push_back(checker); +} + +const checker::Checker *Program::Checker() const { + return checkers_.at(compiler::GetPhaseManager()->GetCurrentMajor()); } std::string Program::Dump() const @@ -53,16 +87,16 @@ void Program::DumpSilent() const varbinder::ClassScope *Program::GlobalClassScope() { - ES2PANDA_ASSERT(globalClass_ != nullptr); - ES2PANDA_ASSERT(globalClass_->Scope() != nullptr); - return globalClass_->Scope()->AsClassScope(); + ES2PANDA_ASSERT(GlobalClass() != nullptr); + ES2PANDA_ASSERT(GlobalClass()->Scope() != nullptr); + return GlobalClass()->Scope()->AsClassScope(); } const varbinder::ClassScope *Program::GlobalClassScope() const { - ES2PANDA_ASSERT(globalClass_ != nullptr); - ES2PANDA_ASSERT(globalClass_->Scope() != nullptr); - return globalClass_->Scope()->AsClassScope(); + ES2PANDA_ASSERT(GlobalClass() != nullptr); + ES2PANDA_ASSERT(GlobalClass()->Scope() != nullptr); + return GlobalClass()->Scope()->AsClassScope(); } varbinder::GlobalScope *Program::GlobalScope() @@ -157,9 +191,40 @@ compiler::CFG *Program::GetCFG() return cfg_; } +ir::ClassDefinition *Program::GlobalClass() +{ + return ast_->AsETSModule()->GlobalClass(); +} + +const ir::ClassDefinition *Program::GlobalClass() const +{ + return ast_->AsETSModule()->GlobalClass(); +} + +void Program::SetGlobalClass(ir::ClassDefinition *globalClass) +{ + ast_->AsETSModule()->SetGlobalClass(globalClass); +} + const compiler::CFG *Program::GetCFG() const { return cfg_; } +bool Program::MergeExternalSource(const ExternalSource *externalSource) +{ + // prevent using cache for cycle import + for (const auto &[moduleName, _] : *externalSource) { + if (ModuleName() == moduleName) { + return false; + } + } + + for (const auto &[moduleName, extProgs] : *externalSource) { + externalSources_.emplace(moduleName, extProgs); + } + + return true; +} + } // namespace ark::es2panda::parser diff --git a/ets2panda/parser/program/program.h b/ets2panda/parser/program/program.h index d3e0ac67a6..c29543942c 100644 --- a/ets2panda/parser/program/program.h +++ b/ets2panda/parser/program/program.h @@ -27,6 +27,7 @@ #include "util/enumbitops.h" #include +#include namespace ark::es2panda::ir { class BlockStatement; @@ -41,6 +42,10 @@ namespace ark::es2panda::compiler { class CFG; } // namespace ark::es2panda::compiler +namespace ark::es2panda::checker { +class Checker; +} // namespace ark::es2panda::checker + namespace ark::es2panda::parser { enum class ScriptKind { SCRIPT, MODULE, STDLIB }; enum EntityType { CLASS_PROPERTY = 0, METHOD_DEFINITION = 1, CLASS_DEFINITION = 2, TS_INTERFACE_DECLARATION = 3 }; @@ -98,20 +103,16 @@ public: return allocator_; } - const varbinder::VarBinder *VarBinder() const - { - return varbinder_; - } + void PushVarBinder(varbinder::VarBinder *varbinder); - varbinder::VarBinder *VarBinder() - { - return varbinder_; - } + const varbinder::VarBinder *VarBinder() const; - void SetVarBinder(varbinder::VarBinder *varbinder) - { - varbinder_ = varbinder; - } + varbinder::VarBinder *VarBinder(); + + checker::Checker *Checker(); + const checker::Checker *Checker() const; + + void PushChecker(checker::Checker *checker); ScriptExtension Extension() const { @@ -190,20 +191,11 @@ public: MaybeTransformToDeclarationModule(); } - ir::ClassDefinition *GlobalClass() - { - return globalClass_; - } + ir::ClassDefinition *GlobalClass(); - const ir::ClassDefinition *GlobalClass() const - { - return globalClass_; - } + const ir::ClassDefinition *GlobalClass() const; - void SetGlobalClass(ir::ClassDefinition *globalClass) - { - globalClass_ = globalClass; - } + void SetGlobalClass(ir::ClassDefinition *globalClass); ExternalSource &ExternalSources() { @@ -289,6 +281,16 @@ public: void SetASTChecked(); bool IsASTChecked(); + void MarkASTAsLowered() + { + isASTlowered_ = true; + } + + bool IsASTLowered() const + { + return isASTlowered_; + } + bool IsStdLib() const { // NOTE (hurton): temporary solution, needs rework when std sources are renamed @@ -315,6 +317,8 @@ public: return declGenExportNodes_; } + bool MergeExternalSource(const ExternalSource *externalSource); + void AddDeclGenExportNode(const std::string &declGenExportStr, ir::AstNode *node) { declGenExportNodes_.emplace_back(declGenExportStr, node); @@ -367,10 +371,9 @@ public: private: void MaybeTransformToDeclarationModule(); +private: ArenaAllocator *allocator_ {}; - varbinder::VarBinder *varbinder_ {nullptr}; ir::BlockStatement *ast_ {}; - ir::ClassDefinition *globalClass_ {}; util::StringView sourceCode_ {}; util::Path sourceFile_ {}; util::StringView sourceFileFolder_ {}; @@ -382,12 +385,16 @@ private: ScriptExtension extension_ {}; ETSNolintsCollectionMap etsnolintCollection_; util::ModuleInfo moduleInfo_; + bool isASTlowered_ {}; lexer::SourcePosition packageStartPosition_ {}; compiler::CFG *cfg_; std::vector> declGenExportNodes_; ArenaVector functionScopes_; std::unordered_map> fileDependencies_; +private: + ArenaMap varbinders_; + ArenaVector checkers_; #ifndef NDEBUG uint32_t poisonValue_ {POISON_VALUE}; #endif diff --git a/ets2panda/public/cppToCTypes.yaml b/ets2panda/public/cppToCTypes.yaml index 37cbb764e9..10e1650666 100644 --- a/ets2panda/public/cppToCTypes.yaml +++ b/ets2panda/public/cppToCTypes.yaml @@ -1942,7 +1942,7 @@ change_types: max_ptr_depth: 1 new_args: cast: - expression: auto |es2panda_arg.type.ptr_depth||arg_name|E2p = reinterpret_cast(context)->checker; + expression: auto |es2panda_arg.type.ptr_depth||arg_name|E2p = reinterpret_cast(context)->GetChecker(); call_cast: start: >- (reinterpret_cast(context)->checker)-> @@ -1997,7 +1997,7 @@ change_types: new_args: cast: expression: >- - auto *|arg_name|E2p = reinterpret_cast(context)->checker->AsETSChecker(); + auto *|arg_name|E2p = reinterpret_cast(context)->GetChecker()->AsETSChecker(); call_cast: start: >- (reinterpret_cast(context)->checker->AsETSChecker())-> diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 68c404993f..3ba94058e7 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -243,10 +243,24 @@ __attribute__((unused)) char const *ArenaStrdup(ArenaAllocator *allocator, char return res; } -extern "C" es2panda_Config *CreateConfig(int args, char const *const *argv) +extern "C" void MemInitialize() { + if (mem::MemConfig::IsInitialized()) { + return; + } mem::MemConfig::Initialize(0, 0, COMPILER_SIZE, 0, 0, 0); PoolManager::Initialize(PoolType::MMAP); +} + +extern "C" void MemFinalize() +{ + PoolManager::Finalize(); + mem::MemConfig::Finalize(); +} + +extern "C" es2panda_Config *CreateConfig(int args, char const *const *argv) +{ + MemInitialize(); auto diagnosticEngine = new util::DiagnosticEngine(); auto *options = new util::Options(argv[0], *diagnosticEngine); if (!options->Parse(Span(argv, args))) { @@ -264,9 +278,6 @@ extern "C" es2panda_Config *CreateConfig(int args, char const *const *argv) extern "C" void DestroyConfig(es2panda_Config *config) { - PoolManager::Finalize(); - mem::MemConfig::Finalize(); - auto *cfg = reinterpret_cast(config); if (cfg == nullptr) { return; @@ -294,15 +305,81 @@ static void CompileJob(public_lib::Context *context, varbinder::FunctionScope *s funcEmitter.Generate(); } +static void GenerateStdLibCache(es2panda_Config *config, GlobalContext *globalContext, bool LspUsage); + +extern "C" __attribute__((unused)) es2panda_GlobalContext *CreateGlobalContext(es2panda_Config *config, + const char **externalFileList, + size_t fileNum, bool LspUsage) +{ + auto *globalContext = new GlobalContext; + for (size_t i = 0; i < fileNum; i++) { + auto fileName = externalFileList[i]; + auto globalAllocator = new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + globalContext->cachedExternalPrograms.emplace(fileName, nullptr); + globalContext->externalProgramAllocators.emplace(fileName, globalAllocator); + } + + GenerateStdLibCache(config, globalContext, LspUsage); + + return reinterpret_cast(globalContext); +} + +extern "C" __attribute__((unused)) void RemoveFileCache(es2panda_GlobalContext *globalContext, const char *fileName) +{ + auto globalCtx = reinterpret_cast(globalContext); + ES2PANDA_ASSERT(globalCtx->cachedExternalPrograms.count(fileName) == 1); + globalCtx->cachedExternalPrograms.erase(fileName); + delete globalCtx->externalProgramAllocators[fileName]; + globalCtx->externalProgramAllocators.erase(fileName); +} + +extern "C" __attribute__((unused)) void AddFileCache(es2panda_GlobalContext *globalContext, const char *fileName) +{ + auto globalCtx = reinterpret_cast(globalContext); + ES2PANDA_ASSERT(globalCtx->cachedExternalPrograms.count(fileName) == 0); + auto globalAllocator = new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + globalCtx->cachedExternalPrograms.emplace(fileName, nullptr); + globalCtx->externalProgramAllocators.emplace(fileName, globalAllocator); +} + +extern "C" __attribute__((unused)) void InvalidateFileCache(es2panda_GlobalContext *globalContext, const char *fileName) +{ + RemoveFileCache(globalContext, fileName); + AddFileCache(globalContext, fileName); +} + +static void InitializeContext(Context *res) +{ + res->phaseManager = new compiler::PhaseManager(res, ScriptExtension::ETS, res->allocator); + res->queue = new compiler::CompileQueue(res->config->options->GetThread()); + + auto *varbinder = res->allocator->New(res->allocator); + res->parserProgram = res->allocator->New(res->allocator, varbinder); + res->parser = new parser::ETSParser(res->parserProgram, *res->config->options, *res->diagnosticEngine, + parser::ParserStatus::NO_OPTS); + res->parser->SetContext(res); + + res->PushChecker(res->allocator->New(res->allocator, *res->diagnosticEngine, res->allocator)); + res->isolatedDeclgenChecker = new checker::IsolatedDeclgenChecker(*res->diagnosticEngine, *(res->parserProgram)); + res->PushAnalyzer(res->allocator->New(res->GetChecker())); + res->GetChecker()->SetAnalyzer(res->GetAnalyzer()); + + varbinder->SetProgram(res->parserProgram); + varbinder->SetContext(res); + res->codeGenCb = CompileJob; + res->emitter = new compiler::ETSEmitter(res); + res->program = nullptr; + res->state = ES2PANDA_STATE_NEW; +} + __attribute__((unused)) static es2panda_Context *CreateContext(es2panda_Config *config, std::string &&source, - const char *fileName) + const char *fileName, + es2panda_GlobalContext *globalContext, bool isExternal, + bool genStdLib) { auto *cfg = reinterpret_cast(config); auto *res = new Context; - res->input = std::move(source); - res->sourceFileName = fileName; - res->config = cfg; - + res->compiledByCapi = true; if (cfg == nullptr) { res->errorMessage = "Config is nullptr."; res->state = ES2PANDA_STATE_ERROR; @@ -312,61 +389,88 @@ __attribute__((unused)) static es2panda_Context *CreateContext(es2panda_Config * if (cfg->options->GetExtension() != ScriptExtension::ETS) { res->errorMessage = "Invalid extension. Plugin API supports only ETS."; res->state = ES2PANDA_STATE_ERROR; + res->diagnosticEngine = cfg->diagnosticEngine; return reinterpret_cast(res); } - res->sourceFile = new SourceFile(res->sourceFileName, res->input, cfg->options->IsModule()); - res->allocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); - res->queue = new compiler::CompileQueue(cfg->options->GetThread()); - - auto *varbinder = res->allocator->New(res->allocator); - res->parserProgram = new parser::Program(res->allocator, varbinder); + res->config = cfg; + res->isExternal = isExternal; + res->globalContext = reinterpret_cast(globalContext); res->diagnosticEngine = cfg->diagnosticEngine; - res->parser = - new parser::ETSParser(res->parserProgram, *cfg->options, *cfg->diagnosticEngine, parser::ParserStatus::NO_OPTS); - res->checker = new checker::ETSChecker(*res->diagnosticEngine); - res->isolatedDeclgenChecker = new checker::IsolatedDeclgenChecker(*res->diagnosticEngine, *(res->parserProgram)); - res->analyzer = new checker::ETSAnalyzer(res->checker); - res->checker->SetAnalyzer(res->analyzer); - varbinder->SetProgram(res->parserProgram); + res->input = std::move(source); + res->sourceFileName = fileName; + res->sourceFile = new SourceFile(res->sourceFileName, res->input, cfg->options->IsModule()); + if (isExternal) { + ir::EnableContextHistory(); + ES2PANDA_ASSERT(res->globalContext != nullptr); + if (genStdLib) { + ES2PANDA_ASSERT(res->globalContext->stdLibAllocator != nullptr); + res->allocator = res->globalContext->stdLibAllocator; + } else { + ES2PANDA_ASSERT(res->globalContext->externalProgramAllocators.count(fileName) != 0); + res->allocator = + reinterpret_cast(res->globalContext->externalProgramAllocators[fileName]); + } + } else { + ir::DisableContextHistory(); + res->allocator = new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + } - varbinder->SetContext(res); - res->codeGenCb = CompileJob; - res->phaseManager = new compiler::PhaseManager(ScriptExtension::ETS, res->allocator); - res->emitter = new compiler::ETSEmitter(res); - res->program = nullptr; - res->state = ES2PANDA_STATE_NEW; + InitializeContext(res); return reinterpret_cast(res); } -extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromFile(es2panda_Config *config, - char const *sourceFileName) +__attribute__((unused)) static std::stringstream ReadFile(char const *sourceFileName, Context *&res) { std::ifstream inputStream; inputStream.open(sourceFileName); if (inputStream.fail()) { - auto *res = new Context; + res = new Context; res->errorMessage = "Failed to open file: "; res->errorMessage.append(sourceFileName); - return reinterpret_cast(res); } std::stringstream ss; ss << inputStream.rdbuf(); if (inputStream.fail()) { - auto *res = new Context; + res = new Context; res->errorMessage = "Failed to read file: "; res->errorMessage.append(sourceFileName); + } + return ss; +} + +extern "C" __attribute__((unused)) es2panda_Context *CreateCacheContextFromFile(es2panda_Config *config, + char const *sourceFileName, + es2panda_GlobalContext *globalContext, + bool isExternal) +{ + Context *res = nullptr; + auto ss = ReadFile(sourceFileName, res); + if (res != nullptr) { + return reinterpret_cast(res); + } + return CreateContext(config, ss.str(), sourceFileName, globalContext, isExternal, false); +} + +extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromFile(es2panda_Config *config, + char const *sourceFileName) +{ + Context *res = nullptr; + auto ss = ReadFile(sourceFileName, res); + if (res != nullptr) { return reinterpret_cast(res); + ; } - return CreateContext(config, ss.str(), sourceFileName); + + return CreateContext(config, ss.str(), sourceFileName, nullptr, false, false); } extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromString(es2panda_Config *config, const char *source, char const *fileName) { // NOTE: gogabr. avoid copying source. - return CreateContext(config, std::string(source), fileName); + return CreateContext(config, std::string(source), fileName, nullptr, false, false); } __attribute__((unused)) static Context *Parse(Context *ctx) @@ -377,10 +481,27 @@ __attribute__((unused)) static Context *Parse(Context *ctx) return ctx; } - ctx->phaseManager->Restart(); - ctx->parser->ParseScript(*ctx->sourceFile, - ctx->config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB); + ctx->phaseManager->Reset(); + if (ctx->isExternal && ctx->allocator != ctx->globalContext->stdLibAllocator) { + auto allocator = ctx->allocator; + auto ident = allocator->New(compiler::Signatures::ETS_GLOBAL, allocator); + ArenaVector stmts(allocator->Adapter()); + auto etsModule = allocator->New(allocator, std::move(stmts), ident, ir::ModuleFlag::ETSSCRIPT, + ctx->parserProgram); + ctx->parserProgram->SetAst(etsModule); + util::ImportPathManager::ImportMetadata importData {util::ImportFlags::NONE}; + importData.resolvedSource = ctx->sourceFileName; + importData.lang = Language::Id::ETS; + importData.declPath = util::ImportPathManager::DUMMY_PATH; + importData.ohmUrl = util::ImportPathManager::DUMMY_PATH; + ctx->parser->AsETSParser()->GetImportPathManager()->AddToParseList(importData); + ctx->parser->AsETSParser()->AddExternalSource(ctx->parser->AsETSParser()->ParseSources(true)); + } else { + ctx->parser->ParseScript(*ctx->sourceFile, + ctx->config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB); + } ctx->state = ES2PANDA_STATE_PARSED; + ctx->phaseManager->SetCurrentPhaseIdToAfterParse(); return ctx; } @@ -421,10 +542,32 @@ __attribute__((unused)) static Context *Check(Context *ctx) } phase->Apply(ctx, ctx->parserProgram); } + ctx->phaseManager->SetCurrentPhaseIdToAfterCheck(); ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_CHECKED : ES2PANDA_STATE_ERROR; return ctx; } +__attribute__((unused)) static void SaveCache(Context *ctx) +{ + if (ctx->allocator == ctx->globalContext->stdLibAllocator) { + return; + } + ES2PANDA_ASSERT(ctx->globalContext != nullptr && + ctx->globalContext->cachedExternalPrograms.count(ctx->sourceFileName) != 0); + ctx->globalContext->cachedExternalPrograms[ctx->sourceFileName] = &(ctx->parserProgram->ExternalSources()); + + // cycle dependencies + for (auto &[_, extPrograms] : ctx->parserProgram->ExternalSources()) { + for (auto extProgram : extPrograms) { + auto absPath = std::string {extProgram->AbsoluteName()}; + auto &cacheMap = ctx->globalContext->cachedExternalPrograms; + if (cacheMap.count(absPath) == 1 && cacheMap[absPath] == nullptr) { + cacheMap[absPath] = &(ctx->parserProgram->ExternalSources()); + } + } + } +} + __attribute__((unused)) static Context *Lower(Context *ctx) { if (ctx->state < ES2PANDA_STATE_CHECKED) { @@ -440,6 +583,18 @@ __attribute__((unused)) static Context *Lower(Context *ctx) phase->Apply(ctx, ctx->parserProgram); } ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_LOWERED : ES2PANDA_STATE_ERROR; + + for (auto &[_, extPrograms] : ctx->parserProgram->ExternalSources()) { + for (auto &extProgram : extPrograms) { + if (!extProgram->IsASTLowered()) { + extProgram->MarkASTAsLowered(); + } + } + } + if (ctx->isExternal) { + SaveCache(ctx); + } + return ctx; } @@ -527,6 +682,7 @@ extern "C" __attribute__((unused)) es2panda_Context *ProceedToState(es2panda_Con ctx->state = ES2PANDA_STATE_ERROR; break; } + return reinterpret_cast(ctx); } @@ -535,17 +691,27 @@ extern "C" __attribute__((unused)) void DestroyContext(es2panda_Context *context auto *ctx = reinterpret_cast(context); delete ctx->program; delete ctx->emitter; - delete ctx->analyzer; - delete ctx->checker; delete ctx->parser; - delete ctx->parserProgram; delete ctx->queue; - delete ctx->allocator; delete ctx->sourceFile; delete ctx->phaseManager; + if (!ctx->isExternal) { + delete ctx->allocator; + } delete ctx; } +extern "C" __attribute__((unused)) void DestroyGlobalContext(es2panda_GlobalContext *globalContext) +{ + auto *globalCtx = reinterpret_cast(globalContext); + for (auto [_, alloctor] : globalCtx->externalProgramAllocators) { + delete alloctor; + } + + delete globalCtx->stdLibAllocator; + delete globalCtx; +} + extern "C" __attribute__((unused)) es2panda_ContextState ContextState(es2panda_Context *context) { auto *s = reinterpret_cast(context); @@ -837,7 +1003,7 @@ extern "C" void AstNodeRecheck(es2panda_Context *ctx, es2panda_AstNode *node) auto E2pNode = reinterpret_cast(node); auto context = reinterpret_cast(ctx); auto varbinder = context->parserProgram->VarBinder()->AsETSBinder(); - auto checker = context->checker->AsETSChecker(); + auto checker = context->GetChecker()->AsETSChecker(); auto phaseManager = context->phaseManager; if (E2pNode->IsScriptFunction() || E2pNode->FindChild([](ir::AstNode *n) { return n->IsScriptFunction(); }) != nullptr) { @@ -1000,7 +1166,7 @@ extern "C" __attribute__((unused)) int GenerateTsDeclarationsFromContext(es2pand const char *outputEts, bool exportAll) { auto *ctxImpl = reinterpret_cast(ctx); - auto *checker = reinterpret_cast(ctxImpl->checker); + auto *checker = reinterpret_cast(ctxImpl->GetChecker()); ark::es2panda::declgen_ets2ts::DeclgenOptions declgenOptions; declgenOptions.exportAll = exportAll; @@ -1032,7 +1198,8 @@ extern "C" void InsertETSImportDeclarationAndParse(es2panda_Context *context, es auto *importDeclE2p = reinterpret_cast(importDeclaration); importDeclE2p->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP); - parserProgram->Ast()->Statements().insert(parserProgram->Ast()->Statements().begin(), importDeclE2p); + auto &stmt = parserProgram->Ast()->StatementsForUpdates(); + stmt.insert(stmt.begin(), importDeclE2p); importDeclE2p->SetParent(parserProgram->Ast()); ctx->parser->AsETSParser()->AddExternalSource(ctx->parser->AsETSParser()->ParseSources()); @@ -1042,16 +1209,40 @@ extern "C" void InsertETSImportDeclarationAndParse(es2panda_Context *context, es } } +__attribute__((unused)) static void GenerateStdLibCache(es2panda_Config *config, GlobalContext *globalContext, + bool LspUsage) +{ + auto cfg = reinterpret_cast(config); + globalContext->stdLibAllocator = new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + auto ctx = CreateContext(config, std::move(""), cfg->options->SourceFileName().c_str(), + reinterpret_cast(globalContext), true, true); + ProceedToState(ctx, es2panda_ContextState::ES2PANDA_STATE_CHECKED); + if (!LspUsage) { + AstNodeRecheck(ctx, + reinterpret_cast(reinterpret_cast(ctx)->parserProgram->Ast())); + AstNodeRecheck(ctx, + reinterpret_cast(reinterpret_cast(ctx)->parserProgram->Ast())); + } + ProceedToState(ctx, es2panda_ContextState::ES2PANDA_STATE_LOWERED); + globalContext->stdLibAstCache = &(reinterpret_cast(ctx)->parserProgram->ExternalSources()); + DestroyContext(ctx); +} + es2panda_Impl g_impl = { ES2PANDA_LIB_VERSION, + MemInitialize, + MemFinalize, CreateConfig, DestroyConfig, ConfigGetOptions, CreateContextFromFile, + CreateCacheContextFromFile, CreateContextFromString, ProceedToState, DestroyContext, + CreateGlobalContext, + DestroyGlobalContext, ContextState, ContextErrorMessage, ContextProgram, @@ -1101,6 +1292,9 @@ es2panda_Impl g_impl = { GenerateTsDeclarationsFromContext, InsertETSImportDeclarationAndParse, GenerateStaticDeclarationsFromContext, + InvalidateFileCache, + RemoveFileCache, + AddFileCache, #include "generated/es2panda_lib/es2panda_lib_list.inc" diff --git a/ets2panda/public/es2panda_lib.h b/ets2panda/public/es2panda_lib.h index b331f56829..cf927443b4 100644 --- a/ets2panda/public/es2panda_lib.h +++ b/ets2panda/public/es2panda_lib.h @@ -43,6 +43,7 @@ extern "C" { typedef struct es2panda_Config es2panda_Config; typedef struct es2panda_Context es2panda_Context; +typedef struct es2panda_GlobalContext es2panda_GlobalContext; typedef struct es2panda_variantDoubleCharArrayBool { int index; @@ -175,15 +176,24 @@ typedef enum es2panda_ContextState es2panda_ContextState; struct CAPI_EXPORT es2panda_Impl { int version; + void (*MemInitialize)(); + void (*MemFinalize)(); + es2panda_Config *(*CreateConfig)(int argc, char const *const *argv); void (*DestroyConfig)(es2panda_Config *config); const es2panda_Options *(*ConfigGetOptions)(es2panda_Config *config); es2panda_Context *(*CreateContextFromFile)(es2panda_Config *config, char const *source_file_name); + es2panda_Context *(*CreateCacheContextFromFile)(es2panda_Config *config, char const *source_file_name, + es2panda_GlobalContext *globalContext, bool isExternal); es2panda_Context *(*CreateContextFromString)(es2panda_Config *config, const char *source, char const *file_name); es2panda_Context *(*ProceedToState)(es2panda_Context *context, es2panda_ContextState state); // context is consumed void (*DestroyContext)(es2panda_Context *context); + es2panda_GlobalContext *(*CreateGlobalContext)(es2panda_Config *config, const char **externalFileList, + size_t fileNum, bool LspUsage); + void (*DestroyGlobalContext)(es2panda_GlobalContext *globalContext); + es2panda_ContextState (*ContextState)(es2panda_Context *context); char const *(*ContextErrorMessage)(es2panda_Context *context); @@ -257,6 +267,9 @@ struct CAPI_EXPORT es2panda_Impl { es2panda_AstNode *importDeclaration); int (*GenerateStaticDeclarationsFromContext)(es2panda_Context *context, const char *outputPath); + void (*InvalidateFileCache)(es2panda_GlobalContext *globalContext, const char *fileName); + void (*RemoveFileCache)(es2panda_GlobalContext *globalContext, const char *fileName); + void (*AddFileCache)(es2panda_GlobalContext *globalContext, const char *fileName); // CC-OFFNXT(G.INC.08) project code style #include "generated/es2panda_lib/es2panda_lib_decl.inc" }; diff --git a/ets2panda/public/public.cpp b/ets2panda/public/public.cpp new file mode 100644 index 0000000000..3b3754328b --- /dev/null +++ b/ets2panda/public/public.cpp @@ -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. + */ + +#include "public/public.h" +#include "compiler/lowering/phase.h" + +namespace ark::es2panda::public_lib { + +checker::Checker *Context::GetChecker() const +{ + return checkers_[compiler::GetPhaseManager()->GetCurrentMajor()]; +} + +checker::SemanticAnalyzer *Context::GetAnalyzer() const +{ + return analyzers_[compiler::GetPhaseManager()->GetCurrentMajor()]; +} + +} // namespace ark::es2panda::public_lib diff --git a/ets2panda/public/public.h b/ets2panda/public/public.h index fdb18d9ca6..46ddf91b4c 100644 --- a/ets2panda/public/public.h +++ b/ets2panda/public/public.h @@ -34,6 +34,8 @@ class Options; namespace ark::es2panda::compiler { class PhaseManager; +void SetPhaseManager(PhaseManager *phaseManager); +PhaseManager *GetPhaseManager(); } // namespace ark::es2panda::compiler namespace ark::es2panda::public_lib { @@ -52,14 +54,14 @@ struct ConfigImpl { }; using ExternalSources = std::unordered_map>; - +using ExternalSource = ArenaUnorderedMap>; using ComputedAbstracts = ArenaUnorderedMap, ArenaUnorderedSet>>; class TransitionMemory { public: - explicit TransitionMemory(ArenaAllocator *allocator) + explicit TransitionMemory(ThreadSafeArenaAllocator *allocator) : permanentAllocator_(allocator), compiledPrograms_(allocator->Adapter()) { compiledPrograms_ = {}; @@ -70,7 +72,7 @@ public: ~TransitionMemory() = default; - ArenaAllocator *PermanentAllocator() const + ThreadSafeArenaAllocator *PermanentAllocator() const { return permanentAllocator_.get(); } @@ -136,13 +138,20 @@ public: } private: - std::unique_ptr permanentAllocator_; + std::unique_ptr permanentAllocator_; ArenaVector compiledPrograms_; varbinder::VarBinder *varbinder_ {nullptr}; checker::GlobalTypesHolder *globalTypes_ {nullptr}; ComputedAbstracts *cachedComputedAbstracts_ {nullptr}; }; +struct GlobalContext { + std::unordered_map externalProgramAllocators; + std::unordered_map cachedExternalPrograms; + ThreadSafeArenaAllocator *stdLibAllocator = nullptr; + ExternalSource *stdLibAstCache = nullptr; +}; + struct Context { // NOLINTBEGIN(misc-non-private-member-variables-in-classes) using CodeGenCb = @@ -160,11 +169,41 @@ struct Context { return util::NodeAllocator::ForceSetParent(Allocator(), std::forward(args)...); } + checker::Checker *GetChecker() const; + + void PushChecker(checker::Checker *checker) + { + parserProgram->PushChecker(checker); + checkers_.push_back(checker); + } + + void DestoryCheckers() + { + for (auto item : checkers_) { + delete item; + } + } + + checker::SemanticAnalyzer *GetAnalyzer() const; + + void PushAnalyzer(checker::SemanticAnalyzer *analyzer) + { + return analyzers_.push_back(analyzer); + } + + void DestoryAnalyzers() + { + for (auto item : analyzers_) { + delete item; + } + } + ConfigImpl *config = nullptr; + GlobalContext *globalContext = nullptr; std::string sourceFileName; std::string input; SourceFile const *sourceFile = nullptr; - ArenaAllocator *allocator = nullptr; + ThreadSafeArenaAllocator *allocator = nullptr; compiler::CompileQueue *queue = nullptr; std::vector const *plugins = nullptr; std::vector contextLiterals; @@ -173,10 +212,7 @@ struct Context { parser::Program *parserProgram = nullptr; parser::ParserImpl *parser = nullptr; - checker::Checker *checker = nullptr; - checker::IsolatedDeclgenChecker *isolatedDeclgenChecker = nullptr; - checker::SemanticAnalyzer *analyzer = nullptr; compiler::Emitter *emitter = nullptr; pandasm::Program *program = nullptr; util::DiagnosticEngine *diagnosticEngine = nullptr; @@ -188,8 +224,16 @@ struct Context { CompilingState compilingState {CompilingState::NONE_COMPILING}; ExternalSources externalSources; TransitionMemory *transitionMemory {nullptr}; + bool isExternal = false; + bool compiledByCapi = false; + checker::IsolatedDeclgenChecker *isolatedDeclgenChecker {nullptr}; // NOLINTEND(misc-non-private-member-variables-in-classes) + +private: + std::vector checkers_; + std::vector analyzers_; }; + } // namespace ark::es2panda::public_lib #endif diff --git a/ets2panda/test/ast/compiler/ets/annotation_tests/annotation_for_array_type01.ets b/ets2panda/test/ast/compiler/ets/annotation_tests/annotation_for_array_type01.ets index 170649f36e..c2bf21da69 100644 --- a/ets2panda/test/ast/compiler/ets/annotation_tests/annotation_for_array_type01.ets +++ b/ets2panda/test/ast/compiler/ets/annotation_tests/annotation_for_array_type01.ets @@ -22,5 +22,5 @@ let array: @Anno @Anno Int[][] let deepArray: @Anno @Anno Number[][][][][] -/* @@? 21:19 Error TypeError: Duplicate annotations are not allowed. The annotation 'Anno' has already been applied to this element. */ -/* @@? 22:23 Error TypeError: Duplicate annotations are not allowed. The annotation 'Anno' has already been applied to this element. */ \ No newline at end of file +/* @@? 21:29 Error TypeError: Duplicate annotations are not allowed. The annotation 'Anno' has already been applied to this element. */ +/* @@? 22:42 Error TypeError: Duplicate annotations are not allowed. The annotation 'Anno' has already been applied to this element. */ \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/re_export/re_export_4.ets b/ets2panda/test/ast/parser/ets/re_export/re_export_4.ets index 32c944833a..399324e4b7 100644 --- a/ets2panda/test/ast/parser/ets/re_export/re_export_4.ets +++ b/ets2panda/test/ast/parser/ets/re_export/re_export_4.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -export {foo} from "./export" -export /* @@ label */{foo} from "./export_2" +export /* @@ label */{foo} from "./export" +export {foo} from "./export_2" /* @@@ label Error TypeError: Ambiguous export 'foo' */ diff --git a/ets2panda/test/parser/ets/getterOverride-expected.txt b/ets2panda/test/parser/ets/getterOverride-expected.txt index e223479634..64aef4f75f 100644 --- a/ets2panda/test/parser/ets/getterOverride-expected.txt +++ b/ets2panda/test/parser/ets/getterOverride-expected.txt @@ -132,13 +132,13 @@ "decorators": [], "loc": { "start": { - "line": 19, - "column": 1, + "line": 18, + "column": 15, "program": "getterOverride.ets" }, "end": { "line": 18, - "column": 15, + "column": 26, "program": "getterOverride.ets" } } diff --git a/ets2panda/test/parser/ets/re_export/import_10-expected.txt b/ets2panda/test/parser/ets/re_export/import_10-expected.txt index 186322d784..2152202423 100644 --- a/ets2panda/test/parser/ets/re_export/import_10-expected.txt +++ b/ets2panda/test/parser/ets/re_export/import_10-expected.txt @@ -374,4 +374,4 @@ } } } -TypeError: Ambiguous export 'foo' [re_export_4.ets:17:8] +TypeError: Ambiguous export 'foo' [re_export_4.ets:16:8] diff --git a/ets2panda/test/parser/ets/re_export/re_export_4-expected.txt b/ets2panda/test/parser/ets/re_export/re_export_4-expected.txt index 74a1b2496b..23266085b0 100644 --- a/ets2panda/test/parser/ets/re_export/re_export_4-expected.txt +++ b/ets2panda/test/parser/ets/re_export/re_export_4-expected.txt @@ -471,4 +471,4 @@ } } } -TypeError: Ambiguous export 'foo' [re_export_4.ets:17:8] +TypeError: Ambiguous export 'foo' [re_export_4.ets:16:8] diff --git a/ets2panda/test/runtime/ets/class_implements_interface_export.ets b/ets2panda/test/runtime/ets/class_implements_interface_export.ets new file mode 100644 index 0000000000..585718a5fa --- /dev/null +++ b/ets2panda/test/runtime/ets/class_implements_interface_export.ets @@ -0,0 +1,25 @@ +/* + * 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. + */ + +export class A{} + +interface I { + a: boolean +} + +class B implements I { + a = false +} + diff --git a/ets2panda/test/runtime/ets/class_implements_interface_import.ets b/ets2panda/test/runtime/ets/class_implements_interface_import.ets new file mode 100644 index 0000000000..e779066f3c --- /dev/null +++ b/ets2panda/test/runtime/ets/class_implements_interface_import.ets @@ -0,0 +1,16 @@ +/* + * 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. + */ + +import { A } from "./class_implements_interface_export" \ No newline at end of file diff --git a/ets2panda/test/test-lists/astchecker/astchecker-ets-ignored.txt b/ets2panda/test/test-lists/astchecker/astchecker-ets-ignored.txt index 3888be099f..2e165ab582 100644 --- a/ets2panda/test/test-lists/astchecker/astchecker-ets-ignored.txt +++ b/ets2panda/test/test-lists/astchecker/astchecker-ets-ignored.txt @@ -102,3 +102,7 @@ ast/compiler/ets/lambda_infer_type/lambda_param_type_cannot_be_determined.ets # Issue: #24605 incorrect column ast/parser/ets/named_types_2.ets + +# +ast/parser/ets/partialGenericInterface.ets +ast/parser/ets/partialGenericInterface_n.ets \ No newline at end of file diff --git a/ets2panda/test/test-lists/srcdumper/srcdumper-ets-ignored.txt b/ets2panda/test/test-lists/srcdumper/srcdumper-ets-ignored.txt index cff206ab65..7e8727c782 100644 --- a/ets2panda/test/test-lists/srcdumper/srcdumper-ets-ignored.txt +++ b/ets2panda/test/test-lists/srcdumper/srcdumper-ets-ignored.txt @@ -189,6 +189,8 @@ runtime/ets/exportDefault_1.ets runtime/ets/exportDefault_2.ets runtime/ets/declareExport.ets runtime/ets/implicit_stringliteral_init.ets +runtime/ets/mypackage/implicit_package_import_1.ets +runtime/ets/class_implements_interface_import.ets # #21051 should be log warnings, but there aren't ast/compiler/ets/not_initialized_variable/import_types.ets diff --git a/ets2panda/test/unit/lowerings/node_history.cpp b/ets2panda/test/unit/lowerings/node_history.cpp index c3b982aa63..8a8e6911a8 100644 --- a/ets2panda/test/unit/lowerings/node_history.cpp +++ b/ets2panda/test/unit/lowerings/node_history.cpp @@ -34,6 +34,7 @@ public: allocator_ = std::make_unique(SpaceType::SPACE_TYPE_COMPILER); phaseManager_ = std::make_unique(ScriptExtension::ETS, Allocator()); compiler::SetPhaseManager(phaseManager_.get()); + ir::EnableContextHistory(); } NO_COPY_SEMANTIC(NodeHistoryTest); @@ -54,12 +55,13 @@ private: std::unique_ptr phaseManager_; }; -constexpr int32_t PHASE_ID_0 = 0; -constexpr int32_t PHASE_ID_1 = 1; -constexpr int32_t PHASE_ID_2 = 2; -constexpr int32_t PHASE_ID_3 = 3; -constexpr int32_t PHASE_ID_4 = 4; -constexpr int32_t PHASE_ID_5 = 5; +constexpr compiler::PhaseId PARSER_PHASE_ID = {0, compiler::PARSER_PHASE_ID}; +constexpr compiler::PhaseId PHASE_ID_0 = {0, 0}; +constexpr compiler::PhaseId PHASE_ID_1 = {0, 1}; +constexpr compiler::PhaseId PHASE_ID_2 = {0, 2}; +constexpr compiler::PhaseId PHASE_ID_3 = {0, 3}; +constexpr compiler::PhaseId PHASE_ID_4 = {0, 4}; +constexpr compiler::PhaseId PHASE_ID_5 = {0, 5}; constexpr int32_t INDEX_0 = 0; constexpr int32_t INDEX_1 = 1; @@ -149,26 +151,26 @@ TEST_F(NodeHistoryTest, DoubleLinkedList) TEST_F(NodeHistoryTest, HistoryAt) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier = Allocator()->New(Allocator())->AsIdentifier(); auto history = Allocator()->New(identifier, PhaseManager()->CurrentPhaseId(), Allocator()); - ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->At(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->At(PHASE_ID_0), identifier); ASSERT_EQ(history->At(PHASE_ID_1), nullptr); } TEST_F(NodeHistoryTest, HistoryGet) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier = Allocator()->New(Allocator())->AsIdentifier(); auto history = Allocator()->New(identifier, PhaseManager()->CurrentPhaseId(), Allocator()); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->Get(PHASE_ID_0), identifier); ASSERT_EQ(history->Get(PHASE_ID_1), identifier); ASSERT_EQ(history->Get(PHASE_ID_2), identifier); @@ -178,25 +180,25 @@ TEST_F(NodeHistoryTest, HistoryGet) // CC-OFFNXT(huge_method, G.FUN.01-CPP, G.FUD.05) solid logic TEST_F(NodeHistoryTest, HistorySet) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier0 = Allocator()->New(Allocator())->AsIdentifier(); auto history = Allocator()->New(identifier0, PhaseManager()->CurrentPhaseId(), Allocator()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); auto identifier1 = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier1, PhaseManager()->CurrentPhaseId()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); auto identifier2 = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier2, PhaseManager()->CurrentPhaseId()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_3); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_3.minor); history->Set(nullptr, PhaseManager()->CurrentPhaseId()); // Search forward - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->Get(PHASE_ID_0), identifier0); ASSERT_EQ(history->Get(PHASE_ID_1), identifier1); ASSERT_EQ(history->Get(PHASE_ID_2), identifier2); @@ -211,7 +213,7 @@ TEST_F(NodeHistoryTest, HistorySet) ASSERT_EQ(history->Get(PHASE_ID_2), identifier2); ASSERT_EQ(history->Get(PHASE_ID_1), identifier1); ASSERT_EQ(history->Get(PHASE_ID_0), identifier0); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); // Search random ASSERT_EQ(history->Get(PHASE_ID_1), identifier1); @@ -219,11 +221,11 @@ TEST_F(NodeHistoryTest, HistorySet) ASSERT_EQ(history->Get(PHASE_ID_2), identifier2); ASSERT_EQ(history->Get(PHASE_ID_4), nullptr); ASSERT_EQ(history->Get(PHASE_ID_0), identifier0); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->Get(PHASE_ID_3), nullptr); // Search precise - ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->At(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->At(PHASE_ID_0), identifier0); ASSERT_EQ(history->At(PHASE_ID_1), identifier1); ASSERT_EQ(history->At(PHASE_ID_2), identifier2); @@ -234,47 +236,54 @@ TEST_F(NodeHistoryTest, HistorySet) TEST_F(NodeHistoryTest, HistoryReplace) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier0Orig = Allocator()->New(Allocator())->AsIdentifier(); auto history = Allocator()->New(identifier0Orig, PhaseManager()->CurrentPhaseId(), Allocator()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); auto identifier1Orig = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier1Orig, PhaseManager()->CurrentPhaseId()); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->Get(PHASE_ID_0), identifier0Orig); ASSERT_EQ(history->Get(PHASE_ID_1), identifier1Orig); ASSERT_EQ(history->Get(PHASE_ID_2), identifier1Orig); ASSERT_EQ(history->Get(PHASE_ID_3), identifier1Orig); - ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->At(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->At(PHASE_ID_0), identifier0Orig); ASSERT_EQ(history->At(PHASE_ID_1), identifier1Orig); ASSERT_EQ(history->At(PHASE_ID_2), nullptr); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier0New = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier0New, PhaseManager()->CurrentPhaseId()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); auto identifier1New = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier1New, PhaseManager()->CurrentPhaseId()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); history->Set(nullptr, PhaseManager()->CurrentPhaseId()); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); - ASSERT_EQ(history->Get(PHASE_ID_0), identifier0New); - ASSERT_EQ(history->Get(PHASE_ID_1), identifier1New); - ASSERT_EQ(history->Get(PHASE_ID_2), nullptr); - ASSERT_EQ(history->Get(PHASE_ID_3), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PHASE_ID_0), identifier0Orig); + ASSERT_EQ(history->Get(PHASE_ID_1), identifier1Orig); + ASSERT_EQ(history->Get(PHASE_ID_2), identifier1Orig); + ASSERT_EQ(history->Get(PHASE_ID_3), identifier1Orig); + ASSERT_EQ(history->Get({1, PHASE_ID_0.minor}), identifier0New); + ASSERT_EQ(history->Get({1, PHASE_ID_1.minor}), identifier1New); + ASSERT_EQ(history->Get({1, PHASE_ID_2.minor}), nullptr); + ASSERT_EQ(history->Get({1, PHASE_ID_3.minor}), nullptr); - ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr); - ASSERT_EQ(history->At(PHASE_ID_0), identifier0New); - ASSERT_EQ(history->At(PHASE_ID_1), identifier1New); + ASSERT_EQ(history->At(PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->At(PHASE_ID_0), identifier0Orig); + ASSERT_EQ(history->At(PHASE_ID_1), identifier1Orig); + ASSERT_EQ(history->At(PHASE_ID_2), nullptr); + ASSERT_EQ(history->At({1, PHASE_ID_0.minor}), identifier0New); + ASSERT_EQ(history->At({1, PHASE_ID_1.minor}), identifier1New); ASSERT_EQ(history->At(PHASE_ID_2), nullptr); } @@ -288,9 +297,9 @@ ir::ClassDefinition *NewClassDefinition(ArenaAllocator *allocator) } /// NOTE(mivanov): To be enabled after #24153/#24424 implemented -TEST_F(NodeHistoryTest, DISABLED_UpdateField) +TEST_F(NodeHistoryTest, UpdateField) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); auto definition = NewClassDefinition(Allocator()); ASSERT_FALSE(definition->IsAbstract()); @@ -299,35 +308,35 @@ TEST_F(NodeHistoryTest, DISABLED_UpdateField) definition->AddModifier(ir::ModifierFlags::FINAL); ASSERT_TRUE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); definition->AddModifier(ir::ModifierFlags::ABSTRACT); ASSERT_TRUE(definition->IsAbstract()); definition->ClearModifier(ir::ModifierFlags::FINAL); ASSERT_FALSE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); definition->ClearModifier(ir::ModifierFlags::ABSTRACT); ASSERT_FALSE(definition->IsAbstract()); definition->AddModifier(ir::ModifierFlags::FINAL); ASSERT_TRUE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); definition->ClearModifier(ir::ModifierFlags::FINAL); ASSERT_FALSE(definition->IsFinal()); - PhaseManager()->Restart(); + PhaseManager()->Reset(); ASSERT_FALSE(definition->IsAbstract()); ASSERT_TRUE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); ASSERT_TRUE(definition->IsAbstract()); ASSERT_FALSE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); ASSERT_FALSE(definition->IsAbstract()); ASSERT_TRUE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); ASSERT_FALSE(definition->IsAbstract()); ASSERT_FALSE(definition->IsFinal()); } @@ -335,36 +344,36 @@ TEST_F(NodeHistoryTest, DISABLED_UpdateField) /// NOTE(mivanov): To be enabled after #24153/#24424 implemented TEST_F(NodeHistoryTest, DISABLED_UpdateChild) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); auto declaration = Allocator()->New(NewClassDefinition(Allocator()), Allocator())->AsClassDeclaration(); ASSERT_EQ(declaration->Definition()->Ident(), nullptr); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier0 = Allocator()->New(Allocator())->AsIdentifier(); declaration->Definition()->SetIdent(identifier0); ASSERT_EQ(declaration->Definition()->Ident(), identifier0); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); auto identifier1 = Allocator()->New(Allocator())->AsIdentifier(); declaration->Definition()->SetIdent(identifier1); ASSERT_EQ(declaration->Definition()->Ident(), identifier1); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); declaration->Definition()->SetIdent(nullptr); ASSERT_EQ(declaration->Definition()->Ident(), nullptr); - PhaseManager()->Restart(); + PhaseManager()->Reset(); ASSERT_EQ(declaration->Definition()->Ident(), nullptr); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); ASSERT_EQ(declaration->Definition()->Ident(), identifier0); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); ASSERT_EQ(declaration->Definition()->Ident(), identifier1); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); ASSERT_EQ(declaration->Definition()->Ident(), nullptr); } } // namespace ark::es2panda diff --git a/ets2panda/test/unit/lowerings/scopes_initialization.cpp b/ets2panda/test/unit/lowerings/scopes_initialization.cpp index 472da09d93..1c82aeed87 100644 --- a/ets2panda/test/unit/lowerings/scopes_initialization.cpp +++ b/ets2panda/test/unit/lowerings/scopes_initialization.cpp @@ -30,11 +30,12 @@ public: ~ScopesInitPhaseTest() override = default; ScopesInitPhaseTest() - : allocator_(std::make_unique(SpaceType::SPACE_TYPE_COMPILER)), nodeGen_(allocator_.get()) + : allocator_(std::make_unique(SpaceType::SPACE_TYPE_COMPILER, nullptr, true)), + nodeGen_(allocator_.get()) { } - ArenaAllocator *Allocator() + ark::ThreadSafeArenaAllocator *Allocator() { return allocator_.get(); } @@ -48,7 +49,7 @@ public: NO_MOVE_SEMANTIC(ScopesInitPhaseTest); private: - std::unique_ptr allocator_; + std::unique_ptr allocator_; gtests::NodeGenerator nodeGen_; }; diff --git a/ets2panda/test/unit/lsp/get_type_of_symbol_at_location_test.cpp b/ets2panda/test/unit/lsp/get_type_of_symbol_at_location_test.cpp index 536122486f..cfbac8e419 100644 --- a/ets2panda/test/unit/lsp/get_type_of_symbol_at_location_test.cpp +++ b/ets2panda/test/unit/lsp/get_type_of_symbol_at_location_test.cpp @@ -37,7 +37,7 @@ TEST_F(LSPAPITests, GetTypeOfSymbolAtLocation1) "float;\nlet g: double;\nlet h: char;\nlet i: boolean;"); ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto checker = reinterpret_cast(ctx)->checker->AsETSChecker(); + auto checker = reinterpret_cast(ctx)->GetChecker()->AsETSChecker(); auto astNode = GetAstFromContext(ctx); auto targetNode = astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "a"; }); @@ -97,7 +97,7 @@ TEST_F(LSPAPITests, GetTypeOfSymbolAtLocation2) "undefined;\nlet tuple: [number, number] = [1, 2];\nlet union: int | null;"); ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); - auto checker = reinterpret_cast(ctx)->checker->AsETSChecker(); + auto checker = reinterpret_cast(ctx)->GetChecker()->AsETSChecker(); auto astNode = GetAstFromContext(ctx); auto targetNode = astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "j"; }); diff --git a/ets2panda/test/unit/lsp/isolated_declaration.cpp b/ets2panda/test/unit/lsp/isolated_declaration.cpp index d230e67a2e..5a0f1c776b 100644 --- a/ets2panda/test/unit/lsp/isolated_declaration.cpp +++ b/ets2panda/test/unit/lsp/isolated_declaration.cpp @@ -52,7 +52,7 @@ export function foo(n: number) { Initializer initializer = Initializer(); auto context = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED); auto ctx = reinterpret_cast(context); - auto checker = reinterpret_cast(ctx->checker); + auto checker = reinterpret_cast(ctx->GetChecker()); auto ast = ctx->parserProgram->Ast(); auto id = ast->FindChild([](ark::es2panda::ir::AstNode *childNode) { return childNode->IsIdentifier() && childNode->AsIdentifier()->Name() == "foo"; @@ -91,7 +91,7 @@ export function foo(n: number) { Initializer initializer = Initializer(); auto context = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED); auto ctx = reinterpret_cast(context); - auto checker = reinterpret_cast(ctx->checker); + auto checker = reinterpret_cast(ctx->GetChecker()); auto ast = ctx->parserProgram->Ast(); auto id = ast->FindChild([](ark::es2panda::ir::AstNode *childNode) { return childNode->IsIdentifier() && childNode->AsIdentifier()->Name() == "foo"; @@ -131,7 +131,7 @@ export const foo = () => { Initializer initializer = Initializer(); auto context = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED); auto ctx = reinterpret_cast(context); - auto checker = reinterpret_cast(ctx->checker); + auto checker = reinterpret_cast(ctx->GetChecker()); auto ast = ctx->parserProgram->Ast(); auto id = ast->FindChild([](ark::es2panda::ir::AstNode *childNode) { return childNode->IsIdentifier() && childNode->AsIdentifier()->Name() == "foo"; @@ -172,7 +172,7 @@ export class A { Initializer initializer = Initializer(); auto context = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED); auto ctx = reinterpret_cast(context); - auto checker = reinterpret_cast(ctx->checker); + auto checker = reinterpret_cast(ctx->GetChecker()); auto ast = ctx->parserProgram->Ast(); auto id = ast->FindChild([](ark::es2panda::ir::AstNode *childNode) { return childNode->IsIdentifier() && childNode->AsIdentifier()->Name() == "foo"; @@ -213,7 +213,7 @@ export class A { Initializer initializer = Initializer(); auto context = initializer.CreateContext(filePaths[1].c_str(), ES2PANDA_STATE_CHECKED); auto ctx = reinterpret_cast(context); - auto checker = reinterpret_cast(ctx->checker); + auto checker = reinterpret_cast(ctx->GetChecker()); auto ast = ctx->parserProgram->Ast(); auto id = ast->FindChild([](ark::es2panda::ir::AstNode *childNode) { return childNode->IsIdentifier() && childNode->AsIdentifier()->Name() == "foo"; diff --git a/ets2panda/test/unit/lsp/lsp_rename_test.cpp b/ets2panda/test/unit/lsp/lsp_rename_test.cpp index ea1af27659..39ad9d3887 100644 --- a/ets2panda/test/unit/lsp/lsp_rename_test.cpp +++ b/ets2panda/test/unit/lsp/lsp_rename_test.cpp @@ -441,7 +441,7 @@ TEST_F(LspRenameInfoTests, RenameInfoGetRenameInfoForNode1) ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); auto ast = GetAstFromContext(ctx); - auto checker = reinterpret_cast(ctx)->checker->AsETSChecker(); + auto checker = reinterpret_cast(ctx)->GetChecker()->AsETSChecker(); auto program = reinterpret_cast(ctx)->parserProgram; auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) { diff --git a/ets2panda/test/unit/plugin/plugin_proceed_to_state.cpp b/ets2panda/test/unit/plugin/plugin_proceed_to_state.cpp index aa95c12304..b700c046a9 100644 --- a/ets2panda/test/unit/plugin/plugin_proceed_to_state.cpp +++ b/ets2panda/test/unit/plugin/plugin_proceed_to_state.cpp @@ -39,6 +39,7 @@ int main(int argc, char **argv) std::cout << "LOAD SUCCESS" << std::endl; const char **args = const_cast(&(argv[1])); + impl->MemInitialize(); auto config = impl->CreateConfig(argc - 1, args); auto context = impl->CreateContextFromFile(config, argv[argc - 1]); if (context == nullptr) { @@ -67,6 +68,7 @@ int main(int argc, char **argv) CheckForErrors("BIN", context); impl->DestroyConfig(config); + impl->MemFinalize(); return 0; } diff --git a/ets2panda/test/unit/plugin/plugin_proceed_to_state_create_import.cpp b/ets2panda/test/unit/plugin/plugin_proceed_to_state_create_import.cpp index 2efc5c36d5..d795325136 100644 --- a/ets2panda/test/unit/plugin/plugin_proceed_to_state_create_import.cpp +++ b/ets2panda/test/unit/plugin/plugin_proceed_to_state_create_import.cpp @@ -133,7 +133,7 @@ bool Find(es2panda_AstNode *ast) { if (g_impl->IsETSImportDeclaration(ast)) { size_t len = 0; - auto specifiers = g_impl->ImportDeclarationSpecifiers(g_ctx, ast, &len); + auto specifiers = g_impl->ImportDeclarationSpecifiersConst(g_ctx, ast, &len); auto source = g_impl->ImportDeclarationSource(g_ctx, ast); auto importDeclaration = g_impl->UpdateETSImportDeclaration(g_ctx, ast, source, specifiers, len, IMPORT_KINDS_ALL); diff --git a/ets2panda/test/unit/plugin/plugin_proceed_to_state_find_import_declaration.cpp b/ets2panda/test/unit/plugin/plugin_proceed_to_state_find_import_declaration.cpp index 3cbc8d25db..7d7f575528 100644 --- a/ets2panda/test/unit/plugin/plugin_proceed_to_state_find_import_declaration.cpp +++ b/ets2panda/test/unit/plugin/plugin_proceed_to_state_find_import_declaration.cpp @@ -35,7 +35,7 @@ void CheckForImportDeclaration(es2panda_AstNode *node, void *arg) return; } size_t n = 0; - auto specifiers = impl->ImportDeclarationSpecifiers(context, node, &n); + auto specifiers = impl->ImportDeclarationSpecifiersConst(context, node, &n); for (size_t i = 0; i < n; i++) { if (!impl->IsImportSpecifier(specifiers[i])) { std::cout << impl->IsImportSpecifier(specifiers[i]) << std::endl; diff --git a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_i.cpp b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_i.cpp index 35f7374b7b..7e88eff580 100644 --- a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_i.cpp +++ b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_i.cpp @@ -343,7 +343,7 @@ TEST_F(PluginConversionRuleUnitTest, PairReturnValue) es2panda_Type *classInstance, [[maybe_unused]] es2panda_Type *sourceType/*return_args:*/, es2panda_Type **returnTypeSecond) { - auto *checkerE2p = reinterpret_cast(context)->checker->AsETSChecker(); + auto *checkerE2p = reinterpret_cast(context)->GetChecker()->AsETSChecker(); auto *sourceTypeE2p = reinterpret_cast(sourceType); auto *ctx = reinterpret_cast(context); [[maybe_unused]] auto *ctxAllocator = ctx->allocator; diff --git a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_ii.cpp b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_ii.cpp index d6f9e1b282..eee97381aa 100644 --- a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_ii.cpp +++ b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_ii.cpp @@ -60,7 +60,7 @@ TEST_F(PluginConversionRuleUnitTest, CheckerTypeRelationConstructor) std::string targetCAPI {R"( extern "C" es2panda_TypeRelation *CreateTypeRelation([[maybe_unused]] es2panda_Context *context) { - auto *checkerE2p = reinterpret_cast(context)->checker; + auto *checkerE2p = reinterpret_cast(context)->GetChecker(); auto *ctx = reinterpret_cast(context); auto *ctxAllocator = ctx->allocator; return reinterpret_cast(ctxAllocator->New(checkerE2p)); diff --git a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_iv.cpp b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_iv.cpp index 8eb1282e8c..1b4c7be1d7 100644 --- a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_iv.cpp +++ b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_iv.cpp @@ -62,7 +62,7 @@ TEST_F(PluginConversionRuleUnitTest, CheckerContextPtrReturnValue) extern "C" es2panda_CheckerContext *CreateCheckerContext([[maybe_unused]] es2panda_Context *context, [[maybe_unused]] Es2pandaCheckerStatus newStatus) { - auto *checkerE2p = reinterpret_cast(context)->checker; + auto *checkerE2p = reinterpret_cast(context)->GetChecker(); auto newStatusE2p = E2pToIrCheckerStatus(newStatus); auto *ctx = reinterpret_cast(context); auto *ctxAllocator = ctx->allocator; @@ -97,7 +97,7 @@ TEST_F(PluginConversionRuleUnitTest, CheckerContextPtrConstructor) extern "C" es2panda_CheckerContext *CreateCheckerContext([[maybe_unused]] es2panda_Context *context, [[maybe_unused]] Es2pandaCheckerStatus newStatus) { - auto *checkerE2p = reinterpret_cast(context)->checker; + auto *checkerE2p = reinterpret_cast(context)->GetChecker(); auto newStatusE2p = E2pToIrCheckerStatus(newStatus); auto *ctx = reinterpret_cast(context); auto *ctxAllocator = ctx->allocator; @@ -352,12 +352,11 @@ TEST_F(PluginConversionRuleUnitTest, PropertyProcessorInputParameter) extern "C" void ETSObjectTypeUpdateTypeProperties([[maybe_unused]] es2panda_Context *context, es2panda_Type *classInstance, [[maybe_unused]] PropertyProcessor func/*return_args:*/) { - auto *checkerE2p = reinterpret_cast(context)->checker->AsETSChecker(); std::function funcE2p = [func](varbinder::LocalVariable *propertyProcessorLambdaVariable, checker::Type *propertyProcessorLambdaType) { return reinterpret_cast(func(reinterpret_cast (propertyProcessorLambdaVariable), reinterpret_cast(propertyProcessorLambdaType)));}; - ((reinterpret_cast< checker::ETSObjectType *>(classInstance))->UpdateTypeProperties(checkerE2p, funcE2p)); + ((reinterpret_cast< checker::ETSObjectType *>(classInstance))->UpdateTypeProperties(funcE2p)); })"}; std::string targetAPIWithNoSpace = RemoveWhitespace(targetCAPI); diff --git a/ets2panda/test/unit/public/ast_verifier_check_abstract_call_test.cpp b/ets2panda/test/unit/public/ast_verifier_check_abstract_call_test.cpp index 4564a46588..7814d7f261 100644 --- a/ets2panda/test/unit/public/ast_verifier_check_abstract_call_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_check_abstract_call_test.cpp @@ -33,7 +33,7 @@ namespace { TEST_F(ASTVerifierTest, LabelsHaveReferences) { ark::es2panda::util::DiagnosticEngine de; - ark::es2panda::checker::ETSChecker checker(de); + ark::es2panda::checker::ETSChecker checker {Allocator(), de}; char const *text = R"( abstract class A { diff --git a/ets2panda/test/unit/public/ast_verifier_check_const_properties_test.cpp b/ets2panda/test/unit/public/ast_verifier_check_const_properties_test.cpp index 51b3a9e2cf..2652cdfe6f 100644 --- a/ets2panda/test/unit/public/ast_verifier_check_const_properties_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_check_const_properties_test.cpp @@ -26,7 +26,7 @@ namespace { TEST_F(ASTVerifierTest, CheckConstProperties) { ark::es2panda::util::DiagnosticEngine de {}; - ark::es2panda::checker::ETSChecker checker {de}; + ark::es2panda::checker::ETSChecker checker {Allocator(), de}; char const *text = R"( class Test diff --git a/ets2panda/test/unit/public/ast_verifier_getter_setter_neg_test.cpp b/ets2panda/test/unit/public/ast_verifier_getter_setter_neg_test.cpp index b8d0e49604..651b6ab840 100644 --- a/ets2panda/test/unit/public/ast_verifier_getter_setter_neg_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_getter_setter_neg_test.cpp @@ -29,7 +29,7 @@ namespace { TEST_F(ASTVerifierTest, ValidateGetterReturnTypeAnnotation) { DiagnosticEngine de {}; - ETSChecker checker {de}; + ETSChecker checker {Allocator(), de}; char const *text = R"( @@ -87,7 +87,7 @@ TEST_F(ASTVerifierTest, ValidateGetterHasReturnStatement) auto *const method = child->AsMethodDefinition(); if (method->IsGetter() && method->Value()->IsFunctionExpression()) { auto *const function = method->Value()->AsFunctionExpression()->Function(); - auto &returns = function->ReturnStatements(); + auto &returns = function->ReturnStatementsForUpdate(); returns.clear(); } } @@ -104,7 +104,7 @@ TEST_F(ASTVerifierTest, ValidateGetterHasReturnStatement) TEST_F(ASTVerifierTest, ValidateGetterVoidReturnStatement) { DiagnosticEngine de {}; - ETSChecker checker {de}; + ETSChecker checker {Allocator(), de}; char const *text = R"( @@ -142,7 +142,7 @@ TEST_F(ASTVerifierTest, ValidateGetterVoidReturnStatement) TEST_F(ASTVerifierTest, ValidateGetterArguments) { DiagnosticEngine de {}; - ETSChecker checker {de}; + ETSChecker checker {Allocator(), de}; char const *text = R"( @@ -166,7 +166,7 @@ TEST_F(ASTVerifierTest, ValidateGetterArguments) auto *const method = child->AsMethodDefinition(); if (method->IsGetter() && method->Value()->IsFunctionExpression()) { auto *const function = method->Value()->AsFunctionExpression()->Function(); - auto ¶ms = function->Params(); + auto ¶ms = function->ParamsForUpdate(); ASSERT_EQ(params.size(), 0); params.push_back(param); } @@ -184,7 +184,7 @@ TEST_F(ASTVerifierTest, ValidateGetterArguments) TEST_F(ASTVerifierTest, ValidateSetterReturnType) { DiagnosticEngine de {}; - ETSChecker checker {de}; + ETSChecker checker {Allocator(), de}; char const *text = R"( @@ -225,7 +225,7 @@ TEST_F(ASTVerifierTest, ValidateSetterReturnType) TEST_F(ASTVerifierTest, ValidateSetterArguments) { DiagnosticEngine de {}; - ETSChecker checker {de}; + ETSChecker checker {Allocator(), de}; char const *text = R"( @@ -245,7 +245,7 @@ TEST_F(ASTVerifierTest, ValidateSetterArguments) auto *const method = child->AsMethodDefinition(); if (method->IsSetter() && method->Value()->IsFunctionExpression()) { auto *const function = method->Value()->AsFunctionExpression()->Function(); - auto ¶ms = function->Params(); + auto ¶ms = function->ParamsForUpdate(); ASSERT_EQ(params.size(), 1); params.clear(); } diff --git a/ets2panda/test/unit/public/ast_verifier_getter_setter_test.cpp b/ets2panda/test/unit/public/ast_verifier_getter_setter_test.cpp index 7ee4731ed7..542d91ddf7 100644 --- a/ets2panda/test/unit/public/ast_verifier_getter_setter_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_getter_setter_test.cpp @@ -27,7 +27,7 @@ namespace { TEST_F(ASTVerifierTest, ValidateCorrectGetterSetter) { DiagnosticEngine de {}; - ETSChecker checker {de}; + ETSChecker checker {Allocator(), de}; char const *text = R"( @@ -52,7 +52,7 @@ TEST_F(ASTVerifierTest, ValidateCorrectGetterSetter) TEST_F(ASTVerifierTest, ValidateAbstractGettersSetters) { DiagnosticEngine de {}; - ETSChecker checker {de}; + ETSChecker checker {Allocator(), de}; char const *text = R"( @@ -72,7 +72,7 @@ TEST_F(ASTVerifierTest, ValidateAbstractGettersSetters) TEST_F(ASTVerifierTest, ValidateAmbientGettersSetters) { DiagnosticEngine de {}; - ETSChecker checker {de}; + ETSChecker checker {Allocator(), de}; char const *text = R"( diff --git a/ets2panda/test/unit/public/ast_verifier_short_test.cpp b/ets2panda/test/unit/public/ast_verifier_short_test.cpp index c5cf75fa2b..4a20d2a054 100644 --- a/ets2panda/test/unit/public/ast_verifier_short_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_short_test.cpp @@ -119,7 +119,7 @@ TEST_F(ASTVerifierTest, ScopeNodeTest) TEST_F(ASTVerifierTest, ArithmeticExpressionCorrect1) { DiagnosticEngine de {}; - ETSChecker etschecker {de}; + ETSChecker etschecker {Allocator(), de}; auto left = NumberLiteral(Number {1}); auto right = NumberLiteral(Number {6}); @@ -134,7 +134,7 @@ TEST_F(ASTVerifierTest, ArithmeticExpressionCorrect1) TEST_F(ASTVerifierTest, ArithmeticExpressionCorrect2) { DiagnosticEngine de {}; - ETSChecker etschecker {de}; + ETSChecker etschecker {Allocator(), de}; constexpr uint32_t LEFT1_PARAM = 1; constexpr uint32_t LEFT2_PARAM = 12; @@ -156,7 +156,7 @@ TEST_F(ASTVerifierTest, ArithmeticExpressionCorrect2) TEST_F(ASTVerifierTest, ArithmeticExpressionNegative1) { DiagnosticEngine de {}; - ETSChecker etschecker {de}; + ETSChecker etschecker {Allocator(), de}; const StringView leftParam("1"); constexpr uint32_t RIGHT_PARAM = 1; @@ -174,7 +174,7 @@ TEST_F(ASTVerifierTest, ArithmeticExpressionNegative1) TEST_F(ASTVerifierTest, ArithmeticExpressionNegative2) { DiagnosticEngine de {}; - ETSChecker etschecker {de}; + ETSChecker etschecker {Allocator(), de}; auto left = BooleanLiteral(true); auto right = NumberLiteral(Number {1}); @@ -190,7 +190,7 @@ TEST_F(ASTVerifierTest, ArithmeticExpressionNegative2) TEST_F(ASTVerifierTest, PrimitiveType) { DiagnosticEngine de {}; - ETSChecker etschecker {de}; + ETSChecker etschecker {Allocator(), de}; auto ast = BooleanLiteral(true); ast.SetTsType(etschecker.CreateETSBooleanType(true)); @@ -204,7 +204,7 @@ TEST_F(ASTVerifierTest, PrimitiveType) TEST_F(ASTVerifierTest, SequenceExpressionType) { auto de = DiagnosticEngine(); - auto checker = ETSChecker(de); + auto checker = ETSChecker(Allocator(), de); const auto literalsCount = 3; std::array literals {NumberLiteral {Number {1}}, NumberLiteral {Number {2}}, NumberLiteral {Number {3}}}; diff --git a/ets2panda/test/unit/sizeof_node_test.cpp b/ets2panda/test/unit/sizeof_node_test.cpp index 428a6010b7..3d964e211d 100644 --- a/ets2panda/test/unit/sizeof_node_test.cpp +++ b/ets2panda/test/unit/sizeof_node_test.cpp @@ -69,6 +69,7 @@ size_t SizeOfNodeTest::SizeOf() sizeof(node->flags_) + sizeof(node->astNodeFlags_) + sizeof(node->boxingUnboxingFlags_) + + sizeof(node->history_) + sizeof(node->variable_) + sizeof(node->originalNode_) + sizeof(node->transformedNode_); @@ -588,7 +589,8 @@ size_t SizeOfNodeTest::SizeOf() return SizeOf>>() + sizeof(node->ident_) + Align(sizeof(node->flag_)) + - sizeof(node->program_); + sizeof(node->program_)+ + sizeof(node->globalClass_); // clang-format on } diff --git a/ets2panda/test/unit/union_normalisation_test.h b/ets2panda/test/unit/union_normalisation_test.h index 0a7312aa66..36b345f6c3 100644 --- a/ets2panda/test/unit/union_normalisation_test.h +++ b/ets2panda/test/unit/union_normalisation_test.h @@ -16,6 +16,7 @@ #ifndef PANDA_UNION_NORMALISATION_TEST_H #define PANDA_UNION_NORMALISATION_TEST_H +#include "ir/astNode.h" #include "util/options.h" namespace ark::es2panda::gtests { @@ -23,10 +24,11 @@ namespace ark::es2panda::gtests { class UnionNormalizationTest : public testing::Test { public: UnionNormalizationTest() - : allocator_(std::make_unique(SpaceType::SPACE_TYPE_COMPILER)), + : allocator_(std::make_unique(SpaceType::SPACE_TYPE_COMPILER, nullptr, true)), publicContext_ {std::make_unique()}, + phaseManager_ {ScriptExtension::ETS, Allocator()}, program_ {parser::Program::NewProgram(Allocator())}, - checker_ {diagnosticEngine_} + checker_ {Allocator(), diagnosticEngine_} { } @@ -38,7 +40,7 @@ public: PoolManager::Initialize(); } - ArenaAllocator *Allocator() + ark::ThreadSafeArenaAllocator *Allocator() { return allocator_.get(); } @@ -103,7 +105,7 @@ public: varbinder->SetContext(publicContext_.get()); auto emitter = Emitter(publicContext_.get()); - auto phaseManager = compiler::PhaseManager(unit.ext, allocator_.get()); + auto phaseManager = new compiler::PhaseManager(publicContext_.get(), unit.ext, allocator_.get()); auto config = public_lib::ConfigImpl {}; publicContext_->config = &config; @@ -111,12 +113,14 @@ public: publicContext_->sourceFile = &unit.input; publicContext_->allocator = allocator_.get(); publicContext_->parser = &parser; - publicContext_->checker = checker; - publicContext_->analyzer = publicContext_->checker->GetAnalyzer(); - publicContext_->emitter = &emitter; + parser.SetContext(publicContext_.get()); publicContext_->parserProgram = program; + publicContext_->PushChecker(checker); + publicContext_->PushAnalyzer(publicContext_->GetChecker()->GetAnalyzer()); + publicContext_->emitter = &emitter; publicContext_->diagnosticEngine = &diagnosticEngine_; - publicContext_->phaseManager = &phaseManager; + publicContext_->phaseManager = phaseManager; + publicContext_->GetChecker()->Initialize(varbinder); parser.ParseScript(unit.input, unit.options.GetCompilationMode() == CompilationMode::GEN_STD_LIB); while (auto phase = publicContext_->phaseManager->NextPhase()) { if (!phase->Apply(publicContext_.get(), program)) { @@ -158,8 +162,9 @@ protected: static constexpr uint8_t IDX2 = 2; private: - std::unique_ptr allocator_; + std::unique_ptr allocator_; std::unique_ptr publicContext_; + ark::es2panda::compiler::PhaseManager phaseManager_; parser::Program program_; util::DiagnosticEngine diagnosticEngine_; checker::ETSChecker checker_; diff --git a/ets2panda/test/utils/ast_verifier_test.cpp b/ets2panda/test/utils/ast_verifier_test.cpp index 96fc2c38f9..2175041ca7 100644 --- a/ets2panda/test/utils/ast_verifier_test.cpp +++ b/ets2panda/test/utils/ast_verifier_test.cpp @@ -15,21 +15,25 @@ #include "ast_verifier_test.h" +#include + namespace test::utils { AstVerifierTest::AstVerifierTest() { impl_ = es2panda_GetImpl(ES2PANDA_LIB_VERSION); + impl_->MemInitialize(); auto es2pandaPath = test::utils::PandaExecutablePathGetter::Get()[0]; std::array argv = {es2pandaPath}; cfg_ = impl_->CreateConfig(argv.size(), argv.data()); - allocator_ = new ark::ArenaAllocator(ark::SpaceType::SPACE_TYPE_COMPILER); + allocator_ = new ark::ThreadSafeArenaAllocator(ark::SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + phaseManager_ = new ark::es2panda::compiler::PhaseManager(nullptr, ark::es2panda::ScriptExtension::ETS, allocator_); } AstVerifierTest::~AstVerifierTest() { ASSERT(ctx_ == nullptr); - delete allocator_; + impl_->MemFinalize(); impl_->DestroyConfig(cfg_); } diff --git a/ets2panda/test/utils/ast_verifier_test.h b/ets2panda/test/utils/ast_verifier_test.h index 68ccb22ecb..0d4d9fd955 100644 --- a/ets2panda/test/utils/ast_verifier_test.h +++ b/ets2panda/test/utils/ast_verifier_test.h @@ -18,6 +18,7 @@ #include "ast_verifier/ASTVerifier.h" #include "panda_executable_path_getter.h" +#include "compiler/lowering/phase.h" #include @@ -44,14 +45,14 @@ public: NO_MOVE_SEMANTIC(AstVerifierTest); ~AstVerifierTest() override; - ark::ArenaAllocator *Allocator() const + ark::ThreadSafeArenaAllocator *Allocator() const { return allocator_; } auto *GetChecker() { - return reinterpret_cast(ctx_)->checker->AsETSChecker(); + return reinterpret_cast(ctx_)->GetChecker()->AsETSChecker(); } auto *GetAst() @@ -205,7 +206,8 @@ private: es2panda_Impl const *impl_ {}; es2panda_Config *cfg_ {}; es2panda_Context *ctx_ {}; - ark::ArenaAllocator *allocator_ {}; + ark::ThreadSafeArenaAllocator *allocator_ {}; + ark::es2panda::compiler::PhaseManager *phaseManager_; friend class ::LSPAPITests; }; diff --git a/ets2panda/test/utils/checker_test.h b/ets2panda/test/utils/checker_test.h index cd41db0d66..79259abbad 100644 --- a/ets2panda/test/utils/checker_test.h +++ b/ets2panda/test/utils/checker_test.h @@ -22,6 +22,7 @@ #include "compiler/core/regSpiller.h" #include "compiler/core/ETSemitter.h" #include "checker/ETSAnalyzer.h" +#include "ir/astNode.h" #include "util/options.h" #include "util/diagnosticEngine.h" #include @@ -38,11 +39,13 @@ namespace test::utils { class CheckerTest : public testing::Test { public: CheckerTest() - : allocator_(std::make_unique(ark::SpaceType::SPACE_TYPE_COMPILER)), + : allocator_( + std::make_unique(ark::SpaceType::SPACE_TYPE_COMPILER, nullptr, true)), publicContext_ {std::make_unique()}, + phaseManager_ {ark::es2panda::ScriptExtension::ETS, Allocator()}, program_ {parser_alias::Program::NewProgram(allocator_.get())}, es2pandaPath_ {PandaExecutablePathGetter::Get()[0]}, - checker_(diagnosticEngine_) + checker_(allocator_.get(), diagnosticEngine_) { } ~CheckerTest() override = default; @@ -57,7 +60,7 @@ public: return &checker_; } - ark::ArenaAllocator *Allocator() + ark::ThreadSafeArenaAllocator *Allocator() { return allocator_.get(); } @@ -110,7 +113,7 @@ public: varbinder->SetContext(publicContext_.get()); auto emitter = Emitter(publicContext_.get()); - auto phaseManager = compiler_alias::PhaseManager(unit.ext, allocator_.get()); + auto phaseManager = compiler_alias::PhaseManager(publicContext_.get(), unit.ext, allocator_.get()); auto config = plib_alias::ConfigImpl {}; publicContext_->config = &config; @@ -118,12 +121,14 @@ public: publicContext_->sourceFile = &unit.input; publicContext_->allocator = allocator_.get(); publicContext_->parser = &parser; - publicContext_->checker = checker; - publicContext_->analyzer = publicContext_->checker->GetAnalyzer(); - publicContext_->emitter = &emitter; + parser.SetContext(publicContext_.get()); publicContext_->parserProgram = program; + publicContext_->PushChecker(checker); + publicContext_->PushAnalyzer(publicContext_->GetChecker()->GetAnalyzer()); + publicContext_->emitter = &emitter; publicContext_->diagnosticEngine = &diagnosticEngine_; publicContext_->phaseManager = &phaseManager; + publicContext_->GetChecker()->Initialize(varbinder); parser.ParseScript(unit.input, unit.options.GetCompilationMode() == ark::es2panda::CompilationMode::GEN_STD_LIB); while (auto phase = publicContext_->phaseManager->NextPhase()) { @@ -136,8 +141,9 @@ public: NO_MOVE_SEMANTIC(CheckerTest); private: - std::unique_ptr allocator_; + std::unique_ptr allocator_; std::unique_ptr publicContext_; + ark::es2panda::compiler::PhaseManager phaseManager_; parser_alias::Program program_; std::string es2pandaPath_; util_alias::DiagnosticEngine diagnosticEngine_; diff --git a/ets2panda/test/utils/scope_init_test.h b/ets2panda/test/utils/scope_init_test.h index ce8df944ba..2529a908f5 100644 --- a/ets2panda/test/utils/scope_init_test.h +++ b/ets2panda/test/utils/scope_init_test.h @@ -21,6 +21,7 @@ #include "ir/statements/variableDeclarator.h" #include "ir/statements/variableDeclaration.h" #include "mem/pool_manager.h" +#include "compiler/lowering/phase.h" #include @@ -30,7 +31,14 @@ namespace test::utils { class ScopeInitTest : public testing::Test { public: - ScopeInitTest() : allocator_(std::make_unique(ark::SpaceType::SPACE_TYPE_COMPILER)) {} + ScopeInitTest() + : allocator_( + std::make_unique(ark::SpaceType::SPACE_TYPE_COMPILER, nullptr, true)) + { + phaseManager_ = std::make_unique(ark::es2panda::ScriptExtension::ETS, + allocator_.get()); + ark::es2panda::compiler::SetPhaseManager(phaseManager_.get()); + } /* * Shortcut to convert single elemnt block expression body to it's name @@ -44,13 +52,14 @@ public: ark::PoolManager::Initialize(); } - ark::ArenaAllocator *Allocator() + ark::ThreadSafeArenaAllocator *Allocator() { return allocator_.get(); } private: - std::unique_ptr allocator_; + std::unique_ptr allocator_; + std::unique_ptr phaseManager_; }; } // namespace test::utils diff --git a/ets2panda/util/diagnosticEngine.cpp b/ets2panda/util/diagnosticEngine.cpp index 131ca76cf8..1108b9e7f1 100644 --- a/ets2panda/util/diagnosticEngine.cpp +++ b/ets2panda/util/diagnosticEngine.cpp @@ -52,8 +52,8 @@ DiagnosticStorage DiagnosticEngine::GetAllDiagnostic() DiagnosticStorage merged; merged.reserve(totalSize); for (auto &vec : diagnostics_) { - for (auto &&diag : vec) { - merged.emplace_back(std::move(diag)); + for (auto &diag : vec) { + merged.emplace_back(diag); } } return merged; diff --git a/ets2panda/util/diagnosticEngine.h b/ets2panda/util/diagnosticEngine.h index 0562a1cb45..015dc4d6ad 100644 --- a/ets2panda/util/diagnosticEngine.h +++ b/ets2panda/util/diagnosticEngine.h @@ -46,7 +46,7 @@ public: void Print(const DiagnosticBase &diagnostic) const override; }; -using DiagnosticStorage = std::vector>; +using DiagnosticStorage = std::vector>; class DiagnosticEngine { public: @@ -79,6 +79,13 @@ public: LogDiagnostic(std::forward(args)...); } + void ClearDiagnostics() + { + for (auto &it : diagnostics_) { + it.clear(); + } + } + // NOTE(schernykh): should be removed void Log([[maybe_unused]] const ThrowableDiagnostic &error) { diff --git a/ets2panda/util/enumbitops.h b/ets2panda/util/enumbitops.h index 46a95feeb1..b22f3325b1 100644 --- a/ets2panda/util/enumbitops.h +++ b/ets2panda/util/enumbitops.h @@ -27,7 +27,9 @@ enumbitops::operator^, \ enumbitops::operator|=, \ enumbitops::operator&=, \ - enumbitops::operator^= + enumbitops::operator^=, \ + enumbitops::All, \ + enumbitops::Any // clang-format on namespace enumbitops { @@ -98,6 +100,20 @@ inline constexpr T &operator^=(T &a, T b) return a = a ^ b; } +template ::value, bool> = true> +inline constexpr bool All(T flags, T test) +{ + using Utype = std::underlying_type_t; + return (flags & test) == static_cast(test); +} + +template ::value, bool> = true> +inline constexpr bool Any(T flags, T test) +{ + using Utype = std::underlying_type_t; + return (flags & test) != static_cast(0); +} + } // namespace enumbitops #endif diff --git a/ets2panda/util/es2pandaMacros.h b/ets2panda/util/es2pandaMacros.h index cc0990c7b5..6764fadf6a 100644 --- a/ets2panda/util/es2pandaMacros.h +++ b/ets2panda/util/es2pandaMacros.h @@ -18,6 +18,7 @@ #include "macros.h" #include "lexer/token/sourceLocation.h" + namespace ark::es2panda::parser { class Program; } // namespace ark::es2panda::parser diff --git a/ets2panda/util/importPathManager.h b/ets2panda/util/importPathManager.h index 21095663b0..9e011a2159 100644 --- a/ets2panda/util/importPathManager.h +++ b/ets2panda/util/importPathManager.h @@ -130,6 +130,11 @@ public: return parseList_; } + void ClearParseList() + { + parseList_.clear(); + } + util::StringView FormModuleName(const util::Path &path, const lexer::SourcePosition &srcPos); ImportMetadata GatherImportMetadata(parser::Program *program, ImportFlags importFlags, ir::StringLiteral *importPath); @@ -161,7 +166,8 @@ private: std::string TryMatchDynamicPath(std::string_view fixedPath) const; StringView GetRealPath(StringView path) const; - void AddToParseList(const ImportMetadata importMetadata); +public: + void AddToParseList(ImportMetadata importMetadata); #ifdef USE_UNIX_SYSCALL void UnixWalkThroughDirectoryAndAddToParseList(ImportMetadata importMetadata); #endif diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index 0f9ae6db10..3c1b368ce7 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -77,7 +77,7 @@ bool ETSBinder::HandleDynamicVariables(ir::Identifier *ident, Variable *variable bool ETSBinder::LookupInDebugInfoPlugin(ir::Identifier *ident) { - auto *checker = GetContext()->checker->AsETSChecker(); + auto *checker = GetContext()->GetChecker()->AsETSChecker(); auto *debugInfoPlugin = checker->GetDebugInfoPlugin(); if (UNLIKELY(debugInfoPlugin)) { auto *var = debugInfoPlugin->FindClass(ident); @@ -98,7 +98,7 @@ static void CreateDummyVariable(ETSBinder *varBinder, ir::Identifier *ident) varBinder->NewVarDecl(ident->Start(), compiler::GenName(varBinder->Allocator()).View()); var->SetScope(varBinder->GetScope()); ident->SetVariable(var); - ident->SetTsType(var->SetTsType(varBinder->GetContext()->checker->AsETSChecker()->GlobalTypeError())); + ident->SetTsType(var->SetTsType(varBinder->GetContext()->GetChecker()->AsETSChecker()->GlobalTypeError())); decl->BindNode(ident); } @@ -520,7 +520,7 @@ void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *classDef) } } else { ES2PANDA_ASSERT(GetContext()->diagnosticEngine->IsAnyError()); - auto *checker = GetContext()->checker->AsETSChecker(); + auto *checker = GetContext()->GetChecker()->AsETSChecker(); prop->SetTsType(checker->GlobalTypeError()); prop->Id()->SetTsType(checker->GlobalTypeError()); } @@ -647,11 +647,13 @@ void AddOverloadFlag(ArenaAllocator *allocator, bool isStdLib, varbinder::Variab if (!currentNode->HasOverload(method)) { currentNode->AddOverload(method); - method->Function()->Id()->SetVariable(variable); - method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); - method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD); - util::UString newInternalName(method->Function()->Scope()->Name(), allocator); - method->Function()->Scope()->BindInternalName(newInternalName.View()); + if (method->Function()->Scope()->InternalName() == "") { + method->Function()->Id()->SetVariable(variable); + method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); + method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD); + util::UString newInternalName(method->Function()->Scope()->Name(), allocator); + method->Function()->Scope()->BindInternalName(newInternalName.View()); + } } } @@ -664,6 +666,9 @@ void ETSBinder::ImportAllForeignBindings(ir::AstNode *const specifier, bool const isStdLib = util::Helpers::IsStdLib(Program()); for (const auto [bindingName, var] : globalBindings) { + if (!var->Declaration()->Node()->IsValidInCurrentPhase()) { + continue; + } if (util::Helpers::IsGlobalVar(var)) { const auto *const classDef = var->Declaration()->Node()->AsClassDeclaration()->Definition(); ImportGlobalProperties(classDef); @@ -973,7 +978,10 @@ static Variable *FindInStatic(parser::Program *program) static Variable *FindInInstance(parser::Program *program) { - auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); }; + auto predicateFunc = [](const auto &item) { + return item.second->Declaration()->Node()->IsValidInCurrentPhase() && + item.second->Declaration()->Node()->IsDefaultExported(); + }; const auto &instanceMethodBindings = program->GlobalClassScope()->InstanceMethodScope()->Bindings(); auto result = std::find_if(instanceMethodBindings.begin(), instanceMethodBindings.end(), predicateFunc); if (result == instanceMethodBindings.end()) { @@ -1117,7 +1125,7 @@ bool ETSBinder::BuildInternalName(ir::ScriptFunction *scriptFunc) bool compilable = scriptFunc->Body() != nullptr && !isExternal; if (!compilable) { - recordTable_->Signatures().push_back(funcScope); + recordTable_->EmplaceSignatures(funcScope, scriptFunc); } return compilable; @@ -1140,7 +1148,7 @@ bool ETSBinder::BuildInternalNameWithCustomRecordTable(ir::ScriptFunction *const const bool compilable = scriptFunc->Body() != nullptr && !isExternal; if (!compilable) { - recordTable->Signatures().push_back(funcScope); + recordTable->EmplaceSignatures(funcScope, scriptFunc); } return compilable; @@ -1195,10 +1203,7 @@ void ETSBinder::BuildProgram() for (auto &[_, extPrograms] : Program()->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { - if (!extProg->GetFlag(parser::ProgramFlags::AST_IDENTIFIER_ANALYZED)) { - BuildExternalProgram(extProg); - extProg->SetFlag(parser::ProgramFlags::AST_IDENTIFIER_ANALYZED); - } + BuildExternalProgram(extProg); } } @@ -1208,7 +1213,7 @@ void ETSBinder::BuildProgram() ValidateReexports(); - auto &stmts = Program()->Ast()->Statements(); + auto &stmts = Program()->Ast()->StatementsForUpdates(); const auto etsGlobal = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) { return stmt->IsClassDeclaration() && stmt->AsClassDeclaration()->Definition()->IsGlobal(); }); @@ -1234,13 +1239,19 @@ void ETSBinder::BuildExternalProgram(parser::Program *extProgram) auto flags = Program()->VarBinder()->IsGenStdLib() ? RecordTableFlags::NONE : RecordTableFlags::EXTERNAL; auto *extRecordTable = Allocator()->New(Allocator(), extProgram, flags); + extRecordTable->SetClassDefinition(extProgram->GlobalClass()); + externalRecordTable_.insert({extProgram, extRecordTable}); ResetTopScope(extProgram->GlobalScope()); recordTable_ = extRecordTable; SetProgram(extProgram); - BuildProgram(); + if (!extProgram->IsASTLowered()) { + BuildProgram(); + } else { + extRecordTable->Merge(extProgram->VarBinder()->AsETSBinder()->GetExternalRecordTable().at(extProgram)); + } SetProgram(savedProgram); recordTable_ = savedRecordTable; @@ -1332,7 +1343,7 @@ void ETSBinder::ValidateReexportDeclaration(ir::ETSReExportDeclaration *decl) const auto *const import = decl->GetETSImportDeclarations(); const auto &specifiers = import->Specifiers(); - for (auto specifier : specifiers) { + for (auto const specifier : specifiers) { // Example: export {foo} from "./A" if (specifier->IsImportSpecifier()) { auto importSpecifier = specifier->AsImportSpecifier(); diff --git a/ets2panda/varbinder/ETSBinder.h b/ets2panda/varbinder/ETSBinder.h index 6d24b0f3c7..140596eccd 100644 --- a/ets2panda/varbinder/ETSBinder.h +++ b/ets2panda/varbinder/ETSBinder.h @@ -209,10 +209,15 @@ public: void AddReExportImport(ir::ETSReExportDeclaration *reExport) noexcept { - reExportImports_.push_back(reExport); + reExportImports_.insert(reExport); } - [[nodiscard]] const ArenaVector &ReExportImports() const noexcept + [[nodiscard]] const ArenaUnorderedSet &ReExportImports() const noexcept + { + return reExportImports_; + } + + [[nodiscard]] ArenaUnorderedSet &ReExportImports() noexcept { return reExportImports_; } @@ -273,6 +278,18 @@ public: globalRecordTable_.CleanUp(); } + void CopyTo(VarBinder *target) override + { + auto targetImpl = reinterpret_cast(target); + + targetImpl->defaultImports_ = defaultImports_; + InitImplicitThisParam(); + targetImpl->selectiveExportAliasMultimap_ = selectiveExportAliasMultimap_; + ; + + VarBinder::CopyTo(target); + } + private: void BuildClassDefinitionImpl(ir::ClassDefinition *classDef); void InitImplicitThisParam(); @@ -293,14 +310,14 @@ private: RecordTable globalRecordTable_; RecordTable *recordTable_; ArenaMap externalRecordTable_; - ArenaVector defaultImports_; + ArenaVector defaultImports_; // 1 ArenaVector dynamicImports_; - ArenaVector reExportImports_; + ArenaUnorderedSet reExportImports_; ArenaSet reexportedNames_; DynamicImportVariables dynamicImportVars_; - ir::Identifier *thisParam_ {}; + ir::Identifier *thisParam_ {}; // 2 ir::AstNode *defaultExport_ {}; - ModulesToExportedNamesWithAliases selectiveExportAliasMultimap_; + ModulesToExportedNamesWithAliases selectiveExportAliasMultimap_; // 3 friend class RecordTableContext; }; @@ -310,7 +327,8 @@ public: RecordTableContext(ETSBinder *varBinder, parser::Program *extProgram) : varBinder_(varBinder), savedRecordTable_(varBinder->recordTable_) { - if (extProgram != nullptr) { + if (extProgram != nullptr && + varBinder->externalRecordTable_.find(extProgram) != varBinder->externalRecordTable_.end()) { varBinder->recordTable_ = varBinder->externalRecordTable_[extProgram]; } } diff --git a/ets2panda/varbinder/recordTable.h b/ets2panda/varbinder/recordTable.h index 1b3c9bd10c..437a2ffb79 100644 --- a/ets2panda/varbinder/recordTable.h +++ b/ets2panda/varbinder/recordTable.h @@ -21,6 +21,8 @@ #include "util/ustring.h" #include "util/enumbitops.h" +#include + namespace ark::es2panda::parser { class Program; } // namespace ark::es2panda::parser @@ -72,6 +74,25 @@ public: ~RecordTable() = default; + void Merge(RecordTable *other) + { + for (auto classDef : other->classDefinitions_) { + classDefinitions_.insert(classDef); + } + + for (auto interfaceDecl : other->InterfaceDeclarations()) { + interfaceDeclarations_.insert(interfaceDecl); + } + + for (auto annoDecl : other->AnnotationDeclarations()) { + annotationDeclarations_.insert(annoDecl); + } + + for (auto sig : other->signatures_) { + signatures_.insert(sig); + } + } + bool IsExternal() const { return (flags_ & RecordTableFlags::EXTERNAL) != 0; @@ -107,16 +128,22 @@ public: return annotationDeclarations_; } - ArenaVector &Signatures() + ArenaSet &Signatures() { return signatures_; } - const ArenaVector &Signatures() const + const ArenaSet &Signatures() const { return signatures_; } + void EmplaceSignatures(varbinder::FunctionScope *signature, ir::ScriptFunction *func) + { + func->AddFlag(ir::ScriptFunctionFlags::IN_RECORD); + signatures_.insert(signature); + } + void SetClassDefinition(ir::ClassDefinition *classDefinition) { record_ = classDefinition; @@ -208,7 +235,7 @@ private: ArenaSet classDefinitions_; ArenaSet interfaceDeclarations_; ArenaSet annotationDeclarations_; - ArenaVector signatures_; + ArenaSet signatures_; RecordHolder record_ {nullptr}; parser::Program *program_ {}; BoundContext *boundCtx_ {}; diff --git a/ets2panda/varbinder/varbinder.h b/ets2panda/varbinder/varbinder.h index 7005e55370..ff674f639b 100644 --- a/ets2panda/varbinder/varbinder.h +++ b/ets2panda/varbinder/varbinder.h @@ -285,6 +285,15 @@ protected: functionScopes_.clear(); } + virtual void CopyTo(VarBinder *target) + { + target->program_ = program_; + target->allocator_ = allocator_; + target->context_ = context_; + target->bindingOptions_ = bindingOptions_; + target->genStdLib_ = genStdLib_; + } + private: parser::Program *program_ {}; ArenaAllocator *allocator_ {}; diff --git a/ets2panda/varbinder/variable.h b/ets2panda/varbinder/variable.h index ba937f6b01..be95eb82d3 100644 --- a/ets2panda/varbinder/variable.h +++ b/ets2panda/varbinder/variable.h @@ -152,7 +152,7 @@ private: class LocalVariable : public Variable { public: explicit LocalVariable(Decl *decl, VariableFlags flags); - explicit LocalVariable(VariableFlags flags); + explicit LocalVariable(const VariableFlags flags); VariableType Type() const override { -- Gitee