diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 81fed860b6cb35c565669e0d6cccd15630130206..875e258c659a183ef263566aa73979f03f270589 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -763,9 +763,11 @@ public: void GenerateGetterSetterPropertyAndMethod(ir::ClassProperty *originalProp, ETSObjectType *classType); void SetupGetterSetterFlags(ir::ClassProperty *originalProp, ETSObjectType *classType, ir::MethodDefinition *getter, ir::MethodDefinition *setter, const bool inExternal); - Type *GetImportSpecifierObjectType(ir::ETSImportDeclaration *importDecl, ir::Identifier *ident); + Type *GetImportSpecifierObjectType(ir::ETSImportDeclaration *importDecl, ir::Identifier *ident, + std::unordered_set *moduleStackCache = nullptr); void ImportNamespaceObjectTypeAddReExportType(ir::ETSImportDeclaration *importDecl, - checker::ETSObjectType *lastObjectType, ir::Identifier *ident); + checker::ETSObjectType *lastObjectType, ir::Identifier *ident, + std::unordered_set *moduleStackCache = nullptr); bool CheckValidEqualReferenceType(checker::Type *const leftType, checker::Type *const rightType); bool CheckVoidAnnotation(const ir::ETSPrimitiveType *typeAnnotation); void ETSObjectTypeDeclNode(ETSChecker *checker, ETSObjectType *const objectType); diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 7af150985bfcef9a75db2c5e25a3b34b52378ac8..dd5d023d62c7fecbc4b73fddc9445fff3850ba46 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -3229,13 +3229,14 @@ bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, cons } void ETSChecker::ImportNamespaceObjectTypeAddReExportType(ir::ETSImportDeclaration *importDecl, - checker::ETSObjectType *lastObjectType, ir::Identifier *ident) + checker::ETSObjectType *lastObjectType, ir::Identifier *ident, + std::unordered_set *moduleStackCache) { for (auto item : VarBinder()->AsETSBinder()->ReExportImports()) { if (importDecl->ResolvedSource() != item->GetProgramPath().Mutf8()) { continue; } - auto *reExportType = GetImportSpecifierObjectType(item->GetETSImportDeclarations(), ident); + auto *reExportType = GetImportSpecifierObjectType(item->GetETSImportDeclarations(), ident, moduleStackCache); if (reExportType->IsTypeError()) { continue; } @@ -3250,7 +3251,8 @@ void ETSChecker::ImportNamespaceObjectTypeAddReExportType(ir::ETSImportDeclarati } } -Type *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importDecl, ir::Identifier *ident) +Type *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importDecl, ir::Identifier *ident, + std::unordered_set *moduleStackCache) { auto importPath = importDecl->IsPureDynamic() ? importDecl->DeclPath() : importDecl->ResolvedSource(); parser::Program *program = @@ -3258,6 +3260,16 @@ Type *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importD if (program == nullptr) { return GlobalTypeError(); } + std::unordered_set localCache; + if (moduleStackCache == nullptr) { + moduleStackCache = &localCache; + } + RecursionPreserver guard(*moduleStackCache, program); + + if (*guard) { + LogError(diagnostic::CYCLIC_EXPORT, ident->Start()); + return GlobalTypeError(); + } auto const moduleName = program->ModuleName(); auto const internalName = @@ -3276,7 +3288,7 @@ Type *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importD ES2PANDA_ASSERT(rootVar != nullptr); rootVar->SetTsType(moduleObjectType); - ImportNamespaceObjectTypeAddReExportType(importDecl, moduleObjectType, ident); + ImportNamespaceObjectTypeAddReExportType(importDecl, moduleObjectType, ident, moduleStackCache); SetPropertiesForModuleObject(moduleObjectType, importPath, importDecl->Specifiers()[0]->IsImportNamespaceSpecifier() ? nullptr : importDecl); SetrModuleObjectTsType(ident, moduleObjectType); diff --git a/ets2panda/test/ast/parser/ets/re_export/cyclic_export_file1.ets b/ets2panda/test/ast/parser/ets/re_export/cyclic_export_file1.ets new file mode 100644 index 0000000000000000000000000000000000000000..87aee176d052811f418601ad35db7685f92d348b --- /dev/null +++ b/ets2panda/test/ast/parser/ets/re_export/cyclic_export_file1.ets @@ -0,0 +1,17 @@ +/* + * 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 * from './cyclic_export_file2.ets'; +export let fromA = 111; \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/re_export/cyclic_export_file2.ets b/ets2panda/test/ast/parser/ets/re_export/cyclic_export_file2.ets new file mode 100644 index 0000000000000000000000000000000000000000..2bdfd9939b82f72af21889f1c9e27fad6f86a642 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/re_export/cyclic_export_file2.ets @@ -0,0 +1,17 @@ +/* + * 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 * from './cyclic_export_file1.ets'; +export let fromB = 111; \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/re_export/cyclic_export_test.ets b/ets2panda/test/ast/parser/ets/re_export/cyclic_export_test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f70ac972f820ee57145251f35a23f5f40de36a04 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/re_export/cyclic_export_test.ets @@ -0,0 +1,20 @@ +/* + * 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 * as a from './cyclic_export_file1.ets' +import * as b from './cyclic_export_file2.ets' + +/* @@? 16:13 Error TypeError: Cyclic export detected re-exports */ +/* @@? 17:13 Error TypeError: Cyclic export detected re-exports */ \ No newline at end of file diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index 265d476e7abbe720324265509134e7ebbf535d40..bb8e6f39eca5bff4e51557d8cd44aa3786da5065 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -333,6 +333,10 @@ semantic: id: 380 message: "Class's super type is itself" +- name: CYCLIC_EXPORT + id: 67633 + message: "Cyclic export detected re-exports" + - name: CYCLIC_INHERITANCE id: 310 message: "Cyclic inheritance involving {}."