diff --git a/ets2panda/ast_verifier/invariants/importExportAccessValid.cpp b/ets2panda/ast_verifier/invariants/importExportAccessValid.cpp index bf7351956a7b3bae812a360c9c28f6a777633fae..594d130b5b2cb2d9baa5ce05b9c5058ef90d4411 100644 --- a/ets2panda/ast_verifier/invariants/importExportAccessValid.cpp +++ b/ets2panda/ast_verifier/invariants/importExportAccessValid.cpp @@ -70,7 +70,7 @@ bool ImportExportAccessValid::ValidateExport(const varbinder::Variable *var) if (node == nullptr) { return false; } - return node->IsExported(); + return node->IsExported() || node->HasExportAlias(); } bool ImportExportAccessValid::InvariantImportExportMethod(const std::unordered_set &importedVariables, diff --git a/ets2panda/ast_verifier/invariants/variableNameIdentifierNameSame.cpp b/ets2panda/ast_verifier/invariants/variableNameIdentifierNameSame.cpp index f3d85ee0a0b15c40b6d821c4930a88875a1c6fad..3b82e3e138bba29c4e11b0e3ebd3587a7b810a76 100644 --- a/ets2panda/ast_verifier/invariants/variableNameIdentifierNameSame.cpp +++ b/ets2panda/ast_verifier/invariants/variableNameIdentifierNameSame.cpp @@ -32,8 +32,8 @@ namespace ark::es2panda::compiler::ast_verifier { } const auto variableNode = variable->Declaration()->Node(); // NOTE(psaykerone): skip because, this exceptions need to be fixed in checker and lowering - if (variableNode->IsExported() || variableNode->IsDefaultExported() || id->Name().Utf8().find("field") == 0 || - variable->Name().Utf8().find("field") == 0) { + if (variableNode->IsExported() || variableNode->IsDefaultExported() || variableNode->HasExportAlias() || + id->Name().Utf8().find("field") == 0 || variable->Name().Utf8().find("field") == 0) { return {CheckDecision::CORRECT, CheckAction::CONTINUE}; } if (id->Name() == variable->Name()) { diff --git a/ets2panda/checker/ets/etsWarningAnalyzer.cpp b/ets2panda/checker/ets/etsWarningAnalyzer.cpp index 8320d38cbc81340d85bce06797d619654ce7a19b..4376b07ba802f57f2f1a131f291d017ea6cc907f 100644 --- a/ets2panda/checker/ets/etsWarningAnalyzer.cpp +++ b/ets2panda/checker/ets/etsWarningAnalyzer.cpp @@ -44,7 +44,7 @@ void ETSWarningAnalyzer::AnalyzeClassDefForFinalModifier(const ir::ClassDefiniti ES2PANDA_ASSERT(classDef != nullptr); if (program_ == nullptr || classDef->IsFinal() || classDef->IsAbstract() || classDef->IsStatic() || - classDef->IsGlobal() || classDef->IsExported()) { + classDef->IsGlobal() || classDef->IsExported() || classDef->HasExportAlias()) { return; } diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index d53d72e3226f4789fbe844f604610790d6ef0b48..d0743fac22e03f52a6647d0f168be5c75afe4e2d 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1695,7 +1695,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()->IsExported()) && found) { + if ((var->AsLocalVariable()->Declaration()->Node()->IsExported() || + var->AsLocalVariable()->Declaration()->Node()->HasExportAlias()) && + found) { if (!aliasedName.Empty()) { moduleObjType->AddReExportAlias(var->Declaration()->Name(), aliasedName); } diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp index ee9a0572a2547b7bc51960124f43e7b3cf48ed73..422dc6de01418dfb5f267a26a2e7132cea401aac 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp @@ -62,7 +62,7 @@ void GlobalDeclTransformer::VisitFunctionDeclaration(ir::FunctionDeclaration *fu method->SetRange(funcDecl->Range()); method->Function()->SetAnnotations(std::move(funcDecl->Annotations())); - if (funcDecl->Function()->IsExported() && funcDecl->Function()->HasExportAlias()) { + if (funcDecl->Function()->HasExportAlias()) { method->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS); } @@ -96,8 +96,7 @@ void GlobalDeclTransformer::VisitVariableDeclaration(ir::VariableDeclaration *va field->SetAnnotations(std::move(propAnnotations)); } - if ((varDecl->IsExported() || declarator->IsExported()) && - (varDecl->HasExportAlias() || declarator->HasExportAlias())) { + if (varDecl->HasExportAlias() || declarator->HasExportAlias()) { field->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 adbb17ad0f63cf0a1fcbcf63faf1d8c80188198b..9de0c504a0f36c96891f83653c9ad575f9a6509d 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp @@ -14,6 +14,7 @@ */ #include "compiler/lowering/ets/topLevelStmts/importExportDecls.h" +#include "generated/diagnostic.h" namespace ark::es2panda::compiler { @@ -69,37 +70,33 @@ GlobalClassHandler::ModuleDependencies ImportExportDecls::HandleGlobalStmts(Aren void ImportExportDecls::PopulateAliasMap(const ir::ExportNamedDeclaration *decl, const util::StringView &path) { for (auto spec : decl->Specifiers()) { - if (!varbinder_->AddSelectiveExportAlias(path, spec->Local()->Name(), spec->Exported()->Name(), decl)) { - parser_->LogError(diagnostic::DUPLICATE_EXPORT_NAME, {spec->Local()->Name().Mutf8()}, - spec->Exported()->Start()); + if (!varbinder_->AddSelectiveExportAlias(parser_, path, spec->Local()->Name(), spec->Exported()->Name(), + decl)) { + parser_->LogError(diagnostic::CANNOT_EXPORT_DIFFERENT_OBJECTS_WITH_SAME_NAME, + {spec->Local()->Name().Mutf8()}, spec->Exported()->Start()); lastExportErrorPos_ = lexer::SourcePosition(); } } } -void ImportExportDecls::AddExportFlags(ir::AstNode *node, util::StringView originalFieldName, - lexer::SourcePosition startLoc, bool exportedWithAlias) +void ImportExportDecls::AddExportFlags(ir::AstNode *node, util::StringView originalFieldName, bool exportedWithAlias) { - if ((node->Modifiers() & ir::ModifierFlags::EXPORTED) != 0) { - // Note (oeotvos) Needs to be discussed, whether we would like to allow exporting the same program - // element using its original name and also an alias, like: export {test_func, test_func as foo}. - parser_->LogError(diagnostic::ALREADY_EXPORTED, {originalFieldName.Mutf8()}, startLoc); + if (exportedWithAlias) { + node->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS); + return; } if (originalFieldName == exportDefaultName_) { node->AddModifier(ir::ModifierFlags::DEFAULT_EXPORT); } else { node->AddModifier(ir::ModifierFlags::EXPORT); } - if (exportedWithAlias) { - node->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS); - } } void ImportExportDecls::PopulateAliasMap(const ir::TSTypeAliasDeclaration *decl, const util::StringView &path) { - if (!varbinder_->AddSelectiveExportAlias(path, decl->Id()->AsIdentifier()->Name(), + if (!varbinder_->AddSelectiveExportAlias(parser_, path, decl->Id()->AsIdentifier()->Name(), decl->Id()->AsIdentifier()->Name(), decl)) { - parser_->LogError(diagnostic::DUPLICATE_EXPORT_NAME, {decl->Id()->AsIdentifier()->Name().Mutf8()}, - lastExportErrorPos_); + parser_->LogError(diagnostic::CANNOT_EXPORT_DIFFERENT_OBJECTS_WITH_SAME_NAME, + {decl->Id()->AsIdentifier()->Name().Mutf8()}, lastExportErrorPos_); lastExportErrorPos_ = lexer::SourcePosition(); } } @@ -119,9 +116,9 @@ void ImportExportDecls::HandleSelectiveExportWithAlias(util::StringView original } if (variableDeclarator != nullptr) { - AddExportFlags(variableDeclarator, originalFieldName, startLoc, exportedWithAlias); + AddExportFlags(variableDeclarator, originalFieldName, exportedWithAlias); } else { - AddExportFlags(field, originalFieldName, startLoc, exportedWithAlias); + AddExportFlags(field, originalFieldName, exportedWithAlias); } } @@ -201,11 +198,7 @@ void ImportExportDecls::VisitExportNamedDeclaration(ir::ExportNamedDeclaration * } exportDefaultName_ = local->Name(); } - - if (!exportNameMap_.emplace(local->Name(), local->Start()).second) { - lastExportErrorPos_ = local->Start(); - parser_->LogError(diagnostic::DUPLICATE_EXPORT_NAME, {local->Name().Mutf8()}, lastExportErrorPos_); - } + exportNameMap_.emplace(local->Name(), local->Start()); } } diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.h b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.h index c1b50a29aa16f1a542ec49b051629a2cb51902dd..81351b38e3bca047b5b6ca3929e2d70f9b9cb9c9 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.h +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.h @@ -64,8 +64,7 @@ public: void HandleSimpleType(std::set &exportedStatements, ir::Statement *stmt, util::StringView name); void VerifySingleExportDefault(const ArenaVector &programs); - void AddExportFlags(ir::AstNode *node, util::StringView originalFieldName, lexer::SourcePosition startLoc, - bool exportedWithAlias); + void AddExportFlags(ir::AstNode *node, util::StringView originalFieldName, bool exportedWithAlias); void HandleSelectiveExportWithAlias(util::StringView originalFieldName, util::StringView exportName, lexer::SourcePosition startLoc); void PopulateAliasMap(const ir::ExportNamedDeclaration *decl, const util::StringView &path); diff --git a/ets2panda/ir/ets/etsModule.cpp b/ets2panda/ir/ets/etsModule.cpp index 3fea029e815d4d9281ec27a992d00be6be3fdede..e6cfc877a678472ab3faf5cb9804bb7c15b552b2 100644 --- a/ets2panda/ir/ets/etsModule.cpp +++ b/ets2panda/ir/ets/etsModule.cpp @@ -29,7 +29,7 @@ void ETSModule::Dump(ir::SrcDumper *dumper) const dumper->Add("export default "); } - if (IsDeclare()) { + if (IsDeclare() && !(parent_ != nullptr && parent_->IsDeclare())) { dumper->Add("declare "); } diff --git a/ets2panda/ir/statements/functionDeclaration.cpp b/ets2panda/ir/statements/functionDeclaration.cpp index 21fb0d5f85eea44a9eec9cc135d0589c74b4b153..ff6028046f4578670c6710f38b8de8696bcf4e76 100644 --- a/ets2panda/ir/statements/functionDeclaration.cpp +++ b/ets2panda/ir/statements/functionDeclaration.cpp @@ -74,7 +74,12 @@ void FunctionDeclaration::Dump(ir::SrcDumper *dumper) const if (func_->IsNative()) { dumper->Add("native "); } - if (func_->IsDeclare()) { + if (IsExported()) { + dumper->Add("export "); + } else if (IsDefaultExported()) { + dumper->Add("export default "); + } + if (func_->IsDeclare() && !(parent_ != nullptr && parent_->IsDeclare())) { dumper->Add("declare "); } if (func_->IsAsyncFunc()) { diff --git a/ets2panda/test/ast/compiler/ets/export_and_export_type_class.ets b/ets2panda/test/ast/compiler/ets/export_and_export_type_class.ets index 57d8b40dda03b0dd27436131530e014f8aed9172..ba28d7a7b82c333c15592100bf24415f65acfd2e 100644 --- a/ets2panda/test/ast/compiler/ets/export_and_export_type_class.ets +++ b/ets2panda/test/ast/compiler/ets/export_and_export_type_class.ets @@ -15,5 +15,3 @@ export class A {} export type {/* @@ label */A} - -/* @@@ label Error SyntaxError: Cannot export 'A', it was already exported. */ diff --git a/ets2panda/test/ast/compiler/ets/export_and_export_type_interface.ets b/ets2panda/test/ast/compiler/ets/export_and_export_type_interface.ets index 0b4bef4431094310a46587df4152ce66aec47e84..201b28a8dde1d91067b5c91d203a8a1ea6e5c548 100644 --- a/ets2panda/test/ast/compiler/ets/export_and_export_type_interface.ets +++ b/ets2panda/test/ast/compiler/ets/export_and_export_type_interface.ets @@ -15,5 +15,3 @@ export interface I {} export type {/* @@ label */I} - -/* @@@ label Error SyntaxError: Cannot export 'I', it was already exported. */ diff --git a/ets2panda/test/ast/compiler/ets/export_same_type_at_decl_and_selective_binding.ets b/ets2panda/test/ast/compiler/ets/export_same_type_at_decl_and_selective_binding.ets index e566df5aae04642896e431ed25cc40269097d0df..206cbcabbfdbe33e05b1b534c2dc0b1caa60e063 100644 --- a/ets2panda/test/ast/compiler/ets/export_same_type_at_decl_and_selective_binding.ets +++ b/ets2panda/test/ast/compiler/ets/export_same_type_at_decl_and_selective_binding.ets @@ -15,6 +15,3 @@ export type class A {} export type {/* @@ label */A} - - -/* @@@ label Error SyntaxError: Cannot export 'A', it was already exported. */ diff --git a/ets2panda/test/ast/compiler/ets/export_type_class_multiple_times.ets b/ets2panda/test/ast/compiler/ets/export_type_class_multiple_times.ets index 4609849c5dd6816c3d4ec31b3166efbc84023691..4a2147118c7545d83f849190cc7f84a2319c0ff6 100644 --- a/ets2panda/test/ast/compiler/ets/export_type_class_multiple_times.ets +++ b/ets2panda/test/ast/compiler/ets/export_type_class_multiple_times.ets @@ -19,5 +19,4 @@ export type {A} export type MyA = A export type {MyA} -/* @@? 20:14 Error SyntaxError: The given name 'MyA' is already used in another export. */ -/* @@? 20:14 Error SyntaxError: Cannot export 'MyA', it was already exported. */ +/* @@? 16:1 Warning Warning: Duplicated export aliases for 'MyA'. */ diff --git a/ets2panda/test/ast/compiler/ets/export_type_interface_multiple_times.ets b/ets2panda/test/ast/compiler/ets/export_type_interface_multiple_times.ets index 0a34b8a2ccc76dfe13ec1f5db9f8a32b69a1f350..c714b60e24ca21ee91891a307510645039df3154 100644 --- a/ets2panda/test/ast/compiler/ets/export_type_interface_multiple_times.ets +++ b/ets2panda/test/ast/compiler/ets/export_type_interface_multiple_times.ets @@ -18,6 +18,3 @@ interface I {} export type {I} export type MyI = I export type {MyI} - -/* @@? 20:14 Error SyntaxError: The given name 'MyI' is already used in another export. */ -/* @@? 20:14 Error SyntaxError: Cannot export 'MyI', it was already exported. */ diff --git a/ets2panda/test/ast/compiler/ets/import_tests/export_multi_error.ets b/ets2panda/test/ast/compiler/ets/import_tests/export_multi_error.ets index c02f3a526ae875adb5d1ec2014619b77318671c5..1bcecf5a368b19c18e591af97df0c7138912a6c6 100644 --- a/ets2panda/test/ast/compiler/ets/import_tests/export_multi_error.ets +++ b/ets2panda/test/ast/compiler/ets/import_tests/export_multi_error.ets @@ -58,11 +58,6 @@ export default function TestFuncToo(): void {} /*-----------------*/ /* @@? 16:10 Error SyntaxError: Cannot find name 'foo' to export. */ -/* @@? 27:14 Error SyntaxError: The given name 'foo2' is already used in another export. */ -/* @@? 27:27 Error SyntaxError: The given name 'foo2' is already used in another export. */ -/* @@? 33:11 Error SyntaxError: Cannot export 'foo3', it was already exported. */ -/* @@? 39:19 Error SyntaxError: Cannot export 'A', it was already exported. */ -/* @@? 46:14 Error SyntaxError: The given name 'MyI' is already used in another export. */ -/* @@? 46:14 Error SyntaxError: Cannot export 'MyI', it was already exported. */ +/* @@? 27:14 Error SyntaxError: Cannot export two different names with the same export alias name 'foo2'. */ /* @@? 56:16 Error TypeError: Only one default export is allowed in a module */ /* @@? 57:16 Error TypeError: Only one default export is allowed in a module */ diff --git a/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/export_type_several_times_1.ets b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/export_type_several_times_1.ets new file mode 100644 index 0000000000000000000000000000000000000000..3262d1a8397c9f94e46088aded27755baab15a52 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/export_type_several_times_1.ets @@ -0,0 +1,24 @@ +/* + * 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 function foo(): void {} +export class A {} + +export { + foo as f1, + foo as f2, + A as a1, + A as a2 +} diff --git a/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/export_type_several_times_2.ets b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/export_type_several_times_2.ets new file mode 100644 index 0000000000000000000000000000000000000000..54f88f12e3d075c93af321b165798e14331e755c --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/export_type_several_times_2.ets @@ -0,0 +1,27 @@ +/* + * 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. + */ + +function foo(): void {} +class A {} +let a = new A() + +export { + foo as f1, + foo as f2, + A as a1, + A as a2, + a as a3, + a as a4 +} diff --git a/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/import_same_type_form_alias_1.ets b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/import_same_type_form_alias_1.ets new file mode 100644 index 0000000000000000000000000000000000000000..f3d2d5d4dce9f50757031609c6b892db8e539ee0 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/import_same_type_form_alias_1.ets @@ -0,0 +1,23 @@ +/* + * 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 { foo, f1, f2, A, a1, a2 } from "./export_type_several_times_1.ets" + +foo() +f1() +f2() +let c: A = new A() +let c1: A = new a1() +let c2: A = new a2() \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/import_same_type_form_alias_2.ets b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/import_same_type_form_alias_2.ets new file mode 100644 index 0000000000000000000000000000000000000000..91be1a73dbe8f87fd4b7b6696793289ce2f3f1bf --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/import_same_type_form_alias_2.ets @@ -0,0 +1,23 @@ +/* + * 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 { f1, f2, a1, a2, a3, a4 } from "./export_type_several_times_2.ets" + +f1() +f2() +let c1: a1 = new a1() +let c2: a2 = new a2() +c1 = a3 +c2 = a4 \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/import_same_type_form_alias_3.ets b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/import_same_type_form_alias_3.ets new file mode 100644 index 0000000000000000000000000000000000000000..fec071802f9ed657b099cc121f7fced934488fd2 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/import_same_type_form_alias_3.ets @@ -0,0 +1,24 @@ +/* + * 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 { foo, f1, f2, A, a1, a2 } from "./export_type_several_times_2.ets" + +f1() +f2() +let c1: a1 = new a1() +let c2: a2 = new a2() + +/* @@? 16:10 Error TypeError: Cannot find imported element 'foo' */ +/* @@? 16:23 Error TypeError: Cannot find imported element 'A' */ diff --git a/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/selective_export_clashing_exports_1.ets b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/selective_export_clashing_exports_1.ets index 453e606be33f02190dd29f0fd3abf2417c1936cf..bddda705c6dc2175b3fe368d4a3614e59d69c395 100644 --- a/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/selective_export_clashing_exports_1.ets +++ b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/selective_export_clashing_exports_1.ets @@ -16,7 +16,5 @@ export function foo(): void {} export { - foo as /* @@ label */bar + foo as bar } - -/* @@@ label Error SyntaxError: Cannot export 'foo', it was already exported. */ diff --git a/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/selective_export_clashing_exports_2.ets b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/selective_export_clashing_exports_2.ets index b5eeab80f63d56146b1a930950285600f5b22ed5..a75a5dbac45bf1d154c2f08e209dc9db626f0e2e 100644 --- a/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/selective_export_clashing_exports_2.ets +++ b/ets2panda/test/ast/compiler/ets/import_tests/selective_export_tests/selective_export_clashing_exports_2.ets @@ -16,7 +16,5 @@ export default function foo(): void {} export { - foo as /* @@ label */bar + foo as bar } - -/* @@@ label Error SyntaxError: Cannot export 'foo', it was already exported. */ diff --git a/ets2panda/test/ast/compiler/ets/namespaceExport_neg.ets b/ets2panda/test/ast/compiler/ets/namespaceExport_neg.ets index e742a4cdc820877914a2ce0aaade1f4ab7910b05..fb3ea3bbd88e3a272e2f97495859f8006f8b68a8 100644 --- a/ets2panda/test/ast/compiler/ets/namespaceExport_neg.ets +++ b/ets2panda/test/ast/compiler/ets/namespaceExport_neg.ets @@ -30,5 +30,3 @@ declare namespace A { } export default A -/* @@? 27:20 Error SyntaxError: Cannot export 'A', it was already exported. */ - diff --git a/ets2panda/test/ast/parser/ets/import_tests/type/type_2.ets b/ets2panda/test/ast/parser/ets/import_tests/type/type_2.ets index aa88265896ace1057ed3c5b1512650ac2305064f..7cab79843aa6ea29448fdcacdafb4dc6a2275b8f 100644 --- a/ets2panda/test/ast/parser/ets/import_tests/type/type_2.ets +++ b/ets2panda/test/ast/parser/ets/import_tests/type/type_2.ets @@ -16,5 +16,3 @@ export class A {} export type {A as AA}; - -/* @@? 18:19 Error SyntaxError: Cannot export 'A', it was already exported. */ \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/import_tests/type/type_3.ets b/ets2panda/test/ast/parser/ets/import_tests/type/type_3.ets index 0b9164b765f7c06ab2d9555a1be06ff19d4a9ea5..ea9cf69480b354a22de4ce154b6d7bd83b015012 100644 --- a/ets2panda/test/ast/parser/ets/import_tests/type/type_3.ets +++ b/ets2panda/test/ast/parser/ets/import_tests/type/type_3.ets @@ -19,5 +19,4 @@ class TestClass {} export {foo} export type {TestClass as foo} -/* @@? 20:14 Error SyntaxError: The given name 'foo' is already used in another export. */ -/* @@? 20:27 Error SyntaxError: The given name 'foo' is already used in another export. */ +/* @@? 20:14 Error SyntaxError: Cannot export two different names with the same export alias name 'foo'. */ diff --git a/ets2panda/test/test-lists/astchecker/astchecker-ets-ignored.txt b/ets2panda/test/test-lists/astchecker/astchecker-ets-ignored.txt index 3888be099f06c2f41a1d1aefc8f37af562268910..27aedf969a054fece4a6951c42068f9ccc08c4a8 100644 --- a/ets2panda/test/test-lists/astchecker/astchecker-ets-ignored.txt +++ b/ets2panda/test/test-lists/astchecker/astchecker-ets-ignored.txt @@ -102,3 +102,9 @@ ast/compiler/ets/lambda_infer_type/lambda_param_type_cannot_be_determined.ets # Issue: #24605 incorrect column ast/parser/ets/named_types_2.ets + + +# Issue: #27365 Cannot add correct comment to astchecker to see warning with 0:0 position (duplicate export warning) +ast/compiler/ets/export_type_class_multiple_times.ets +ast/compiler/ets/export_type_interface_multiple_times.ets +ast/compiler/ets/import_tests/export_multi_error.ets \ No newline at end of file diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index 72003d7cc49ccc5ebe9a5a16990078b11485bc10..be7c754eb5c73fad0a0b92a21d1f523c3682bc29 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -80,6 +80,10 @@ syntax: id: 17 message: "Index type expected in index signature." +- name: CANNOT_EXPORT_DIFFERENT_OBJECTS_WITH_SAME_NAME + id: 344 + message: "Cannot export two different names with the same export alias name '{}'." + - name: INDEX_TYPE_NOT_NUMBER id: 18 message: "Index type must be number in index signature." @@ -1240,6 +1244,6 @@ syntax: id: 306 message: "Function expressions are not supported, use arrow functions instead" -- name: DEFAULT_PARAM_IN_DECLARE +- name: DEFAULT_PARAM_IN_DECLARE id: 307 message: "A parameter initializer is only allowed in a function or constructor implementation." diff --git a/ets2panda/util/diagnostic/warning.yaml b/ets2panda/util/diagnostic/warning.yaml index 264a442c2df3de7ad09236d4d6ac5c921f14b0d2..c778be08f0d1c695bb1203fd655cf1348e9d040d 100644 --- a/ets2panda/util/diagnostic/warning.yaml +++ b/ets2panda/util/diagnostic/warning.yaml @@ -28,6 +28,10 @@ warning: id: 4 message: "Boost Equality Statement. Change sides of binary expression." +- name: DUPLICATE_EXPORT_ALIASES + id: 73 + message: "Duplicated export aliases for '{}'." + - name: REPLACE_ASYNC_FUNCTION_WITH_COROUTINE id: 5 message: "Replace asynchronous function with coroutine." diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index 43eb2ceffc8173620047c493aae906f525a0400a..2389c72b23cb45571aba8974cdc9861b1d309df6 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -211,11 +211,20 @@ void ETSBinder::ResolveReferencesForScopeWithContext(ir::AstNode *node, Scope *s ResolveReference(node); } -bool ETSBinder::AddSelectiveExportAlias(util::StringView const &path, util::StringView const &key, - util::StringView const &value, ir::AstNode const *decl) noexcept +// export { a as b } value => a, key => b +// value == value and key == key => Warning, value == value and key != key => Ok, value != value and key == key => CTE +bool ETSBinder::AddSelectiveExportAlias(parser::ETSParser *parser, util::StringView const &path, + util::StringView const &key, util::StringView const &value, + ir::AstNode const *decl) noexcept { if (auto foundMap = selectiveExportAliasMultimap_.find(path); foundMap != selectiveExportAliasMultimap_.end()) { - return foundMap->second.insert({key, std::make_pair(value, decl)}).second; + auto inserted = foundMap->second.insert({key, std::make_pair(value, decl)}).second; + if (UNLIKELY(!inserted && foundMap->second.find(key)->second.first == value)) { + parser->DiagnosticEngine().Log( + {util::DiagnosticType::WARNING, diagnostic::DUPLICATE_EXPORT_ALIASES, {key}, decl->Start()}); + return true; + } + return inserted; } ArenaMap> map(Allocator()->Adapter()); @@ -805,7 +814,8 @@ Variable *ETSBinder::FindImportSpecifiersVariable(const util::StringView &import static bool IsExportedVariable(varbinder::Variable *const var) { return var != nullptr && - (var->Declaration()->Node()->IsExported() || var->Declaration()->Node()->IsDefaultExported()); + (var->Declaration()->Node()->IsExported() || var->Declaration()->Node()->IsDefaultExported() || + var->Declaration()->Node()->HasExportAlias()); } std::pair ETSBinder::FindImportDeclInExports( @@ -942,7 +952,7 @@ void ETSBinder::ValidateImportVariable(const ir::AstNode *node, const util::Stri { if (node->IsDefaultExported()) { ThrowError(importPath->Start(), diagnostic::DEFAULT_EXPORT_DIRECT_IMPORTED); - } else if (!node->IsExported() && !node->IsDefaultExported()) { + } else if (!node->IsExported() && !node->IsDefaultExported() && !node->HasExportAlias()) { ThrowError(importPath->Start(), diagnostic::IMPORTED_NOT_EXPORTED, {imported}); } } @@ -1064,8 +1074,9 @@ bool ETSBinder::AddImportSpecifiersToTopBindings(Span re } // The first part of the condition will be true, if something was given an alias when exported, but we try - // to import it using its original name. - if (nameToSearchFor == imported && var->Declaration()->Node()->HasExportAlias()) { + // to import it using its original name and if original name is not exported. + if (nameToSearchFor == imported && var->Declaration()->Node()->HasExportAlias() && + !var->Declaration()->Node()->IsExported()) { ThrowError(importSpecifier->Start(), diagnostic::IMPORT_NOT_FOUND, {imported}); return false; } diff --git a/ets2panda/varbinder/ETSBinder.h b/ets2panda/varbinder/ETSBinder.h index bc0096047f6817f283244f5df55243624ad406ba..4b446aa2e022fbcbcdb27cd82be4f2cbe7a00d12 100644 --- a/ets2panda/varbinder/ETSBinder.h +++ b/ets2panda/varbinder/ETSBinder.h @@ -23,6 +23,7 @@ #include "ir/expressions/identifier.h" #include "ir/module/importSpecifier.h" #include "ir/statements/annotationDeclaration.h" +#include "parser/ETSparser.h" namespace ark::es2panda::ir { class ETSImportDeclaration; @@ -256,8 +257,9 @@ public: void ResolveReferencesForScopeWithContext(ir::AstNode *node, Scope *scope); - [[nodiscard]] bool AddSelectiveExportAlias(util::StringView const &path, util::StringView const &key, - util::StringView const &value, ir::AstNode const *decl) noexcept; + [[nodiscard]] bool AddSelectiveExportAlias(parser::ETSParser *parser, util::StringView const &path, + util::StringView const &key, util::StringView const &value, + ir::AstNode const *decl) noexcept; [[nodiscard]] const ModulesToExportedNamesWithAliases &GetSelectiveExportAliasMultimap() const noexcept { diff --git a/ets2panda/varbinder/scope.cpp b/ets2panda/varbinder/scope.cpp index 49b0538b7bd08e01d151b7cc164c31b28e82211e..4f40ed1606a2888152d206d791af4170851ae5bd 100644 --- a/ets2panda/varbinder/scope.cpp +++ b/ets2panda/varbinder/scope.cpp @@ -671,7 +671,7 @@ Scope::InsertResult GlobalScope::InsertImpl(const util::StringView &name, Variab ES2PANDA_ASSERT(var->Declaration()->Name().Utf8().find(compiler::Signatures::ETS_GLOBAL) == std::string::npos); const auto *const node = var->Declaration()->Node(); - if (!(node->IsExported() || node->IsDefaultExported())) { + if (!(node->IsExported() || node->IsDefaultExported() || node->HasExportAlias())) { return Scope::InsertResult {Bindings().end(), false}; } }