From 1c666b4418f3c55b743d9c6e1c32e035a19c9a55 Mon Sep 17 00:00:00 2001 From: songqi Date: Mon, 7 Nov 2022 11:12:35 +0800 Subject: [PATCH] Move interface into tsBindings Issue: I5X04W Test: test262, parser tests, compiler tests, tsc Signed-off-by: songqi Change-Id: I75370b26b54ff5e00429c855b8c9a6f2592abd22 --- es2panda/binder/binder.cpp | 7 +- es2panda/binder/binder.h | 11 +- es2panda/binder/scope.cpp | 31 +--- es2panda/binder/scope.h | 8 +- es2panda/binder/variable.cpp | 1 + es2panda/binder/variable.h | 12 ++ es2panda/binder/variableFlags.h | 12 +- es2panda/compiler/core/function.cpp | 2 +- es2panda/ir/ts/tsInterfaceDeclaration.cpp | 4 + es2panda/parser/parserImpl.h | 2 +- es2panda/parser/statementParser.cpp | 35 ++-- es2panda/parser/transformer/transformer.cpp | 4 +- .../ts/test-export-interface-expected.txt | 163 ++++++++++++++++++ .../test/parser/ts/test-export-interface.ts | 21 +++ es2panda/test/test_tsc_ignore_list.txt | 1 - 15 files changed, 243 insertions(+), 71 deletions(-) create mode 100644 es2panda/test/parser/ts/test-export-interface-expected.txt create mode 100644 es2panda/test/parser/ts/test-export-interface.ts diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index a5a97664bd..2cfbe93703 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -129,7 +129,7 @@ void Binder::ValidateExportDecl(const ir::ExportNamedDeclaration *exportDecl) for (auto *it : exportDecl->Specifiers()) { auto localName = it->AsExportSpecifier()->Local()->Name(); if (scope_->IsTSModuleScope()) { - if (scope_->FindLocal(localName, ResolveBindingOptions::ALL) == nullptr && + if (scope_->FindLocal(localName) == nullptr && !scope_->InLocalTSBindings(localName) && !scope_->AsTSModuleScope()->InExportBindings(localName)) { ThrowUndeclaredExport(it->AsExportSpecifier()->Local()->Start(), localName); @@ -140,8 +140,7 @@ void Binder::ValidateExportDecl(const ir::ExportNamedDeclaration *exportDecl) if (scope_->FindLocal(localName) == nullptr) { // The declaration of ts cannot correspond to the variables of ts before transform, // After the transform, they are all js variables. So it can return directly here. - if (scope_->InLocalTSBindings(localName) || - scope_->FindLocal(localName, ResolveBindingOptions::INTERFACES)) { + if (scope_->InLocalTSBindings(localName)) { continue; } ThrowUndeclaredExport(it->AsExportSpecifier()->Local()->Start(), localName); @@ -206,7 +205,7 @@ void Binder::LookupIdentReference(ir::Identifier *ident) InstantiateArguments(); } - ScopeFindResult res = scope_->Find(ident->Name(), bindingOptions_); + ScopeFindResult res = scope_->Find(ident->Name()); if (res.level != 0) { ASSERT(res.variable); diff --git a/es2panda/binder/binder.h b/es2panda/binder/binder.h index a45d8a198d..fa355e95bb 100644 --- a/es2panda/binder/binder.h +++ b/es2panda/binder/binder.h @@ -49,15 +49,7 @@ public: functionNames_(Allocator()->Adapter()), anonymousFunctionNames_(Allocator()->Adapter()), variableNames_(Allocator()->Adapter()), - extension_(extension) - { - if (extension_ == ScriptExtension::TS) { - bindingOptions_ = ResolveBindingOptions::ALL; - return; - } - - bindingOptions_ = ResolveBindingOptions::BINDINGS; - } + extension_(extension) {} NO_COPY_SEMANTIC(Binder); DEFAULT_MOVE_SEMANTIC(Binder); @@ -202,7 +194,6 @@ private: FunctionScope *topScope_ {}; Scope *scope_ {}; ArenaVector functionScopes_; - ResolveBindingOptions bindingOptions_; ArenaSet functionNames_; ArenaUnorderedMap anonymousFunctionNames_; ArenaSet variableNames_; diff --git a/es2panda/binder/scope.cpp b/es2panda/binder/scope.cpp index 63e1295967..3db08b64c3 100644 --- a/es2panda/binder/scope.cpp +++ b/es2panda/binder/scope.cpp @@ -63,21 +63,8 @@ FunctionScope *Scope::EnclosingFunctionVariableScope() return nullptr; } -Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const +Variable *Scope::FindLocal(const util::StringView &name) const { - if (options & ResolveBindingOptions::INTERFACES) { - util::StringView interfaceNameView(binder::TSBinding::ToTSBinding(name)); - - auto res = bindings_.find(interfaceNameView); - if (res != bindings_.end()) { - return res->second; - } - - if (!(options & ResolveBindingOptions::BINDINGS)) { - return nullptr; - } - } - auto res = bindings_.find(name); if (res == bindings_.end()) { return nullptr; @@ -86,14 +73,14 @@ Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions o return res->second; } -ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions options) const +ScopeFindResult Scope::Find(const util::StringView &name) const { uint32_t level = 0; uint32_t lexLevel = 0; const auto *iter = this; if (iter->IsFunctionParamScope()) { - Variable *v = iter->FindLocal(name, options); + Variable *v = iter->FindLocal(name); if (v != nullptr) { return {name, const_cast(iter), level, lexLevel, v}; @@ -111,7 +98,7 @@ ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions } while (iter != nullptr) { - Variable *v = iter->FindLocal(name, options); + Variable *v = iter->FindLocal(name); if (v != nullptr) { return {name, const_cast(iter), level, lexLevel, v}; @@ -201,8 +188,8 @@ bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl newDecl->Name(), allocator->New(newDecl, VariableFlags::ENUM_LITERAL)); } case DeclType::INTERFACE: { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::INTERFACE)}); - return true; + return tsBindings_.AddTSVariable( + newDecl->Name(), allocator->New(newDecl, VariableFlags::INTERFACE)); } case DeclType::FUNC: { flags = VariableFlags::HOIST; @@ -304,7 +291,7 @@ bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVaria return AddTSBinding(allocator, newDecl, VariableFlags::IMPORT_EQUALS); } case DeclType::INTERFACE: { - return AddTSBinding(allocator, currentVariable, newDecl, VariableFlags::INTERFACE); + return AddTSBinding(allocator, newDecl, VariableFlags::INTERFACE); } default: { return AddLexical(allocator, currentVariable, newDecl); @@ -339,7 +326,7 @@ bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl return AddTSBinding(allocator, newDecl, VariableFlags::IMPORT_EQUALS); } case DeclType::INTERFACE: { - return AddTSBinding(allocator, currentVariable, newDecl, VariableFlags::INTERFACE); + return AddTSBinding(allocator, newDecl, VariableFlags::INTERFACE); } default: { return AddLexical(allocator, currentVariable, newDecl); @@ -406,7 +393,7 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl return AddTSBinding(allocator, newDecl, VariableFlags::IMPORT_EQUALS); } case DeclType::INTERFACE: { - return AddTSBinding(allocator, currentVariable, newDecl, VariableFlags::INTERFACE); + return AddTSBinding(allocator, newDecl, VariableFlags::INTERFACE); } default: { if (currentVariable) { diff --git a/es2panda/binder/scope.h b/es2panda/binder/scope.h index 29c03a3297..ae90e9ccdc 100644 --- a/es2panda/binder/scope.h +++ b/es2panda/binder/scope.h @@ -277,7 +277,7 @@ public: bool AddTsDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension) { decls_.push_back(decl); - return AddBinding(allocator, FindLocal(decl->Name(), ResolveBindingOptions::ALL), decl, extension); + return AddBinding(allocator, FindLocal(decl->Name()), decl, extension); } template @@ -306,11 +306,9 @@ public: virtual bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension) = 0; - Variable *FindLocal(const util::StringView &name, - ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const; + Variable *FindLocal(const util::StringView &name) const; - ScopeFindResult Find(const util::StringView &name, - ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const; + ScopeFindResult Find(const util::StringView &name) const; Decl *FindDecl(const util::StringView &name) const; diff --git a/es2panda/binder/variable.cpp b/es2panda/binder/variable.cpp index 0539c9ccc5..be07b49b40 100644 --- a/es2panda/binder/variable.cpp +++ b/es2panda/binder/variable.cpp @@ -71,6 +71,7 @@ void EnumVariable::SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] ut void NamespaceVariable::SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::Hotfix *hotfixHelper) {} void ImportEqualsVariable::SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::Hotfix *hotfixHelper) {} void EnumLiteralVariable::SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::Hotfix *hotfixHelper) {} +void InterfaceVariable::SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::Hotfix *hotfixHelper) {} void EnumVariable::ResetDecl(Decl *decl) { diff --git a/es2panda/binder/variable.h b/es2panda/binder/variable.h index 170055cf16..84d5613f84 100644 --- a/es2panda/binder/variable.h +++ b/es2panda/binder/variable.h @@ -350,5 +350,17 @@ private: Scope *scope_ {nullptr}; }; +class InterfaceVariable : public Variable { +public: + explicit InterfaceVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {} + + VariableType Type() const override + { + return VariableType::INTERFACE; + } + + void SetLexical([[maybe_unused]] Scope *scope, [[maybe_unused]] util::Hotfix *hotfixHelper = nullptr) override; +}; + } // namespace panda::es2panda::binder #endif diff --git a/es2panda/binder/variableFlags.h b/es2panda/binder/variableFlags.h index 4d0d465663..3f85f54c8f 100644 --- a/es2panda/binder/variableFlags.h +++ b/es2panda/binder/variableFlags.h @@ -68,15 +68,6 @@ enum class ScopeType { #undef GEN_SCOPE_TYPES }; -enum class ResolveBindingOptions { - BINDINGS = 1U << 0U, - INTERFACES = 1U << 1U, - - ALL = BINDINGS | INTERFACES, -}; - -DEFINE_BITOPS(ResolveBindingOptions) - enum class ResolveBindingFlags { ALL = 1U << 0U, TS_BEFORE_TRANSFORM = 1U << 1U, @@ -91,7 +82,8 @@ DEFINE_BITOPS(ResolveBindingFlags) _(ENUM, EnumVariable) \ _(NAMESPACE, NamespaceVariable) \ _(IMPORT_EQUALS, ImportEqualsVariable) \ - _(ENUMLITERAL, EnumLiteralVariable) + _(ENUMLITERAL, EnumLiteralVariable) \ + _(INTERFACE, InterfaceVariable) enum class VariableType { #define GEN_VARIABLE_TYPES(type, class_name) type, diff --git a/es2panda/compiler/core/function.cpp b/es2panda/compiler/core/function.cpp index 9143ac1ca2..39d1562884 100644 --- a/es2panda/compiler/core/function.cpp +++ b/es2panda/compiler/core/function.cpp @@ -70,7 +70,7 @@ static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFu if (ref.Kind() == ReferenceKind::DESTRUCTURING) { util::StringView name = util::Helpers::ToStringView(pg->Allocator(), index); - paramVar = pg->Scope()->FindLocal(name, binder::ResolveBindingOptions::BINDINGS); + paramVar = pg->Scope()->FindLocal(name); } ASSERT(paramVar && paramVar->IsLocalVariable()); diff --git a/es2panda/ir/ts/tsInterfaceDeclaration.cpp b/es2panda/ir/ts/tsInterfaceDeclaration.cpp index ef74133aa7..948178edc3 100644 --- a/es2panda/ir/ts/tsInterfaceDeclaration.cpp +++ b/es2panda/ir/ts/tsInterfaceDeclaration.cpp @@ -96,6 +96,10 @@ void CheckInheritedPropertiesAreIdentical(checker::Checker *checker, checker::In checker::Type *TSInterfaceDeclaration::Check(checker::Checker *checker) const { binder::Variable *var = id_->Variable(); + // TODO: Interface Identifier binds InterfaceVariable. + if (var == nullptr) { + return nullptr; + } ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSInterfaceDeclaration()); if (this == var->Declaration()->Node()) { diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index 94a64af6b1..967fd1dfe9 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -487,7 +487,7 @@ private: ir::TSEnumDeclaration *ParseEnumMembers(ir::Identifier *key, const lexer::SourcePosition &enumStart, bool isExport, bool isDeclare, bool isConst); ir::TSEnumDeclaration *ParseEnumDeclaration(bool isExport = false, bool isDeclare = false, bool isConst = false); - ir::TSInterfaceDeclaration *ParseTsInterfaceDeclaration(); + ir::TSInterfaceDeclaration *ParseTsInterfaceDeclaration(bool isExport = false); ir::SwitchCaseStatement *ParseSwitchCaseStatement(bool *seenDefault); ir::SwitchStatement *ParseSwitchStatement(); ir::ThrowStatement *ParseThrowStatement(); diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index 704e029e3d..08892f6644 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -671,7 +671,7 @@ ir::TSTypeAliasDeclaration *ParserImpl::ParseTsTypeAliasDeclaration(bool isDecla return typeAliasDecl; } -ir::TSInterfaceDeclaration *ParserImpl::ParseTsInterfaceDeclaration() +ir::TSInterfaceDeclaration *ParserImpl::ParseTsInterfaceDeclaration(bool isExport) { ASSERT(lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_INTERFACE); context_.Status() |= ParserStatus::ALLOW_THIS_TYPE; @@ -690,18 +690,25 @@ ir::TSInterfaceDeclaration *ParserImpl::ParseTsInterfaceDeclaration() } const util::StringView &ident = lexer_->GetToken().Ident(); - binder::TSBinding tsBinding(Allocator(), ident); - - const auto &bindings = Binder()->GetScope()->Bindings(); - auto res = bindings.find(tsBinding.View()); binder::InterfaceDecl *decl {}; - - if (res == bindings.end()) { - decl = Binder()->AddTsDecl(lexer_->GetToken().Start(), Allocator(), tsBinding.View()); - } else if (!res->second->Declaration()->IsInterfaceDecl()) { + auto *currentScope = Binder()->GetScope(); + binder::Variable *res = currentScope->FindLocalTSVariable(ident); + if (res == nullptr && isExport && currentScope->IsTSModuleScope()) { + res = currentScope->AsTSModuleScope()->FindExportTSVariable(ident); + if (res != nullptr) { + currentScope->AddLocalTSVariable(ident, res); + } + } + if (res == nullptr) { + decl = Binder()->AddTsDecl(lexer_->GetToken().Start(), Allocator(), ident); + res = currentScope->FindLocalTSVariable(ident); + if (isExport && currentScope->IsTSModuleScope()) { + currentScope->AsTSModuleScope()->AddExportTSVariable(ident, res); + } + } else if (!res->Declaration()->IsInterfaceDecl()) { Binder()->ThrowRedeclaration(lexer_->GetToken().Start(), ident); } else { - decl = res->second->Declaration()->AsInterfaceDecl(); + decl = res->Declaration()->AsInterfaceDecl(); } auto *id = AllocNode(lexer_->GetToken().Ident(), Allocator()); @@ -776,9 +783,7 @@ ir::TSInterfaceDeclaration *ParserImpl::ParseTsInterfaceDeclaration() ASSERT(decl); - if (res == bindings.end()) { - decl->BindNode(interfaceDecl); - } + localScope.GetScope()->BindNode(interfaceDecl); decl->AsInterfaceDecl()->Add(interfaceDecl); lexer_->NextToken(); @@ -2281,7 +2286,7 @@ ir::ExportDefaultDeclaration *ParserImpl::ParseExportDefaultDeclaration(const le declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION | ParserStatus::EXPORT_REACHED); } else if (Extension() == ScriptExtension::TS && lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_INTERFACE) { - declNode = ParseTsInterfaceDeclaration(); + declNode = ParseTsInterfaceDeclaration(true); } else { declNode = ParseExpression(); Binder()->AddDecl(declNode->Start(), binder::DeclarationFlags::EXPORT, @@ -2458,7 +2463,7 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: break; } case lexer::TokenType::KEYW_INTERFACE: { - decl = ParseTsInterfaceDeclaration(); + decl = ParseTsInterfaceDeclaration(true); break; } case lexer::TokenType::KEYW_TYPE: { diff --git a/es2panda/parser/transformer/transformer.cpp b/es2panda/parser/transformer/transformer.cpp index 6726e1be61..a0c8cee834 100644 --- a/es2panda/parser/transformer/transformer.cpp +++ b/es2panda/parser/transformer/transformer.cpp @@ -156,7 +156,7 @@ binder::Scope *Transformer::FindExportVariableInTsModuleScope(util::StringView n bool isExport = false; auto currentScope = Scope(); while (currentScope != nullptr) { - binder::Variable *v = currentScope->FindLocal(name, binder::ResolveBindingOptions::ALL); + binder::Variable *v = currentScope->FindLocal(name); bool isTSModuleScope = currentScope->IsTSModuleScope(); if (v != nullptr) { if (!v->HasFlag(binder::VariableFlags::VAR)) { @@ -1184,7 +1184,7 @@ ir::UpdateNodes Transformer::VisitTsModuleDeclaration(ir::TSModuleDeclaration *n util::StringView name = GetNameFromModuleDeclaration(node); - auto findRes = Scope()->FindLocal(name, binder::ResolveBindingOptions::ALL); + auto findRes = Scope()->FindLocal(name); if (findRes == nullptr) { res.push_back(CreateVariableDeclarationForTSEnumOrTSModule(name, node, isExport)); } diff --git a/es2panda/test/parser/ts/test-export-interface-expected.txt b/es2panda/test/parser/ts/test-export-interface-expected.txt new file mode 100644 index 0000000000..62861a8321 --- /dev/null +++ b/es2panda/test/parser/ts/test-export-interface-expected.txt @@ -0,0 +1,163 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSInterfaceDeclaration", + "body": { + "type": "TSInterfaceBody", + "body": [ + { + "type": "TSPropertySignature", + "computed": false, + "optional": false, + "readonly": false, + "key": { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 6 + } + } + }, + "typeAnnotation": { + "type": "TSStringKeyword", + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 19, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 13 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + "id": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 12 + } + } + }, + "extends": [], + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 19, + "column": 2 + } + } + }, + { + "type": "ExportNamedDeclaration", + "declaration": null, + "source": null, + "specifiers": [ + { + "type": "ExportSpecifier", + "local": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 9 + }, + "end": { + "line": 21, + "column": 10 + } + } + }, + "exported": { + "type": "Identifier", + "name": "A", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 9 + }, + "end": { + "line": 21, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 9 + }, + "end": { + "line": 21, + "column": 10 + } + } + } + ], + "loc": { + "start": { + "line": 21, + "column": 1 + }, + "end": { + "line": 21, + "column": 11 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 21, + "column": 11 + } + } +} diff --git a/es2panda/test/parser/ts/test-export-interface.ts b/es2panda/test/parser/ts/test-export-interface.ts new file mode 100644 index 0000000000..8ae0290e26 --- /dev/null +++ b/es2panda/test/parser/ts/test-export-interface.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 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. + */ + + +interface A { + a : string +} + +export {A} \ No newline at end of file diff --git a/es2panda/test/test_tsc_ignore_list.txt b/es2panda/test/test_tsc_ignore_list.txt index 4aff71e039..426fef7208 100644 --- a/es2panda/test/test_tsc_ignore_list.txt +++ b/es2panda/test/test_tsc_ignore_list.txt @@ -23,7 +23,6 @@ es2panda/test/TypeScript/tests/cases/compiler/letInVarDeclOfForIn_ES5.ts es2panda/test/TypeScript/tests/cases/compiler/letInVarDeclOfForIn_ES6.ts es2panda/test/TypeScript/tests/cases/compiler/letInVarDeclOfForOf_ES5.ts es2panda/test/TypeScript/tests/cases/compiler/letInVarDeclOfForOf_ES6.ts -es2panda/test/TypeScript/tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts es2panda/test/TypeScript/tests/cases/compiler/overloadedConstructorFixesInferencesAppropriately.ts es2panda/test/TypeScript/tests/cases/compiler/parameterInitializerBeforeDestructuringEmit.ts es2panda/test/TypeScript/tests/cases/compiler/parseEntityNameWithReservedWord.ts -- Gitee