diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index c86dbcd5101999c998dfb9548412cf8df49cefd0..ce3d8c43a2c37a10d9da1837f6bfd84b9af6eb96 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -44,6 +44,35 @@ void ETSObjectType::Iterate(const PropertyTraverser &cb) const } } +void ETSObjectType::AddInterface(ETSObjectType *interfaceType) +{ + if (std::find(interfaces_.begin(), interfaces_.end(), interfaceType) == interfaces_.end()) { + interfaces_.push_back(interfaceType); + CacheSupertypeTransitive(interfaceType); + } +} + +void ETSObjectType::SetSuperType(ETSObjectType *super) +{ + superType_ = super; + if (super == nullptr) { + return; + } + CacheSupertypeTransitive(super); +} + +void ETSObjectType::CacheSupertypeTransitive(ETSObjectType *type) +{ + auto const insertType = [this](ETSObjectType *t) { + return transitiveSupertypes_.insert(t->GetOriginalBaseType()).second; + }; + if (insertType(type)) { + for (auto &t : type->transitiveSupertypes_) { + insertType(t); + } + } +} + varbinder::LocalVariable *ETSObjectType::SearchFieldsDecls(util::StringView name, PropertySearchFlags flags) const { varbinder::LocalVariable *res {}; @@ -67,35 +96,51 @@ varbinder::LocalVariable *ETSObjectType::SearchFieldsDecls(util::StringView name varbinder::LocalVariable *ETSObjectType::GetProperty(util::StringView name, PropertySearchFlags flags) const { - varbinder::LocalVariable *res = SearchFieldsDecls(name, flags); - if (res == nullptr && (flags & PropertySearchFlags::SEARCH_METHOD) != 0) { - if ((flags & PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION) != 0) { - if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) != 0) { - res = GetOwnProperty(name); + // CC-OFFNXT(G.FMT.14-CPP) project code style + auto const searchOwnMethod = [this, flags, name]() -> varbinder::LocalVariable * { + if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) != 0) { + if (auto res = GetOwnProperty(name); res != nullptr) { + return res; + } + } + if ((flags & PropertySearchFlags::SEARCH_STATIC_METHOD) != 0) { + if (auto res = GetOwnProperty(name); res != nullptr) { + return res; } + } + return nullptr; + }; - if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_METHOD) != 0)) { - res = GetOwnProperty(name); + if (auto res = SearchFieldsDecls(name, flags); res != nullptr) { + return res; + } + + if ((flags & PropertySearchFlags::SEARCH_METHOD) != 0) { + if ((flags & PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION) != 0) { + if (auto res = searchOwnMethod(); res != nullptr) { + return res; } } else { - res = CreateSyntheticVarFromEverySignature(name, flags); + if (auto res = CreateSyntheticVarFromEverySignature(name, flags)) { + return res; + } } } - if (res == nullptr && (flags & PropertySearchFlags::SEARCH_IN_INTERFACES) != 0) { + if (((flags & PropertySearchFlags::SEARCH_INSTANCE) != 0 || (flags & PropertySearchFlags::SEARCH_STATIC) == 0) && + (flags & PropertySearchFlags::SEARCH_IN_INTERFACES) != 0) { for (auto *interface : interfaces_) { - res = interface->GetProperty(name, flags); - if (res != nullptr) { + if (auto res = interface->GetProperty(name, flags); res != nullptr) { return res; } } } - if (res == nullptr && superType_ != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) { - res = superType_->GetProperty(name, flags); + if ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0 && superType_ != nullptr) { + return superType_->GetProperty(name, flags); } - return res; + return nullptr; } bool ETSObjectType::IsPropertyInherited(const varbinder::Variable *var) @@ -266,6 +311,10 @@ static void CollectSignaturesForSyntheticType(ETSObjectType const *owner, } } + if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) == 0) { + return; + } + if (owner->SuperType() != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) { CollectSignaturesForSyntheticType(owner->SuperType(), signatureSet, name, flags); } @@ -803,6 +852,14 @@ void ETSObjectType::IsSupertypeOf(TypeRelation *relation, Type *source) void ETSObjectType::IsSubtypeOf(TypeRelation *relation, Type *target) { + if (target->IsETSObjectType()) { + auto &transitives = transitiveSupertypes_; + if (transitives.find(target->AsETSObjectType()->GetOriginalBaseType()) == transitives.end()) { + relation->Result(false); + return; + } + } + if (auto super = SuperType(); super != nullptr) { if (relation->IsSupertypeOf(target, super)) { return; diff --git a/ets2panda/checker/types/ets/etsObjectType.h b/ets2panda/checker/types/ets/etsObjectType.h index 4c8538f0828a23af6d6cbff53b20055d760fd126..5f60a202513851e7544bfdc8579dfeb45a116804 100644 --- a/ets2panda/checker/types/ets/etsObjectType.h +++ b/ets2panda/checker/types/ets/etsObjectType.h @@ -67,20 +67,11 @@ public: propertiesInstantiated_ = true; } - void AddInterface(ETSObjectType *interfaceType) - { - if (std::find(interfaces_.begin(), interfaces_.end(), interfaceType) == interfaces_.end()) { - interfaces_.push_back(interfaceType); - } - } + void AddInterface(ETSObjectType *interfaceType); + void SetSuperType(ETSObjectType *super); ETSChecker *GetETSChecker(); - void SetSuperType(ETSObjectType *super) - { - superType_ = super; - } - void SetTypeArguments(ArenaVector &&typeArgs) { #ifndef NDEBUG @@ -415,6 +406,7 @@ private: reExportAlias_(allocator->Adapter()), flags_(std::get(info)), typeArguments_(allocator->Adapter()), + transitiveSupertypes_(allocator->Adapter()), relation_(std::get(info)), constructSignatures_(allocator->Adapter()), properties_ {(void(IS), PropertyMap {allocator->Adapter()})...} @@ -448,6 +440,8 @@ private: bool TryCastFloating(TypeRelation *const relation, Type *const target); bool TryCastUnboxable(TypeRelation *const relation, Type *const target); + void CacheSupertypeTransitive(ETSObjectType *type); + ir::TSTypeParameterDeclaration *GetTypeParams() const; ThreadSafeArenaAllocator *const allocator_; @@ -463,6 +457,9 @@ private: ETSObjectType *enclosingType_ {}; ETSObjectType *baseType_ {}; + // optimized subtyping + ArenaSet transitiveSupertypes_; + // for lazy properties instantiation TypeRelation *relation_ = nullptr; const Substitution *effectiveSubstitution_ = nullptr; diff --git a/ets2panda/checker/types/typeRelation.cpp b/ets2panda/checker/types/typeRelation.cpp index 80a8ad001a584dbb859a1dbd3ab14acf798ae4dc..680872e6d09694b9f21f02fe169037c120c9e145 100644 --- a/ets2panda/checker/types/typeRelation.cpp +++ b/ets2panda/checker/types/typeRelation.cpp @@ -256,13 +256,15 @@ bool TypeRelation::IsLegalBoxedPrimitiveConversion(Type *target, Type *source) bool TypeRelation::IsSupertypeOf(Type *super, Type *sub) { - if (super == sub) { + if (LIKELY(super == sub)) { return Result(true); } - if (sub == nullptr) { return false; } + if (super->IsETSPrimitiveType() != sub->IsETSPrimitiveType()) { + return false; + } result_ = CacheLookup(super, sub, checker_->SupertypeResults(), RelationType::SUPERTYPE); if (result_ == RelationResult::CACHE_MISS) { diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index d3dd8aa92638a92b867d7dfbfe356f7e9a031cdf..b87c2adb55faf3225d8036d8c30b9d5eb4c9fa33 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -122,7 +122,8 @@ static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc, for (const auto *var : paramScope->Params()) { func.params.emplace_back(PandasmTypeWithRank(var->TsType()), EXTENSION); - if (var->Declaration()->Node() == nullptr || !var->Declaration()->Node()->IsETSParameterExpression()) { + if (scriptFunc->IsExternal() || var->Declaration()->Node() == nullptr || + !var->Declaration()->Node()->IsETSParameterExpression()) { continue; } func.params.back().GetOrCreateMetadata().SetAnnotations(emitter->GenCustomAnnotations( @@ -144,7 +145,9 @@ static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc, accessFlags |= ACC_VARARGS; } func.metadata->SetAccessFlags(accessFlags); - func.metadata->SetAnnotations(emitter->GenCustomAnnotations(scriptFunc->Annotations(), func.name)); + if (!scriptFunc->IsExternal()) { + func.metadata->SetAnnotations(emitter->GenCustomAnnotations(scriptFunc->Annotations(), func.name)); + } return func; } @@ -501,14 +504,9 @@ void ETSEmitter::GenGlobalArrayRecord(const checker::ETSArrayType *arrayType, ch void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external) { auto *baseType = interfaceDecl->TsType()->AsETSObjectType(); - auto interfaceRecord = pandasm::Record(interfaceDecl->InternalName().Mutf8(), Program()->lang); - if (external) { - interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL); - } uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE; - if (interfaceDecl->IsStatic()) { accessFlags |= ACC_STATIC; } @@ -518,13 +516,6 @@ void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceD interfaceRecord.sourceFile = std::string {Context()->parserProgram->VarBinder()->Program()->RelativeFilePath()}; interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); - for (auto *it : baseType->Interfaces()) { - auto *declNode = it->GetDeclNode(); - ES2PANDA_ASSERT(declNode->IsTSInterfaceDeclaration()); - std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8(); - interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name); - } - GenClassInheritedFields(baseType, interfaceRecord); for (const auto *prop : interfaceDecl->Body()->Body()) { @@ -538,6 +529,19 @@ void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceD } } + if (external) { + interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL); + Program()->recordTable.emplace(interfaceRecord.name, std::move(interfaceRecord)); + return; + } + + for (auto *it : baseType->Interfaces()) { + auto *declNode = it->GetDeclNode(); + ES2PANDA_ASSERT(declNode->IsTSInterfaceDeclaration()); + std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8(); + interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name); + } + Program()->recordTable.emplace(interfaceRecord.name, std::move(interfaceRecord)); } @@ -593,16 +597,26 @@ static uint32_t GetAccessFlags(const ir::ClassDefinition *classDef) void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool external) { auto classRecord = pandasm::Record(classDef->InternalName().Mutf8(), Program()->lang); - if (external) { - classRecord.metadata->SetAttribute(Signatures::EXTERNAL); - } - - classRecord.metadata->SetAnnotations(GenCustomAnnotations(classDef->Annotations(), classRecord.name)); uint32_t accessFlags = GetAccessFlags(classDef); classRecord.metadata->SetAccessFlags(accessFlags); classRecord.sourceFile = std::string {Context()->parserProgram->VarBinder()->Program()->RelativeFilePath()}; auto *baseType = classDef->TsType()->AsETSObjectType(); + GenClassInheritedFields(baseType, classRecord); + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty()) { + continue; + } + + GenClassField(prop->AsClassProperty(), classRecord, external); + } + + if (external) { + classRecord.metadata->SetAttribute(Signatures::EXTERNAL); + Program()->recordTable.emplace(classRecord.name, std::move(classRecord)); + return; + } + if (baseType->SuperType() != nullptr) { classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, baseType->SuperType()->AssemblerName().Mutf8()); @@ -629,17 +643,9 @@ void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool extern classRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name); } - GenClassInheritedFields(baseType, classRecord); - for (const auto *prop : classDef->Body()) { - if (!prop->IsClassProperty()) { - continue; - } - - GenClassField(prop->AsClassProperty(), classRecord, external); - } + classRecord.metadata->SetAnnotations(GenCustomAnnotations(classDef->Annotations(), classRecord.name)); std::vector annotations = GenAnnotations(classDef); - if (classDef->IsNamespaceTransformed() || classDef->IsGlobalInitialized()) { annotations.push_back(GenAnnotationModule(classDef)); } diff --git a/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp b/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp index 0a3374acc29ed51294a32aa3902c52e7c829727d..2bffe0888e7eb8d0e63d098076de692df01fed1b 100644 --- a/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp +++ b/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp @@ -21,7 +21,7 @@ namespace ark::es2panda::compiler { bool CFGBuilderPhase::Perform(public_lib::Context *ctx, parser::Program *program) { - if (ctx->config->options->IsGenStdlib()) { + if (!ctx->config->options->IsDumpCfg() || ctx->config->options->IsGenStdlib()) { return true; } @@ -44,11 +44,8 @@ bool CFGBuilderPhase::Perform(public_lib::Context *ctx, parser::Program *program cfg->MergeEmptyBlocks(); - if (ctx->config->options->IsDumpCfg()) { - std::string filename = program->AbsoluteName().Mutf8(); - cfg->DumpDot((filename + ".dot").c_str()); - } - + std::string filename = program->AbsoluteName().Mutf8(); + cfg->DumpDot((filename + ".dot").c_str()); return true; } diff --git a/ets2panda/compiler/lowering/ets/convertPrimitiveCastMethodCall.h b/ets2panda/compiler/lowering/ets/convertPrimitiveCastMethodCall.h index 377ab6a73b1b5182b3ca2d731430f2c6c7d7940f..64ac95a07493bf1ed87d46d8080e168428f2bdc4 100644 --- a/ets2panda/compiler/lowering/ets/convertPrimitiveCastMethodCall.h +++ b/ets2panda/compiler/lowering/ets/convertPrimitiveCastMethodCall.h @@ -31,7 +31,7 @@ namespace ark::es2panda::compiler { // let d: double = 3.14 // let i: int = d as int // -class ConvertPrimitiveCastMethodCall : public PhaseForDeclarations { +class ConvertPrimitiveCastMethodCall : public PhaseForBodies { public: std::string_view Name() const override; bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; diff --git a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp index 4033c033f31f838d865d385b9ebdd4f503e404f9..434636afec6c75ad013f04bc2915bf7d502f22cd 100644 --- a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp +++ b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp @@ -115,27 +115,27 @@ void UpdateCallSignature(public_lib::Context *ctx, ir::CallExpression *expr) bool DeclareOverloadLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { // Note: Generate helper overload method - program->Ast()->TransformChildrenRecursively( - [ctx](ir::AstNode *ast) { - if (ast->IsMethodDefinition() && ast->AsMethodDefinition()->GetOverloadInfo().needHelperOverload) { - BuildOverloadHelperFunction(ctx, ast->AsMethodDefinition()); - } - return ast; - }, - Name()); + auto const transformMethodDef = [ctx](ir::AstNode *ast) { + if (ast->IsMethodDefinition() && ast->AsMethodDefinition()->GetOverloadInfo().needHelperOverload) { + BuildOverloadHelperFunction(ctx, ast->AsMethodDefinition()); + } + return ast; + }; // Note: Update signature for call expression - program->Ast()->TransformChildrenRecursively( - [ctx](ir::AstNode *ast) { - if (!ast->IsCallExpression() || ast->AsCallExpression()->Signature() == nullptr) { - return ast; - } - - if (ast->AsCallExpression()->Signature()->HasSignatureFlag(checker::SignatureFlags::DUPLICATE_ASM)) { - UpdateCallSignature(ctx, ast->AsCallExpression()); - } - + auto const transformCallExpr = [ctx](ir::AstNode *ast) { + if (!ast->IsCallExpression() || ast->AsCallExpression()->Signature() == nullptr) { return ast; + } + if (ast->AsCallExpression()->Signature()->HasSignatureFlag(checker::SignatureFlags::DUPLICATE_ASM)) { + UpdateCallSignature(ctx, ast->AsCallExpression()); + } + return ast; + }; + + program->Ast()->TransformChildrenRecursively( + [transformMethodDef, transformCallExpr](ir::AstNode *ast) { + return transformMethodDef(transformCallExpr(ast)); }, Name()); return true; diff --git a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp index 18ea80f9434a5da96724e18c44965c01d5c2cf7d..b9aafa87361b4555855a0375dbdf0706b9fbf3dc 100644 --- a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp +++ b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp @@ -317,8 +317,11 @@ bool InterfacePropertyDeclarationsPhase::PerformForModule(public_lib::Context *c return ast; }; - program->Ast()->TransformChildrenRecursively(handleInterfacePropertyDecl, Name()); - program->Ast()->TransformChildrenRecursively(handleClassPropertyDecl, Name()); + program->Ast()->TransformChildrenRecursively( + [handleClassPropertyDecl, handleInterfacePropertyDecl](ir::AstNode *const ast) { + return handleClassPropertyDecl(handleInterfacePropertyDecl(ast)); + }, + Name()); return true; } diff --git a/ets2panda/compiler/lowering/ets/resizableArrayLowering.cpp b/ets2panda/compiler/lowering/ets/resizableArrayLowering.cpp index 2ba3489fe42cce6427058e8d3bfae483b2511efb..2b9012963be009d6915d23177873abbf5a085628 100644 --- a/ets2panda/compiler/lowering/ets/resizableArrayLowering.cpp +++ b/ets2panda/compiler/lowering/ets/resizableArrayLowering.cpp @@ -38,7 +38,7 @@ static ir::AstNode *ConvertToResizableArrayType(ir::TSArrayType *node, public_li bool ResizableArrayConvert::PerformForModule(public_lib::Context *ctx, parser::Program *program) { bool insideAnnotdecl = false; - program->Ast()->TransformChildrenRecursively( + program->Ast()->PreTransformChildrenRecursively( [&insideAnnotdecl, ctx](ir::AstNode *node) -> AstNodePtr { if (node->IsAnnotationDeclaration()) { ES2PANDA_ASSERT(!insideAnnotdecl); diff --git a/ets2panda/compiler/lowering/ets/setJumpTarget.h b/ets2panda/compiler/lowering/ets/setJumpTarget.h index ddef1ff51b4b92080a07176cb8c057324126907d..5c09f822ae3bfeb223b665ffbb8dd4321b06b63a 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 PhaseForDeclarations { +class SetJumpTargetPhase : public PhaseForBodies { public: std::string_view Name() const override { diff --git a/ets2panda/ir/astNode.cpp b/ets2panda/ir/astNode.cpp index 9661f1c36ce5dfbfd9d35f7d8ed39c2b1de88c4c..006c66348b88e5d45a56a25af2ee19b9cf599729 100644 --- a/ets2panda/ir/astNode.cpp +++ b/ets2panda/ir/astNode.cpp @@ -125,120 +125,6 @@ AstNode *AstNode::Clone([[maybe_unused]] ArenaAllocator *const allocator, [[mayb ES2PANDA_UNREACHABLE(); } -void AstNode::TransformChildrenRecursively(const NodeTransformer &cb, std::string_view transformationName) -{ // post-order, but use when you don't care about the order - TransformChildrenRecursivelyPostorder(cb, transformationName); -} - -void AstNode::TransformChildrenRecursively(const NodeTransformer &pre, const NodeTraverser &post, - std::string_view transformationName) -{ - TransformChildren( - [&pre, &post, transformationName](AstNode *child) { - auto *childReplacement = pre(child); - childReplacement->TransformChildrenRecursively(pre, post, transformationName); - post(childReplacement); - return childReplacement; - }, - transformationName); -} - -void AstNode::TransformChildrenRecursively(const NodeTraverser &pre, const NodeTransformer &post, - std::string_view transformationName) -{ - TransformChildren( - [&pre, &post, transformationName](AstNode *child) { - pre(child); - child->TransformChildrenRecursively(pre, post, transformationName); - return post(child); - }, - transformationName); -} - -void AstNode::TransformChildrenRecursivelyPreorder(const NodeTransformer &cb, std::string_view transformationName) -{ - TransformChildren( - [&cb, transformationName](AstNode *child) { - auto *res = cb(child); - res->TransformChildrenRecursivelyPreorder(cb, transformationName); - return res; - }, - transformationName); -} - -void AstNode::TransformChildrenRecursivelyPostorder(const NodeTransformer &cb, std::string_view transformationName) -{ - TransformChildren( - [&cb, transformationName](AstNode *child) { - child->TransformChildrenRecursivelyPostorder(cb, transformationName); - return cb(child); - }, - transformationName); -} - -void AstNode::IterateRecursively(const NodeTraverser &cb) const -{ // pre-order, use when you don't care - IterateRecursivelyPreorder(cb); -} - -void AstNode::IterateRecursivelyPreorder(const NodeTraverser &cb) const -{ - Iterate([&cb](AstNode *child) { - cb(child); - child->IterateRecursivelyPreorder(cb); - }); -} - -void AstNode::IterateRecursivelyPostorder(const NodeTraverser &cb) const -{ - Iterate([&cb](AstNode *child) { - child->IterateRecursivelyPostorder(cb); - cb(child); - }); -} - -void AnyChildHelper(bool *found, const NodePredicate &cb, AstNode *ast) -{ - if (*found) { - return; - } - - if (cb(ast)) { - *found = true; - return; - } - - ast->Iterate([&cb, found](AstNode *child) { AnyChildHelper(found, cb, child); }); -} - -bool AstNode::IsAnyChild(const NodePredicate &cb) const -{ - bool found = false; - Iterate([&found, cb](AstNode *child) { AnyChildHelper(&found, cb, child); }); - return found; -} - -void FindChildHelper(AstNode *&found, const NodePredicate &cb, AstNode *ast) -{ - if (found != nullptr) { - return; - } - - if (cb(ast)) { - found = ast; - return; - } - - ast->Iterate([&found, cb](AstNode *child) { FindChildHelper(found, cb, child); }); -} - -AstNode *AstNode::FindChild(const NodePredicate &cb) const -{ - AstNode *found = nullptr; - Iterate([&found, cb](AstNode *child) { FindChildHelper(found, cb, child); }); - return found; -} - varbinder::Scope *AstNode::EnclosingScope(const ir::AstNode *expr) noexcept { while (expr != nullptr && !expr->IsScopeBearer()) { @@ -381,17 +267,15 @@ compiler::PhaseId AstNode::GetFirstCreated() const return history_->FirstCreated(); } -AstNode *AstNode::GetHistoryNode() const +AstNode *AstNode::GetFromExistingHistory() const { - AstNode *node = nullptr; - - if (HistoryInitialized()) { - node = history_->Get(compiler::GetPhaseManager()->CurrentPhaseId()); - } else { - node = const_cast(this); + ES2PANDA_ASSERT(HistoryInitialized()); + auto node = history_->Get(compiler::GetPhaseManager()->CurrentPhaseId()); + if (UNLIKELY(node == nullptr)) { + // the callee assumes the nullptr might be returned, but + // the caller asserts it is not possible, so the explicit check is inserted + ES2PANDA_UNREACHABLE(); } - - ES2PANDA_ASSERT(node != nullptr); return node; } diff --git a/ets2panda/ir/astNode.h b/ets2panda/ir/astNode.h index 1fd37c07dd7059a0a6db370d646c4e540deade4e..86fa2af4c8d73988790f569dce2645d06c17ec67 100644 --- a/ets2panda/ir/astNode.h +++ b/ets2panda/ir/astNode.h @@ -535,22 +535,118 @@ public: virtual void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) = 0; virtual void Iterate(const NodeTraverser &cb) const = 0; - void TransformChildrenRecursively(const NodeTransformer &cb, std::string_view transformationName); - void TransformChildrenRecursively(const NodeTransformer &pre, const NodeTraverser &post, - std::string_view transformationName); - void TransformChildrenRecursively(const NodeTraverser &pre, const NodeTransformer &post, - std::string_view transformationName); - // CC-OFFNXT(C_RULE_ID_FUNCTION_HEADER, G.CMT.04) false positive - // Keep these for perf reasons: - void TransformChildrenRecursivelyPreorder(const NodeTransformer &cb, std::string_view transformationName); - void TransformChildrenRecursivelyPostorder(const NodeTransformer &cb, std::string_view transformationName); - - void IterateRecursively(const NodeTraverser &cb) const; - void IterateRecursivelyPreorder(const NodeTraverser &cb) const; - void IterateRecursivelyPostorder(const NodeTraverser &cb) const; - - bool IsAnyChild(const NodePredicate &cb) const; - AstNode *FindChild(const NodePredicate &cb) const; + template + void TransformChildrenRecursively(const F &cb, std::string_view transformationName) + { + TransformChildrenRecursivelyPostorder(cb, transformationName); + } + + // Preserved for the API bindings + void TransformChildrenRecursively(const NodeTransformer &cb, std::string_view transformationName) + { + return TransformChildrenRecursively(cb, transformationName); + } + + template + void TransformChildrenRecursivelyPreorder(const F &cb, std::string_view transformationName) + { + std::function hcb = [&](AstNode *child) { + AstNode *res = cb(child); + res->TransformChildren(hcb, transformationName); + return res; + }; + TransformChildren(hcb, transformationName); + } + + template + void TransformChildrenRecursivelyPostorder(const F &cb, std::string_view transformationName) + { + std::function hcb = [&](AstNode *child) { + child->TransformChildren(hcb, transformationName); + return cb(child); + }; + TransformChildren(hcb, transformationName); + } + + template + void PreTransformChildrenRecursively(const F1 &pre, const F2 &post, std::string_view transformationName) + { + std::function hcb = [&](AstNode *child) { + AstNode *upd = pre(child); + upd->TransformChildren(hcb, transformationName); + post(upd); + return upd; + }; + TransformChildren(hcb, transformationName); + } + + template + void PostTransformChildrenRecursively(const NodeTraverser &pre, const NodeTransformer &post, + std::string_view transformationName) + { + std::function hcb = [&](AstNode *child) { + pre(child); + child->TransformChildren(hcb, transformationName); + return post(child); + }; + TransformChildren(hcb, transformationName); + } + + template + void IterateRecursively(const F &cb) const + { + IterateRecursivelyPreorder(cb); + } + + template + void IterateRecursivelyPreorder(const F &cb) const + { + std::function hcb = [&](AstNode *child) { + cb(child); + child->Iterate(hcb); + }; + Iterate(hcb); + } + + template + void IterateRecursivelyPostorder(const F &cb) const + { + std::function hcb = [&](AstNode *child) { + child->Iterate(hcb); + cb(child); + }; + Iterate(hcb); + } + + template + AstNode *FindChild(const F &cb) const + { + AstNode *found = nullptr; + std::function hcb = [&](AstNode *child) { + if (found != nullptr) { + return; + } + if (cb(child)) { + found = child; + return; + } + child->Iterate(hcb); + }; + Iterate(hcb); + return found; + } + + template + bool IsAnyChild(const F &cb) const + { + return FindChild(cb) != nullptr; + } + + // Preserved for the API bindings + bool IsAnyChild(const NodePredicate &cb) const + { + return IsAnyChild(cb); + } std::string DumpJSON() const; std::string DumpEtsSrc() const; @@ -585,7 +681,14 @@ public: bool IsValidInCurrentPhase() const; - AstNode *GetHistoryNode() const; + AstNode *GetHistoryNode() const + { + if (UNLIKELY(history_ != nullptr)) { + return GetFromExistingHistory(); + } + return const_cast(this); + } + AstNode *GetOrCreateHistoryNode() const; protected: @@ -605,6 +708,8 @@ protected: void InitHistory(); bool HistoryInitialized() const; + AstNode *GetFromExistingHistory() const; + template T *GetHistoryNodeAs() const { diff --git a/ets2panda/ir/ets/etsParameterExpression.cpp b/ets2panda/ir/ets/etsParameterExpression.cpp index 672d060e2a08ec2ab822eb7c746b074166dabb50..300573755bbaca5882dd11d55b2a13e4d9249b52 100644 --- a/ets2panda/ir/ets/etsParameterExpression.cpp +++ b/ets2panda/ir/ets/etsParameterExpression.cpp @@ -280,6 +280,7 @@ ETSParameterExpression *ETSParameterExpression::Clone(ArenaAllocator *const allo ? allocator->New(identOrSpread, initializer, allocator) : allocator->New(identOrSpread, IsOptional(), allocator); ES2PANDA_ASSERT(identOrSpread != nullptr); + // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage) identOrSpread->SetParent(clone); if (initializer != nullptr) { diff --git a/ets2panda/test/unit/cfg/CMakeLists.txt b/ets2panda/test/unit/cfg/CMakeLists.txt index 6fc961f9235ef610a50af31b15fef01e0bd6bbf8..1732954d84f813afd8de43118936a3b448fd4f8f 100644 --- a/ets2panda/test/unit/cfg/CMakeLists.txt +++ b/ets2panda/test/unit/cfg/CMakeLists.txt @@ -15,12 +15,13 @@ if(NOT PANDA_WITH_ETS) return() endif() -ets2panda_add_gtest(cfg_tests - CPP_SOURCES cfg_test_do_while.cpp - cfg_test_for.cpp - cfg_test_for_of.cpp - cfg_test_if.cpp - cfg_test_switch.cpp -# cfg_test_try_catch.cpp - cfg_test_while.cpp -) +# 26593 - code should be moved out of the compilation pipeline +# ets2panda_add_gtest(cfg_tests +# CPP_SOURCES cfg_test_do_while.cpp +# cfg_test_for.cpp +# cfg_test_for_of.cpp +# cfg_test_if.cpp +# cfg_test_switch.cpp +# # cfg_test_try_catch.cpp +# cfg_test_while.cpp +# ) 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 1b4c7be1d7115e28a79a197d3f1a15554b92e3df..97046535e46c031796ca41d2ab5618da4403953d 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 @@ -325,26 +325,6 @@ TEST_F(PluginConversionRuleUnitTest, NodeTransformerInputParameter) EXPECT_TRUE(HasMatched(targetAPIWithNoSpace)); } -// apiName: AstNodeFindChildConst -TEST_F(PluginConversionRuleUnitTest, NodePredicateInputParameter) -{ - std::string targetCAPI {R"( - extern "C" es2panda_AstNode *AstNodeFindChildConst([[maybe_unused]] es2panda_Context *context, - es2panda_AstNode *classInstance, [[maybe_unused]] NodePredicate cb/*return_args:*/) - { - std::function cbE2p = [cb](ir::AstNode *traverserLambdaNode) - {return cb(reinterpret_cast(traverserLambdaNode));}; - auto apiRes = reinterpret_cast< es2panda_AstNode *> - ((reinterpret_cast(classInstance))->FindChild(cbE2p)); - return apiRes; - } - -)"}; - - std::string targetAPIWithNoSpace = RemoveWhitespace(targetCAPI); - EXPECT_TRUE(HasMatched(targetAPIWithNoSpace)); -} - // apiName: ETSObjectTypeUpdateTypeProperties TEST_F(PluginConversionRuleUnitTest, PropertyProcessorInputParameter) {