diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 06acf7c826f90455c0fceeb4ebce21401d991d2f..d5701e55ec847aa5dc45400a6e07b8a5e54c21d7 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -2004,7 +2004,7 @@ checker::Type *ETSAnalyzer::Check(ir::MemberExpression *expr) const expr->Property()->AsIdentifier()->Name(), checker); reExportType.first != nullptr) { baseType = reExportType.first; - expr->object_->AsIdentifier()->SetTsType(baseType); + expr->object_->SetTsType(baseType); expr->property_->AsIdentifier()->SetName(reExportType.second); } } @@ -2976,7 +2976,7 @@ checker::Type *ETSAnalyzer::Check(ir::ImportNamespaceSpecifier *st) const } if (importDecl->IsPureDynamic()) { - auto *type = checker->GlobalBuiltinDynamicType(importDecl->Language()); + auto *type = checker->GetImportSpecifierObjectType(importDecl, st->Local()->AsIdentifier())->AsETSObjectType(); checker->SetrModuleObjectTsType(st->Local(), type); return type; } diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index bf9c6c2c56219190165b6ee9e0a46968961690db..85c9f9556f46f52b93eb55a3b6970f11d1919b92 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1759,6 +1759,11 @@ void ETSChecker::BindingsModuleObjectAddProperty(checker::ETSObjectType *moduleO } } +template void ETSChecker::BindingsModuleObjectAddProperty( + ETSObjectType *, ir::ETSImportDeclaration *, const varbinder::Scope::VariableMap &, const util::StringView &); +template void ETSChecker::BindingsModuleObjectAddProperty( + ETSObjectType *, ir::ETSImportDeclaration *, const varbinder::Scope::VariableMap &, const util::StringView &); + util::StringView ETSChecker::FindPropNameForNamespaceImport(const util::StringView &originalName, const util::StringView &importPath) { @@ -1799,37 +1804,21 @@ void ETSChecker::SetPropertiesForModuleObject(checker::ETSObjectType *moduleObjT program->SetASTChecked(); program->Ast()->Check(this); } - if (program->IsDeclForDynamicStaticInterop()) { - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->StaticFieldScope()->Bindings(), importPath); - - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->StaticMethodScope()->Bindings(), importPath); - - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->StaticDeclScope()->Bindings(), importPath); - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->InstanceDeclScope()->Bindings(), importPath); + BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->StaticFieldScope()->Bindings(), importPath); - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->TypeAliasScope()->Bindings(), importPath); - } else { - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->StaticFieldScope()->Bindings(), importPath); - - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->StaticMethodScope()->Bindings(), importPath); + BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->StaticMethodScope()->Bindings(), importPath); - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->StaticDeclScope()->Bindings(), importPath); + BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->StaticDeclScope()->Bindings(), importPath); - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->InstanceDeclScope()->Bindings(), importPath); + BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->InstanceDeclScope()->Bindings(), importPath); - BindingsModuleObjectAddProperty( - moduleObjType, importDecl, program->GlobalClassScope()->TypeAliasScope()->Bindings(), importPath); - } + BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->TypeAliasScope()->Bindings(), importPath); } void ETSChecker::SetrModuleObjectTsType(ir::Identifier *local, checker::ETSObjectType *moduleObjType) @@ -3159,7 +3148,7 @@ void ETSChecker::ImportNamespaceObjectTypeAddReExportType(ir::ETSImportDeclarati Type *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importDecl, ir::Identifier *ident) { - auto importPath = importDecl->ResolvedSource(); + auto importPath = importDecl->IsPureDynamic() ? importDecl->DeclPath() : importDecl->ResolvedSource(); parser::Program *program = SelectEntryOrExternalProgram(static_cast(VarBinder()), importPath); if (program == nullptr) { diff --git a/ets2panda/compiler/lowering/ets/dynamicImport.cpp b/ets2panda/compiler/lowering/ets/dynamicImport.cpp index 7701480b15a4b430eb6ec9501755101e38b978b8..819e81ad1e1b8dfab60ddf433377d68dc6da88ed 100644 --- a/ets2panda/compiler/lowering/ets/dynamicImport.cpp +++ b/ets2panda/compiler/lowering/ets/dynamicImport.cpp @@ -28,6 +28,8 @@ using AstNodePtr = ir::AstNode *; static constexpr std::string_view LAZY_IMPORT_OBJECT_SUFFIX = "%%lazyImportObject-"; static constexpr std::string_view FIELD_NAME = "value"; +static checker::Type *CreateModuleObjectType(public_lib::Context *ctx, ir::ETSImportDeclaration *importDecl); + ir::ClassDeclaration *GetOrCreateLazyImportObjectClass(ark::ArenaAllocator *allocator, ir::ETSImportDeclaration *importDecl, parser::Program *program) { @@ -99,13 +101,68 @@ static void AddImportInitializationStatement(public_lib::Context *ctx, ir::ETSIm statements->push_back(util::NodeAllocator::ForceSetParent(allocator, initializer)); } -checker::Type *CreateModuleObjectType(public_lib::Context *ctx, ir::ETSImportDeclaration *importDecl) +static void ImportNamespaceObjectTypeAddReExportType(public_lib::Context *ctx, varbinder::ETSBinder *varbinder, + ir::ETSImportDeclaration *importDecl, + checker::ETSObjectType *lastObjectType) +{ + for (auto item : varbinder->AsETSBinder()->ReExportImports()) { + if (importDecl->DeclPath() != item->GetProgramPath().Mutf8()) { + continue; + } + auto *reExportType = CreateModuleObjectType(ctx, item->GetETSImportDeclarations()); + if (reExportType->IsTypeError()) { + continue; + } + ES2PANDA_ASSERT(lastObjectType != nullptr); + lastObjectType->AddReExports(reExportType->AsETSObjectType()); + for (auto node : importDecl->Specifiers()) { + if (node->IsImportSpecifier()) { + auto specifier = node->AsImportSpecifier(); + lastObjectType->AddReExportAlias(specifier->Imported()->Name(), specifier->Local()->Name()); + } + } + } +} + +static void SetPropertiesForModuleObject(public_lib::Context *ctx, checker::ETSObjectType *moduleObjType, + const util::StringView &importPath, ir::ETSImportDeclaration *importDecl) +{ + auto checker = ctx->GetChecker()->AsETSChecker(); + auto varbinder = static_cast(checker->VarBinder()->AsETSBinder()); + parser::Program *program = + checker->SelectEntryOrExternalProgram(static_cast(varbinder), importPath); + // Check imported properties before assigning them to module object + ES2PANDA_ASSERT(program != nullptr); + if (!program->IsASTChecked()) { + // NOTE: helps to avoid endless loop in case of recursive imports that uses all bindings + program->SetASTChecked(); + program->Ast()->Check(checker); + } + + checker->BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->StaticFieldScope()->Bindings(), importPath); + + checker->BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->StaticMethodScope()->Bindings(), importPath); + + checker->BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->StaticDeclScope()->Bindings(), importPath); + + checker->BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->InstanceDeclScope()->Bindings(), importPath); + + checker->BindingsModuleObjectAddProperty( + moduleObjType, importDecl, program->GlobalClassScope()->TypeAliasScope()->Bindings(), importPath); +} + +static checker::Type *CreateModuleObjectType(public_lib::Context *ctx, ir::ETSImportDeclaration *importDecl) { auto checker = ctx->GetChecker()->AsETSChecker(); auto varbinder = static_cast(checker->VarBinder()->AsETSBinder()); auto allocator = checker->ProgramAllocator(); - const auto importPath = importDecl->DeclPath(); + const auto importPath = importDecl->DeclPath() == util::ImportPathManager::DUMMY_PATH ? importDecl->ResolvedSource() + : importDecl->DeclPath(); auto program = checker->SelectEntryOrExternalProgram(varbinder, importPath); if (program == nullptr) { return checker->GlobalTypeError(); @@ -124,11 +181,29 @@ checker::Type *CreateModuleObjectType(public_lib::Context *ctx, ir::ETSImportDec auto *rootDecl = allocator->New(moduleName); auto *rootVar = allocator->New(rootDecl, varbinder::VariableFlags::NONE); rootVar->SetTsType(moduleObjectType); - checker->SetPropertiesForModuleObject(moduleObjectType, importPath, nullptr); + ImportNamespaceObjectTypeAddReExportType(ctx, program->VarBinder()->AsETSBinder(), importDecl, moduleObjectType); + SetPropertiesForModuleObject(ctx, moduleObjectType, importPath, nullptr); + moduleObjectType->AddObjectFlag(checker::ETSObjectFlags::LAZY_IMPORT_OBJECT); return moduleObjectType; } +static void FillVarMapForImportSpecifiers(const ArenaVector &specifiers, ir::ClassDefinition *classDef, + ArenaUnorderedMap &varMap) +{ + for (auto specifier : specifiers) { + if (specifier->IsImportSpecifier()) { + auto *var = specifier->AsImportSpecifier()->Imported()->Variable(); + var->AddFlag(varbinder::VariableFlags::DYNAMIC); + varMap.insert({var, classDef}); + } else if (specifier->IsImportNamespaceSpecifier()) { + auto *var = specifier->AsImportNamespaceSpecifier()->Local()->Variable(); + var->AddFlag(varbinder::VariableFlags::DYNAMIC); + varMap.insert({var, classDef}); + } + } +} + static void BuildLazyImportObject(public_lib::Context *ctx, ir::ETSImportDeclaration *importDecl, parser::Program *program, ArenaUnorderedMap &moduleMap, @@ -144,11 +219,7 @@ static void BuildLazyImportObject(public_lib::Context *ctx, ir::ETSImportDeclara } auto *classDecl = GetOrCreateLazyImportObjectClass(allocator, importDecl, program); - for (auto specifier : importDecl->Specifiers()) { - auto var = specifier->AsImportSpecifier()->Imported()->Variable(); - var->AddFlag(varbinder::VariableFlags::DYNAMIC); - varMap.insert({var, classDecl->Definition()}); - } + FillVarMapForImportSpecifiers(importDecl->Specifiers(), classDecl->Definition(), varMap); const auto className = classDecl->Definition()->Ident()->Name(); auto found = moduleMap.find(className); @@ -160,7 +231,6 @@ static void BuildLazyImportObject(public_lib::Context *ctx, ir::ETSImportDeclara auto *objType = CreateModuleObjectType(ctx, importDecl)->AsETSObjectType(); moduleMap.insert({className, objType}); - objType->AddObjectFlag(checker::ETSObjectFlags::LAZY_IMPORT_OBJECT); auto moduleType = checker->CreateGradualType(objType, Language::Id::JS); auto parser = ctx->parser->AsETSParser(); @@ -182,10 +252,6 @@ static void BuildLazyImportObject(public_lib::Context *ctx, ir::ETSImportDeclara classDecl->Definition()->EmplaceBody(initializer); initializer->SetParent(classDecl->Definition()); - for (auto specifier : importDecl->Specifiers()) { - varMap.insert({specifier->AsImportSpecifier()->Imported()->Variable(), classDecl->Definition()}); - } - program->GlobalClass()->EmplaceBody(classDecl); classDecl->SetParent(program->GlobalClass()); @@ -195,15 +261,32 @@ static void BuildLazyImportObject(public_lib::Context *ctx, ir::ETSImportDeclara classDecl->Check(checker); } +static ir::MemberExpression *CreateTripleMemberExpr(ArenaAllocator *allocator, const util::StringView &left, + const util::StringView &middle, const util::StringView &right) +{ + auto *leftId = allocator->New(left, allocator); + auto *middleId = allocator->New(middle, allocator); + auto *expr = util::NodeAllocator::ForceSetParent( + allocator, leftId, middleId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); + auto *rightId = allocator->New(right, allocator); + return util::NodeAllocator::ForceSetParent( + allocator, expr, rightId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); +} + static AstNodePtr TransformIdentifier(ir::Identifier *ident, public_lib::Context *ctx, const ArenaUnorderedMap &varMap) { auto checker = ctx->GetChecker()->AsETSChecker(); auto varBinder = checker->VarBinder()->AsETSBinder(); auto allocator = checker->ProgramAllocator(); + if (ident->Variable()->Declaration() != nullptr && ident->Variable()->Declaration()->Node() != nullptr && + ident->Variable()->Declaration()->Node()->IsImportNamespaceSpecifier()) { + return ident; + } const auto parent = ident->Parent(); - if (parent->IsImportSpecifier() || parent->IsScriptFunction() || parent->IsMethodDefinition()) { + if (parent->IsImportSpecifier() || parent->IsImportNamespaceSpecifier() || parent->IsScriptFunction() || + parent->IsMethodDefinition()) { return ident; } @@ -212,26 +295,80 @@ static AstNodePtr TransformIdentifier(ir::Identifier *ident, public_lib::Context return ident; } - auto newIdent = allocator->New(ident->Variable()->Name(), allocator); - auto *leftId = allocator->New(varIt->second->Ident()->Name(), allocator); - auto *rightId = allocator->New(FIELD_NAME, allocator); - - auto *expr = util::NodeAllocator::ForceSetParent( - allocator, leftId, rightId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); - - auto *memberExpr = util::NodeAllocator::ForceSetParent( - allocator, expr, newIdent, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); - + auto *memberExpr = + CreateTripleMemberExpr(allocator, varIt->second->Ident()->Name(), FIELD_NAME, ident->Variable()->Name()); memberExpr->SetParent(parent); // Ensure that it will not be incorrectly converted to ArrowType. if (parent->IsCallExpression() && parent->AsCallExpression()->Callee() == ident) { parent->AsCallExpression()->SetCallee(memberExpr); } CheckLoweredNode(varBinder, checker, memberExpr); + return memberExpr; +} + +AstNodePtr TransformTsQualifiedName(ir::TSQualifiedName *qualifiedName, public_lib::Context *ctx, + const ArenaUnorderedMap &varMap) +{ + auto checker = ctx->GetChecker()->AsETSChecker(); + auto varBinder = checker->VarBinder()->AsETSBinder(); + auto allocator = checker->ProgramAllocator(); + if (!qualifiedName->Left()->IsIdentifier()) { + return qualifiedName; + } + auto *moduleId = qualifiedName->Left()->AsIdentifier(); + if (moduleId->Variable() != nullptr && moduleId->Variable()->Declaration() != nullptr && + !moduleId->Variable()->Declaration()->Node()->IsImportNamespaceSpecifier()) { + return qualifiedName; + } + auto varIt = varMap.find(moduleId->Variable()); + if (varIt == varMap.end()) { + return qualifiedName; + } + const auto parent = qualifiedName->Parent(); + auto *newIdent = allocator->New(qualifiedName->Right()->AsIdentifier()->Name(), allocator); + auto *memberExpr = CreateTripleMemberExpr(allocator, varIt->second->Ident()->Name(), FIELD_NAME, newIdent->Name()); + memberExpr->SetParent(parent); + // Ensure that it will not be incorrectly converted to ArrowType. + if (parent->IsCallExpression() && parent->AsCallExpression()->Callee() == qualifiedName) { + parent->AsCallExpression()->SetCallee(memberExpr); + } + CheckLoweredNode(varBinder, checker, memberExpr); return memberExpr; } +AstNodePtr TransformMemberExpression(ir::MemberExpression *memberExpr, public_lib::Context *ctx, + const ArenaUnorderedMap &varMap) +{ + auto checker = ctx->GetChecker()->AsETSChecker(); + auto varBinder = checker->VarBinder()->AsETSBinder(); + auto allocator = checker->ProgramAllocator(); + if (!memberExpr->Object()->IsIdentifier() || !memberExpr->Property()->IsIdentifier()) { + return memberExpr; + } + auto *moduleId = memberExpr->Object()->AsIdentifier(); + if (moduleId->Variable()->Declaration() != nullptr && + !moduleId->Variable()->Declaration()->Node()->IsImportNamespaceSpecifier()) { + return memberExpr; + } + auto varIt = varMap.find(moduleId->Variable()); + if (varIt == varMap.end()) { + return memberExpr; + } + const auto parent = memberExpr->Parent(); + auto *newIdent = allocator->New(memberExpr->Property()->AsIdentifier()->Name(), allocator); + auto *res = CreateTripleMemberExpr(allocator, varIt->second->Ident()->Name(), FIELD_NAME, newIdent->Name()); + res->SetParent(parent); + + // Ensure that it will not be incorrectly converted to ArrowType. + if (parent->IsCallExpression() && parent->AsCallExpression()->Callee() == memberExpr) { + parent->AsCallExpression()->SetCallee(res); + } + CheckLoweredNode(varBinder, checker, res); + + return res; +} + bool DynamicImport::PerformForModule(public_lib::Context *ctx, parser::Program *program) { auto allocator = ctx->GetChecker()->ProgramAllocator(); @@ -248,6 +385,12 @@ bool DynamicImport::PerformForModule(public_lib::Context *ctx, parser::Program * if (node->IsIdentifier() && node->AsIdentifier()->Variable() != nullptr) { return TransformIdentifier(node->AsIdentifier(), ctx, varMap); } + if (node->IsTSQualifiedName()) { + return TransformTsQualifiedName(node->AsTSQualifiedName(), ctx, varMap); + } + if (node->IsMemberExpression() && node->AsMemberExpression()->PropVar() != nullptr) { + return TransformMemberExpression(node->AsMemberExpression(), ctx, varMap); + } return node; }, Name()); diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 120bb9dc25c0147c872db890418a45b3e3794a79..7e9deaf04ab8a744214980b18e323ef38e217ecf 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -961,12 +961,6 @@ void InitScopesPhaseETS::VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecif void InitScopesPhaseETS::VisitImportSpecifier(ir::ImportSpecifier *importSpec) { - if (importSpec->Parent()->IsETSImportDeclaration() && - importSpec->Parent()->AsETSImportDeclaration()->IsPureDynamic()) { - auto [decl, var] = VarBinder()->NewVarDecl(importSpec->Local()->Start(), - importSpec->Local()->Name(), importSpec); - var->AddFlag(varbinder::VariableFlags::INITIALIZED); - } Iterate(importSpec); } diff --git a/ets2panda/ir/ets/etsImportDeclaration.h b/ets2panda/ir/ets/etsImportDeclaration.h index dc5d6d8094a6ac8e100e7117dcd0fa7e94be6512..598b06f9d8cfa4b630d580b32e7cc5c83361b5ca 100644 --- a/ets2panda/ir/ets/etsImportDeclaration.h +++ b/ets2panda/ir/ets/etsImportDeclaration.h @@ -74,7 +74,7 @@ public: bool IsPureDynamic() const { - return IsValid() && DeclPath().empty() && Language().IsDynamic(); + return IsValid() && !DeclPath().empty() && Language().IsDynamic(); } void SetAssemblerName(util::StringView assemblerName)