• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ETSBinder.h"
17 
18 #include "ir/expressions/blockExpression.h"
19 #include "ir/expressions/identifier.h"
20 #include "ir/expressions/thisExpression.h"
21 #include "ir/expressions/typeofExpression.h"
22 #include "ir/expressions/memberExpression.h"
23 #include "ir/expressions/callExpression.h"
24 #include "ir/expressions/functionExpression.h"
25 #include "ir/base/methodDefinition.h"
26 #include "ir/base/scriptFunction.h"
27 #include "ir/base/classElement.h"
28 #include "ir/base/classDefinition.h"
29 #include "ir/base/classProperty.h"
30 #include "ir/base/classStaticBlock.h"
31 #include "ir/statements/blockStatement.h"
32 #include "ir/statements/classDeclaration.h"
33 #include "ir/statements/variableDeclarator.h"
34 #include "ir/statements/functionDeclaration.h"
35 #include "ir/statements/returnStatement.h"
36 #include "ir/ets/etsPrimitiveType.h"
37 #include "ir/ets/etsTypeReferencePart.h"
38 #include "ir/ets/etsNewClassInstanceExpression.h"
39 #include "ir/ets/etsTypeReference.h"
40 #include "ir/ets/etsFunctionType.h"
41 #include "ir/ets/etsScript.h"
42 #include "ir/ets/etsImportDeclaration.h"
43 #include "ir/ts/tsInterfaceDeclaration.h"
44 #include "ir/ts/tsTypeParameterDeclaration.h"
45 #include "ir/ts/tsTypeParameterInstantiation.h"
46 #include "ir/ts/tsClassImplements.h"
47 #include "ir/ts/tsEnumDeclaration.h"
48 #include "ir/ts/tsEnumMember.h"
49 #include "ir/ts/tsInterfaceHeritage.h"
50 #include "ir/ts/tsInterfaceBody.h"
51 #include "ir/ts/tsFunctionType.h"
52 #include "ir/ts/tsQualifiedName.h"
53 #include "ir/module/importDefaultSpecifier.h"
54 #include "ir/module/importNamespaceSpecifier.h"
55 #include "ir/module/importDeclaration.h"
56 #include "ir/module/importSpecifier.h"
57 #include "ir/expressions/literals/stringLiteral.h"
58 #include "mem/arena_allocator.h"
59 #include "util/helpers.h"
60 #include "util/ustring.h"
61 #include "checker/types/type.h"
62 #include "checker/types/ets/types.h"
63 
64 namespace ark::es2panda::varbinder {
65 
IdentifierAnalysis()66 void ETSBinder::IdentifierAnalysis()
67 {
68     ASSERT(Program()->Ast());
69     ASSERT(GetScope() == TopScope());
70     ASSERT(VarScope() == TopScope());
71 
72     recordTable_->SetProgram(Program());
73     globalRecordTable_.SetClassDefinition(Program()->GlobalClass());
74     externalRecordTable_.insert({Program(), &globalRecordTable_});
75 
76     BuildProgram();
77 
78     ASSERT(globalRecordTable_.ClassDefinition() == Program()->GlobalClass());
79 }
80 
LookupTypeArgumentReferences(ir::ETSTypeReference * typeRef)81 void ETSBinder::LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef)
82 {
83     auto *iter = typeRef->Part();
84 
85     while (iter != nullptr) {
86         if (iter->TypeParams() == nullptr) {
87             iter = iter->Previous();
88             continue;
89         }
90 
91         ResolveReferences(iter->TypeParams());
92         iter = iter->Previous();
93     }
94 }
95 
LookupTypeReference(ir::Identifier * ident,bool allowDynamicNamespaces)96 void ETSBinder::LookupTypeReference(ir::Identifier *ident, bool allowDynamicNamespaces)
97 {
98     const auto &name = ident->Name();
99     if (name == compiler::Signatures::UNDEFINED || name == compiler::Signatures::NULL_LITERAL ||
100         name == compiler::Signatures::READONLY_TYPE_NAME || name == compiler::Signatures::PARTIAL_TYPE_NAME ||
101         name == compiler::Signatures::REQUIRED_TYPE_NAME) {
102         return;
103     }
104     auto *iter = GetScope();
105 
106     while (iter != nullptr) {
107         auto res = iter->Find(name, ResolveBindingOptions::DECLARATION | ResolveBindingOptions::TYPE_ALIASES);
108         if (res.variable == nullptr) {
109             break;
110         }
111 
112         if (IsDynamicModuleVariable(res.variable)) {
113             ident->SetVariable(res.variable);
114             return;
115         }
116 
117         if (allowDynamicNamespaces && IsDynamicNamespaceVariable(res.variable)) {
118             ident->SetVariable(res.variable);
119             return;
120         }
121 
122         switch (res.variable->Declaration()->Node()->Type()) {
123             case ir::AstNodeType::CLASS_DECLARATION:
124             case ir::AstNodeType::CLASS_DEFINITION:
125             case ir::AstNodeType::STRUCT_DECLARATION:
126             case ir::AstNodeType::TS_ENUM_DECLARATION:
127             case ir::AstNodeType::TS_INTERFACE_DECLARATION:
128             case ir::AstNodeType::TS_TYPE_PARAMETER:
129             case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION:
130             case ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER: {
131                 ident->SetVariable(res.variable);
132                 return;
133             }
134             default: {
135                 iter = iter->Parent();
136             }
137         }
138     }
139 
140     ThrowUnresolvableType(ident->Start(), name);
141 }
142 
ResolveReferencesForScope(ir::AstNode const * const parent,Scope * const scope)143 void ETSBinder::ResolveReferencesForScope(ir::AstNode const *const parent, Scope *const scope)
144 {
145     parent->Iterate([this, scope](auto *node) { ResolveReferenceForScope(node, scope); });
146 }
147 
ResolveReferenceForScope(ir::AstNode * const node,Scope * const scope)148 void ETSBinder::ResolveReferenceForScope(ir::AstNode *const node, Scope *const scope)
149 {
150     switch (node->Type()) {
151         case ir::AstNodeType::IDENTIFIER: {
152             auto *ident = node->AsIdentifier();
153             if (ident->Variable() != nullptr) {
154                 break;
155             }
156             if (auto const res = scope->Find(ident->Name(), ResolveBindingOptions::ALL); res.variable != nullptr) {
157                 ident->SetVariable(res.variable);
158             }
159             break;
160         }
161         case ir::AstNodeType::VARIABLE_DECLARATOR: {
162             auto scopeCtx = LexicalScope<Scope>::Enter(this, scope);
163             BuildVarDeclarator(node->AsVariableDeclarator());
164             break;
165         }
166         /* Maybe will be used
167         case ir::AstNodeType::BLOCK_STATEMENT: {
168             auto scope_ctx = LexicalScope<Scope>::Enter(this, node->AsBlockStatement()->Scope());
169             ResolveReferences(node);
170             break;
171         }
172         */
173         case ir::AstNodeType::BLOCK_EXPRESSION: {
174             auto scopeCtx = LexicalScope<Scope>::Enter(this, node->AsBlockExpression()->Scope());
175             ResolveReferences(node);
176             break;
177         }
178         default: {
179             ResolveReferencesForScope(node, scope);
180             break;
181         }
182     }
183 }
184 
ResolveReferencesForScopeWithContext(ir::AstNode * node,Scope * scope)185 void ETSBinder::ResolveReferencesForScopeWithContext(ir::AstNode *node, Scope *scope)
186 {
187     auto lexScope = LexicalScope<Scope>::Enter(this, scope);
188     ResolveReference(node);
189 }
190 
LookupIdentReference(ir::Identifier * ident)191 void ETSBinder::LookupIdentReference(ir::Identifier *ident)
192 {
193     const auto &name = ident->Name();
194     auto res = GetScope()->Find(name, ResolveBindingOptions::ALL);
195     if (res.level != 0) {
196         ASSERT(res.variable != nullptr);
197 
198         auto *outerFunction = GetScope()->EnclosingVariableScope()->Node();
199 
200         if ((!outerFunction->IsScriptFunction() || !outerFunction->AsScriptFunction()->IsArrow()) &&
201             !res.variable->IsGlobalVariable() && res.variable->HasFlag(VariableFlags::LOCAL) && res.level > 1) {
202             ThrowInvalidCapture(ident->Start(), name);
203         }
204     }
205 
206     if (res.variable == nullptr) {
207         return;
208     }
209 
210     if (ident->IsReference() && res.variable->Declaration()->IsLetOrConstDecl() &&
211         !res.variable->HasFlag(VariableFlags::INITIALIZED)) {
212         ThrowTDZ(ident->Start(), name);
213     }
214 }
215 
BuildClassProperty(const ir::ClassProperty * prop)216 void ETSBinder::BuildClassProperty(const ir::ClassProperty *prop)
217 {
218     ResolveReferences(prop);
219 }
220 
InitializeInterfaceIdent(ir::TSInterfaceDeclaration * decl)221 void ETSBinder::InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl)
222 {
223     auto res = GetScope()->Find(decl->Id()->Name());
224 
225     ASSERT(res.variable && res.variable->Declaration()->IsInterfaceDecl());
226     res.variable->AddFlag(VariableFlags::INITIALIZED);
227     decl->Id()->SetVariable(res.variable);
228 }
229 
ResolveEnumDeclaration(ir::TSEnumDeclaration * enumDecl)230 void ETSBinder::ResolveEnumDeclaration(ir::TSEnumDeclaration *enumDecl)
231 {
232     auto enumScopeCtx = LexicalScope<LocalScope>::Enter(this, enumDecl->Scope());
233 
234     for (auto *member : enumDecl->Members()) {
235         ResolveReference(member);
236     }
237 }
238 
ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration * decl)239 void ETSBinder::ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl)
240 {
241     auto boundCtx = BoundContext(recordTable_, decl);
242 
243     for (auto *extend : decl->Extends()) {
244         ResolveReference(extend);
245     }
246 
247     auto scopeCtx = LexicalScope<ClassScope>::Enter(this, decl->Scope()->AsClassScope());
248 
249     for (auto *stmt : decl->Body()->Body()) {
250         if (!stmt->IsClassProperty()) {
251             continue;
252         }
253 
254         ResolveReference(stmt);
255 
256         auto fieldVar =
257             ResolvePropertyReference(stmt->AsClassProperty(), decl->Scope()->AsClassScope())
258                 ->FindLocal(stmt->AsClassProperty()->Id()->Name(), varbinder::ResolveBindingOptions::BINDINGS);
259         fieldVar->AddFlag(VariableFlags::INITIALIZED);
260     }
261 
262     for (auto *stmt : decl->Body()->Body()) {
263         if (stmt->IsClassProperty()) {
264             continue;
265         }
266         ResolveReference(stmt);
267     }
268 }
269 
BuildInterfaceDeclaration(ir::TSInterfaceDeclaration * decl)270 void ETSBinder::BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl)
271 {
272     if (decl->TypeParams() != nullptr) {
273         auto typeParamScopeCtx = LexicalScope<LocalScope>::Enter(this, decl->TypeParams()->Scope());
274         ResolveReferences(decl->TypeParams());
275         ResolveInterfaceDeclaration(decl);
276         return;
277     }
278 
279     ResolveInterfaceDeclaration(decl);
280 }
281 
BuildMethodDefinition(ir::MethodDefinition * methodDef)282 void ETSBinder::BuildMethodDefinition(ir::MethodDefinition *methodDef)
283 {
284     if (methodDef->Function()->TypeParams() != nullptr) {
285         auto scopeCtx = LexicalScope<LocalScope>::Enter(this, methodDef->Function()->TypeParams()->Scope());
286         ResolveReferences(methodDef->Function()->TypeParams());
287     }
288     ResolveMethodDefinition(methodDef);
289 }
290 
ResolveMethodDefinition(ir::MethodDefinition * methodDef)291 void ETSBinder::ResolveMethodDefinition(ir::MethodDefinition *methodDef)
292 {
293     methodDef->ResolveReferences([this](auto *childNode) { ResolveReference(childNode); });
294 
295     auto *func = methodDef->Function();
296     if (methodDef->IsStatic() || func->IsStaticBlock()) {
297         return;
298     }
299 
300     auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, func->Scope()->ParamScope());
301 
302     auto params = func->Scope()->ParamScope()->Params();
303     if (!params.empty() && params.front()->Name() == MANDATORY_PARAM_THIS) {
304         return;  // Implicit this parameter is already inserted by ResolveReferences(), don't insert it twice.
305     }
306 
307     auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS);
308     thisParam->Declaration()->BindNode(thisParam_);
309 }
310 
BuildMemberExpression(ir::MemberExpression * memberExpr)311 void ETSBinder::BuildMemberExpression(ir::MemberExpression *memberExpr)
312 {
313     ResolveReference(memberExpr->Object());
314 
315     if (memberExpr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
316         ResolveReference(memberExpr->Property());
317     }
318 }
319 
BuildClassDefinition(ir::ClassDefinition * classDef)320 void ETSBinder::BuildClassDefinition(ir::ClassDefinition *classDef)
321 {
322     auto boundCtx = BoundContext(recordTable_, classDef);
323 
324     if (classDef->TypeParams() != nullptr) {
325         auto scopeCtx = LexicalScope<LocalScope>::Enter(this, classDef->TypeParams()->Scope());
326         ResolveReferences(classDef->TypeParams());
327         BuildClassDefinitionImpl(classDef);
328         return;
329     }
330 
331     BuildClassDefinitionImpl(classDef);
332 }
333 
ResolvePropertyReference(ir::ClassProperty * prop,ClassScope * scope)334 LocalScope *ETSBinder::ResolvePropertyReference(ir::ClassProperty *prop, ClassScope *scope)
335 {
336     ResolveReferences(prop);
337 
338     if (prop->IsStatic()) {
339         return scope->StaticFieldScope();
340     }
341 
342     return scope->InstanceFieldScope();
343 }
344 
BuildClassDefinitionImpl(ir::ClassDefinition * classDef)345 void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *classDef)
346 {
347     auto classCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope()->AsClassScope());
348 
349     if (classDef->Super() != nullptr) {
350         ResolveReference(classDef->Super());
351     }
352 
353     for (auto *impl : classDef->Implements()) {
354         ResolveReference(impl);
355     }
356 
357     for (auto *stmt : classDef->Body()) {
358         if (!stmt->IsClassProperty()) {
359             continue;
360         }
361 
362         auto fieldScope = ResolvePropertyReference(stmt->AsClassProperty(), classDef->Scope()->AsClassScope());
363         auto fieldName = stmt->AsClassProperty()->Id()->Name();
364         auto fieldVar = fieldScope->FindLocal(fieldName, varbinder::ResolveBindingOptions::BINDINGS);
365         fieldVar->AddFlag(VariableFlags::INITIALIZED);
366         if ((fieldVar->Declaration()->IsConstDecl() || fieldVar->Declaration()->IsReadonlyDecl()) &&
367             stmt->AsClassProperty()->Value() == nullptr) {
368             fieldVar->AddFlag(VariableFlags::EXPLICIT_INIT_REQUIRED);
369         }
370     }
371 
372     for (auto *stmt : classDef->Body()) {
373         if (stmt->IsClassProperty()) {
374             continue;
375         }
376         ResolveReference(stmt);
377     }
378 }
379 
AddFunctionThisParam(ir::ScriptFunction * func)380 void ETSBinder::AddFunctionThisParam(ir::ScriptFunction *func)
381 {
382     auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, func->Scope()->ParamScope());
383     auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS);
384     thisParam->Declaration()->BindNode(thisParam_);
385 }
386 
BuildProxyMethod(ir::ScriptFunction * func,const util::StringView & containingClassName,bool isStatic,bool isExternal)387 void ETSBinder::BuildProxyMethod(ir::ScriptFunction *func, const util::StringView &containingClassName, bool isStatic,
388                                  bool isExternal)
389 {
390     ASSERT(!containingClassName.Empty());
391     func->Scope()->BindName(containingClassName);
392 
393     if (!isStatic) {
394         auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, func->Scope()->ParamScope());
395         auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS);
396         thisParam->Declaration()->BindNode(thisParam_);
397     }
398 
399     if (!func->IsAsyncFunc() && !isExternal) {
400         Functions().push_back(func->Scope());
401     }
402 }
403 
AddDynamicSpecifiersToTopBindings(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import)404 void ETSBinder::AddDynamicSpecifiersToTopBindings(ir::AstNode *const specifier,
405                                                   const ir::ETSImportDeclaration *const import)
406 {
407     const auto name = [specifier]() {
408         if (specifier->IsImportNamespaceSpecifier()) {
409             return specifier->AsImportNamespaceSpecifier()->Local()->Name();
410         }
411 
412         return specifier->AsImportSpecifier()->Local()->Name();
413     }();
414 
415     ASSERT(GetScope()->Find(name, ResolveBindingOptions::DECLARATION).variable != nullptr);
416     auto specDecl = GetScope()->Find(name, ResolveBindingOptions::DECLARATION);
417     dynamicImportVars_.emplace(specDecl.variable, DynamicImportData {import, specifier, specDecl.variable});
418 
419     if (specifier->IsImportSpecifier()) {
420         auto importSpecifier = specifier->AsImportSpecifier();
421         importSpecifier->Imported()->SetVariable(specDecl.variable);
422         importSpecifier->Local()->SetVariable(specDecl.variable);
423     }
424 }
425 
InsertForeignBinding(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import,const util::StringView & name,Variable * var)426 void ETSBinder::InsertForeignBinding(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import,
427                                      const util::StringView &name, Variable *var)
428 {
429     if (import->Language().IsDynamic()) {
430         dynamicImportVars_.emplace(var, DynamicImportData {import, specifier, var});
431     }
432 
433     TopScope()->InsertForeignBinding(name, var);
434 }
435 
RedeclarationErrorMessageAssembler(const Variable * const var,const Variable * const variable,util::StringView localName)436 std::string RedeclarationErrorMessageAssembler(const Variable *const var, const Variable *const variable,
437                                                util::StringView localName)
438 {
439     auto type = var->Declaration()->Node()->IsClassDefinition() ? "Class '"
440                 : var->Declaration()->IsFunctionDecl()          ? "Function '"
441                                                                 : "Variable '";
442     auto str = util::Helpers::AppendAll(type, localName.Utf8(), "'");
443     str += variable->Declaration()->Type() == var->Declaration()->Type() ? " is already defined."
444                                                                          : " is already defined with different type.";
445 
446     return str;
447 }
448 
GetPackageName(varbinder::Variable * var)449 static const util::StringView &GetPackageName(varbinder::Variable *var)
450 {
451     Scope *scope = var->GetScope();
452 
453     while (scope->Parent() != nullptr) {
454         scope = scope->Parent();
455     }
456 
457     ASSERT(scope->Node()->IsETSScript());
458 
459     return scope->Node()->AsETSScript()->Program()->ModuleName();
460 }
461 
AddOverloadFlag(ArenaAllocator * allocator,bool isStdLib,varbinder::Variable * importedVar,varbinder::Variable * variable)462 void AddOverloadFlag(ArenaAllocator *allocator, bool isStdLib, varbinder::Variable *importedVar,
463                      varbinder::Variable *variable)
464 {
465     auto *const currentNode = variable->Declaration()->Node()->AsMethodDefinition();
466     auto *const method = importedVar->Declaration()->Node()->AsMethodDefinition();
467 
468     // Necessary because stdlib and escompat handled as same package, it can be removed after fixing package handling
469     if (isStdLib && (GetPackageName(importedVar) != GetPackageName(variable))) {
470         return;
471     }
472 
473     if (!method->Overloads().empty() && !method->HasOverload(currentNode)) {
474         method->AddOverload(currentNode);
475         currentNode->Function()->Id()->SetVariable(importedVar);
476         currentNode->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
477         currentNode->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD);
478         util::UString newInternalName(currentNode->Function()->Scope()->Name(), allocator);
479         currentNode->Function()->Scope()->BindInternalName(newInternalName.View());
480         return;
481     }
482 
483     if (!currentNode->HasOverload(method)) {
484         currentNode->AddOverload(method);
485         method->Function()->Id()->SetVariable(variable);
486         method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
487         method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD);
488         util::UString newInternalName(method->Function()->Scope()->Name(), allocator);
489         method->Function()->Scope()->BindInternalName(newInternalName.View());
490     }
491 }
492 
ImportAllForeignBindings(ir::AstNode * const specifier,const varbinder::Scope::VariableMap & globalBindings,const parser::Program * const importProgram,const varbinder::GlobalScope * const importGlobalScope,const ir::ETSImportDeclaration * const import)493 void ETSBinder::ImportAllForeignBindings(ir::AstNode *const specifier,
494                                          const varbinder::Scope::VariableMap &globalBindings,
495                                          const parser::Program *const importProgram,
496                                          const varbinder::GlobalScope *const importGlobalScope,
497                                          const ir::ETSImportDeclaration *const import)
498 {
499     for (const auto [bindingName, var] : globalBindings) {
500         if (bindingName.Is(compiler::Signatures::ETS_GLOBAL)) {
501             const auto *const classDef = var->Declaration()->Node()->AsClassDeclaration()->Definition();
502             ImportGlobalProperties(classDef);
503             continue;
504         }
505 
506         if (!importGlobalScope->IsForeignBinding(bindingName) && !var->Declaration()->Node()->IsDefaultExported() &&
507             (var->AsLocalVariable()->Declaration()->Node()->IsExported() ||
508              var->AsLocalVariable()->Declaration()->Node()->IsExportedType())) {
509             auto variable = Program()->GlobalClassScope()->FindLocal(bindingName, ResolveBindingOptions::ALL);
510             if (variable != nullptr && var != variable && variable->Declaration()->IsFunctionDecl() &&
511                 var->Declaration()->IsFunctionDecl()) {
512                 bool isStdLib = util::Helpers::IsStdLib(Program());
513                 AddOverloadFlag(Allocator(), isStdLib, var, variable);
514                 continue;
515             }
516             if (variable != nullptr && var != variable) {
517                 ThrowError(import->Source()->Start(), RedeclarationErrorMessageAssembler(var, variable, bindingName));
518             }
519             InsertForeignBinding(specifier, import, bindingName, var);
520         }
521     }
522 
523     for (const auto [bindingName, var] : importProgram->GlobalClassScope()->StaticMethodScope()->Bindings()) {
524         if (!var->Declaration()->Node()->IsDefaultExported()) {
525             InsertForeignBinding(specifier, import, bindingName, var);
526         }
527     }
528 
529     for (const auto [bindingName, var] : importProgram->GlobalClassScope()->StaticFieldScope()->Bindings()) {
530         if (!var->Declaration()->Node()->IsDefaultExported()) {
531             InsertForeignBinding(specifier, import, bindingName, var);
532         }
533     }
534 }
535 
AddImportNamespaceSpecifiersToTopBindings(ir::AstNode * const specifier,const varbinder::Scope::VariableMap & globalBindings,const parser::Program * const importProgram,const varbinder::GlobalScope * const importGlobalScope,const ir::ETSImportDeclaration * const import)536 bool ETSBinder::AddImportNamespaceSpecifiersToTopBindings(ir::AstNode *const specifier,
537                                                           const varbinder::Scope::VariableMap &globalBindings,
538                                                           const parser::Program *const importProgram,
539                                                           const varbinder::GlobalScope *const importGlobalScope,
540                                                           const ir::ETSImportDeclaration *const import)
541 {
542     if (!specifier->IsImportNamespaceSpecifier()) {
543         return false;
544     }
545     const auto *const namespaceSpecifier = specifier->AsImportNamespaceSpecifier();
546 
547     if (namespaceSpecifier->Local()->Name().Empty()) {
548         ImportAllForeignBindings(specifier, globalBindings, importProgram, importGlobalScope, import);
549     }
550 
551     std::unordered_set<std::string> exportedNames;
552     for (auto item : ReExportImports()) {
553         // NOTE(rsipka): this should be refactored or eliminated
554         if (auto source = import->ResolvedSource()->Str(), program = item->GetProgramPath();
555             !source.Is(program.Mutf8())) {
556             continue;
557         }
558 
559         for (auto it : item->GetETSImportDeclarations()->Specifiers()) {
560             if (it->IsImportNamespaceSpecifier() && !namespaceSpecifier->Local()->Name().Empty()) {
561                 continue;
562             }
563 
564             AddSpecifiersToTopBindings(it, item->GetETSImportDeclarations(),
565                                        item->GetETSImportDeclarations()->Source());
566 
567             if (it->IsImportSpecifier() &&
568                 !exportedNames.insert(it->AsImportSpecifier()->Local()->Name().Mutf8()).second) {
569                 ThrowError(import->Start(), "Ambiguous import \"" + it->AsImportSpecifier()->Local()->Name().Mutf8() +
570                                                 "\" has multiple matching exports");
571             }
572         }
573     }
574 
575     return true;
576 }
577 
FindImportSpecifiersVariable(const util::StringView & imported,const varbinder::Scope::VariableMap & globalBindings,const ArenaVector<parser::Program * > & recordRes)578 Variable *ETSBinder::FindImportSpecifiersVariable(const util::StringView &imported,
579                                                   const varbinder::Scope::VariableMap &globalBindings,
580                                                   const ArenaVector<parser::Program *> &recordRes)
581 {
582     auto foundVar = globalBindings.find(imported);
583     if (foundVar == globalBindings.end()) {
584         const auto &staticMethodBindings = recordRes.front()->GlobalClassScope()->StaticMethodScope()->Bindings();
585         foundVar = staticMethodBindings.find(imported);
586         if (foundVar != staticMethodBindings.end()) {
587             return foundVar->second;
588         }
589         bool found = false;
590         for (auto res : recordRes) {
591             const auto &staticFieldBindings = res->GlobalClassScope()->StaticFieldScope()->Bindings();
592             foundVar = staticFieldBindings.find(imported);
593             if (foundVar != staticFieldBindings.end()) {
594                 found = true;
595                 foundVar->second->AsLocalVariable()->AddFlag(VariableFlags::INITIALIZED);
596                 break;
597             }
598         }
599         if (!found) {
600             return nullptr;
601         }
602     }
603 
604     return foundVar->second;
605 }
606 
FindImportDeclInReExports(const ir::ETSImportDeclaration * const import,std::vector<ir::ETSImportDeclaration * > & viewedReExport,const util::StringView & imported,const ir::StringLiteral * const importPath)607 ir::ETSImportDeclaration *ETSBinder::FindImportDeclInReExports(const ir::ETSImportDeclaration *const import,
608                                                                std::vector<ir::ETSImportDeclaration *> &viewedReExport,
609                                                                const util::StringView &imported,
610                                                                const ir::StringLiteral *const importPath)
611 {
612     ir::ETSImportDeclaration *implDecl = nullptr;
613     for (auto item : ReExportImports()) {
614         if (auto source = import->ResolvedSource()->Str(), program = item->GetProgramPath();
615             !source.Is(program.Mutf8())) {
616             continue;
617         }
618 
619         viewedReExport.push_back(item->GetETSImportDeclarations());
620 
621         auto specifiers = item->GetETSImportDeclarations()->Specifiers();
622         if (specifiers[0]->IsImportSpecifier()) {
623             if (!std::any_of(specifiers.begin(), specifiers.end(), [&imported](auto it) {
624                     return it->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8());
625                 })) {
626                 continue;
627             }
628         } else {
629             ArenaVector<parser::Program *> record =
630                 GetExternalProgram(item->GetETSImportDeclarations()->ResolvedSource()->Str(), importPath);
631             if (FindImportSpecifiersVariable(imported, record.front()->GlobalScope()->Bindings(), record) == nullptr) {
632                 continue;
633             }
634         }
635 
636         // NOTE: ttamas - Duplication check created error
637         implDecl = item->GetETSImportDeclarations();
638     }
639     return implDecl;
640 }
641 
ValidateImportVariable(varbinder::Variable * const var,const ir::ETSImportDeclaration * const import,const util::StringView & imported,const ir::StringLiteral * const importPath)642 void ETSBinder::ValidateImportVariable(varbinder::Variable *const var, const ir::ETSImportDeclaration *const import,
643                                        const util::StringView &imported, const ir::StringLiteral *const importPath)
644 {
645     if (var->Declaration()->Node()->IsDefaultExported()) {
646         ThrowError(importPath->Start(), "Use the default import syntax to import a default exported element");
647     }
648 
649     if (import->IsTypeKind() && !var->Declaration()->Node()->IsExportedType()) {
650         ThrowError(importPath->Start(),
651                    "Cannot import '" + imported.Mutf8() + "', imported type imports only exported types.");
652     }
653 
654     if (!var->Declaration()->Node()->IsExported() && !var->Declaration()->Node()->IsExportedType()) {
655         ThrowError(importPath->Start(), "Imported element not exported '" + var->Declaration()->Name().Mutf8() + "'");
656     }
657 }
658 
ImportLocalName(const ir::ImportSpecifier * importSpecifier,const ir::StringLiteral * importPath,util::StringView imported,ArenaVector<std::pair<util::StringView,util::StringView>> & importSpecifiers,GlobalScope * topScope)659 static util::StringView ImportLocalName(const ir::ImportSpecifier *importSpecifier, const ir::StringLiteral *importPath,
660                                         util::StringView imported,
661                                         ArenaVector<std::pair<util::StringView, util::StringView>> &importSpecifiers,
662                                         GlobalScope *topScope)
663 {
664     if (importSpecifier->Local() != nullptr) {
665         auto fnc = [&importPath, &imported](const auto &savedSpecifier) {
666             return importPath->Str() != savedSpecifier.first && imported == savedSpecifier.second;
667         };
668         if (!std::any_of(importSpecifiers.begin(), importSpecifiers.end(), fnc)) {
669             topScope->EraseBinding(imported);
670         }
671 
672         importSpecifiers.push_back(std::make_pair(importPath->Str(), imported));
673 
674         return importSpecifier->Local()->Name();
675     }
676 
677     return imported;
678 }
679 
DetectNameConflict(const util::StringView localName,Variable * const var,Variable * const otherVar,const ir::StringLiteral * const importPath,bool overloadAllowed)680 bool ETSBinder::DetectNameConflict(const util::StringView localName, Variable *const var, Variable *const otherVar,
681                                    const ir::StringLiteral *const importPath, bool overloadAllowed)
682 {
683     if (otherVar == nullptr || var == otherVar) {
684         return false;
685     }
686 
687     if (overloadAllowed && var->Declaration()->IsFunctionDecl() && otherVar->Declaration()->IsFunctionDecl()) {
688         AddOverloadFlag(Allocator(), util::Helpers::IsStdLib(Program()), var, otherVar);
689         return true;
690     }
691 
692     ThrowError(importPath->Start(), RedeclarationErrorMessageAssembler(var, otherVar, localName));
693 }
694 
AddImportSpecifiersToTopBindings(ir::AstNode * const specifier,const varbinder::Scope::VariableMap & globalBindings,const ir::ETSImportDeclaration * const import,const ArenaVector<parser::Program * > & recordRes,std::vector<ir::ETSImportDeclaration * > viewedReExport)695 bool ETSBinder::AddImportSpecifiersToTopBindings(ir::AstNode *const specifier,
696                                                  const varbinder::Scope::VariableMap &globalBindings,
697                                                  const ir::ETSImportDeclaration *const import,
698                                                  const ArenaVector<parser::Program *> &recordRes,
699                                                  std::vector<ir::ETSImportDeclaration *> viewedReExport)
700 {
701     if (!specifier->IsImportSpecifier()) {
702         return false;
703     }
704     const ir::StringLiteral *const importPath = import->Source();
705 
706     auto importSpecifier = specifier->AsImportSpecifier();
707     if (!importSpecifier->Imported()->IsIdentifier()) {
708         return true;
709     }
710 
711     auto imported = importSpecifier->Imported()->Name();
712 
713     for (auto const item : import->Specifiers()) {
714         if (item->IsImportSpecifier() && item->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8()) &&
715             !item->AsImportSpecifier()->Local()->Name().Is(item->AsImportSpecifier()->Imported()->Name().Mutf8())) {
716             imported = item->AsImportSpecifier()->Imported()->Name();
717         }
718     }
719 
720     util::StringView nameToSearchFor = FindNameInAliasMap(import->ResolvedSource()->Str(), imported);
721     if (nameToSearchFor.Empty()) {
722         nameToSearchFor = imported;
723     }
724 
725     auto *const var = FindImportSpecifiersVariable(nameToSearchFor, globalBindings, recordRes);
726     importSpecifier->Imported()->SetVariable(var);
727     importSpecifier->Local()->SetVariable(var);
728 
729     const auto localName = ImportLocalName(importSpecifier, importPath, imported, importSpecifiers_, TopScope());
730 
731     if (var == nullptr) {
732         ir::ETSImportDeclaration *implDecl = FindImportDeclInReExports(import, viewedReExport, imported, importPath);
733         if (implDecl != nullptr) {
734             AddSpecifiersToTopBindings(specifier, implDecl, implDecl->Source(), viewedReExport);
735             return true;
736         }
737 
738         ThrowError(importPath->Start(), "Cannot find imported element '" + imported.Mutf8() + "'");
739     }
740 
741     ValidateImportVariable(var, import, imported, importPath);
742 
743     auto varInGlobalClassScope = Program()->GlobalClassScope()->FindLocal(localName, ResolveBindingOptions::ALL);
744     auto previouslyImportedVariable = TopScope()->FindLocal(localName, ResolveBindingOptions::ALL);
745     if (DetectNameConflict(localName, var, varInGlobalClassScope, importPath, true) ||
746         DetectNameConflict(localName, var, previouslyImportedVariable, importPath, false)) {
747         return true;
748     }
749 
750     // The first part of the condition will be true, if something was given an alias when exported, but we try
751     // to import it using its original name.
752     if (nameToSearchFor == imported && var->Declaration()->Node()->HasExportAlias()) {
753         ThrowError(specifier->Start(), "Cannot find imported element '" + imported.Mutf8() + "'");
754     }
755 
756     InsertForeignBinding(specifier, import, localName, var);
757     return true;
758 }
759 
FindStaticBinding(const ArenaVector<parser::Program * > & recordRes,const ir::StringLiteral * const importPath)760 varbinder::Variable *ETSBinder::FindStaticBinding(const ArenaVector<parser::Program *> &recordRes,
761                                                   const ir::StringLiteral *const importPath)
762 {
763     auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); };
764     const auto &staticMethodBindings = recordRes.front()->GlobalClassScope()->StaticMethodScope()->Bindings();
765     auto result = std::find_if(staticMethodBindings.begin(), staticMethodBindings.end(), predicateFunc);
766     if (result == staticMethodBindings.end()) {
767         const auto &staticFieldBindings = recordRes.front()->GlobalClassScope()->StaticFieldScope()->Bindings();
768         result = std::find_if(staticFieldBindings.begin(), staticFieldBindings.end(), predicateFunc);
769         if (result == staticFieldBindings.end()) {
770             ThrowError(importPath->Start(), "Cannot find default imported element in the target");
771         }
772     }
773     return result->second;
774 }
775 
GetExternalProgram(const util::StringView & sourceName,const ir::StringLiteral * importPath)776 ArenaVector<parser::Program *> ETSBinder::GetExternalProgram(const util::StringView &sourceName,
777                                                              const ir::StringLiteral *importPath)
778 {
779     // NOTE: quick fix to make sure not to look for the global program among the external sources
780     if (sourceName.Compare(globalRecordTable_.Program()->AbsoluteName()) == 0) {
781         ArenaVector<parser::Program *> mainModule(Allocator()->Adapter());
782         mainModule.emplace_back(globalRecordTable_.Program());
783         return mainModule;
784     }
785 
786     auto programList = GetProgramList(sourceName);
787     if (programList.empty()) {
788         // NOTE(rsipka): it is not clear that an error should be thrown in these cases
789         if (ark::os::file::File::IsDirectory(sourceName.Mutf8())) {
790             ThrowError(importPath->Start(),
791                        "Cannot find index.[sts|ts] or package module in folder: " + importPath->Str().Mutf8());
792         }
793 
794         ThrowError(importPath->Start(), "Cannot find import: " + importPath->Str().Mutf8());
795     }
796 
797     return programList;
798 }
799 
AddSpecifiersToTopBindings(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import,ir::StringLiteral * path,std::vector<ir::ETSImportDeclaration * > viewedReExport)800 void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import,
801                                            ir::StringLiteral *path,
802                                            std::vector<ir::ETSImportDeclaration *> viewedReExport)
803 {
804     const ir::StringLiteral *const importPath = path;
805 
806     if (import->IsPureDynamic()) {
807         AddDynamicSpecifiersToTopBindings(specifier, import);
808         return;
809     }
810 
811     const util::StringView sourceName = import->ResolvedSource()->Str();
812 
813     auto record = GetExternalProgram(sourceName, importPath);
814     const auto *const importProgram = record.front();
815     const auto *const importGlobalScope = importProgram->GlobalScope();
816     const auto &globalBindings = importGlobalScope->Bindings();
817 
818     if (AddImportNamespaceSpecifiersToTopBindings(specifier, globalBindings, importProgram, importGlobalScope,
819                                                   import) ||
820         AddImportSpecifiersToTopBindings(specifier, globalBindings, import, record, std::move(viewedReExport))) {
821         return;
822     }
823 
824     ASSERT(specifier->IsImportDefaultSpecifier());
825     auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); };
826 
827     auto item = std::find_if(globalBindings.begin(), globalBindings.end(), predicateFunc);
828     if (item == globalBindings.end()) {
829         auto var = FindStaticBinding(record, importPath);
830         specifier->AsImportDefaultSpecifier()->Local()->SetVariable(var);
831         InsertForeignBinding(specifier, import, specifier->AsImportDefaultSpecifier()->Local()->Name(), var);
832         return;
833     }
834 
835     specifier->AsImportDefaultSpecifier()->Local()->SetVariable(item->second);
836     InsertForeignBinding(specifier, import, specifier->AsImportDefaultSpecifier()->Local()->Name(), item->second);
837 }
838 
HandleCustomNodes(ir::AstNode * childNode)839 void ETSBinder::HandleCustomNodes(ir::AstNode *childNode)
840 {
841     switch (childNode->Type()) {
842         case ir::AstNodeType::ETS_TYPE_REFERENCE: {
843             auto *typeRef = childNode->AsETSTypeReference();
844             auto *baseName = typeRef->BaseName();
845             ASSERT(baseName->IsReference());
846             // We allow to resolve following types in pure dynamic mode:
847             // import * as I from "@dynamic"
848             // let x : I.X.Y
849             bool allowDynamicNamespaces = typeRef->Part()->Name() != baseName;
850             LookupTypeReference(baseName, allowDynamicNamespaces);
851             LookupTypeArgumentReferences(typeRef);
852             break;
853         }
854         case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
855             BuildInterfaceDeclaration(childNode->AsTSInterfaceDeclaration());
856             break;
857         }
858         case ir::AstNodeType::TS_ENUM_DECLARATION: {
859             ResolveEnumDeclaration(childNode->AsTSEnumDeclaration());
860             break;
861         }
862         case ir::AstNodeType::EXPORT_NAMED_DECLARATION: {
863             break;
864         }
865         case ir::AstNodeType::ETS_IMPORT_DECLARATION: {
866             BuildImportDeclaration(childNode->AsETSImportDeclaration());
867             break;
868         }
869         case ir::AstNodeType::MEMBER_EXPRESSION: {
870             BuildMemberExpression(childNode->AsMemberExpression());
871             break;
872         }
873         case ir::AstNodeType::METHOD_DEFINITION: {
874             BuildMethodDefinition(childNode->AsMethodDefinition());
875             break;
876         }
877         case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
878             BuildETSNewClassInstanceExpression(childNode->AsETSNewClassInstanceExpression());
879             break;
880         }
881         case ir::AstNodeType::ETS_FUNCTION_TYPE: {
882             BuildSignatureDeclarationBaseParams(childNode);
883             break;
884         }
885         default: {
886             ResolveReferences(childNode);
887             break;
888         }
889     }
890 }
891 
BuildInternalName(ir::ScriptFunction * scriptFunc)892 bool ETSBinder::BuildInternalName(ir::ScriptFunction *scriptFunc)
893 {
894     const bool isExternal = recordTable_->IsExternal();
895     if (isExternal) {
896         scriptFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
897     }
898 
899     if (scriptFunc->IsArrow()) {
900         return true;
901     }
902 
903     auto *funcScope = scriptFunc->Scope();
904     funcScope->BindName(recordTable_->RecordName());
905 
906     bool compilable = scriptFunc->Body() != nullptr && !isExternal;
907     if (!compilable) {
908         recordTable_->Signatures().push_back(funcScope);
909     }
910 
911     return compilable;
912 }
913 
BuildInternalNameWithCustomRecordTable(ir::ScriptFunction * const scriptFunc,RecordTable * const recordTable)914 bool ETSBinder::BuildInternalNameWithCustomRecordTable(ir::ScriptFunction *const scriptFunc,
915                                                        RecordTable *const recordTable)
916 {
917     const bool isExternal = recordTable->IsExternal();
918     if (isExternal) {
919         scriptFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
920     }
921 
922     if (scriptFunc->IsArrow()) {
923         return true;
924     }
925 
926     auto *const funcScope = scriptFunc->Scope();
927     funcScope->BindName(recordTable->RecordName());
928 
929     const bool compilable = scriptFunc->Body() != nullptr && !isExternal;
930     if (!compilable) {
931         recordTable->Signatures().push_back(funcScope);
932     }
933 
934     return compilable;
935 }
936 
AddCompilableFunction(ir::ScriptFunction * func)937 void ETSBinder::AddCompilableFunction(ir::ScriptFunction *func)
938 {
939     if (func->IsArrow() || func->IsAsyncFunc()) {
940         return;
941     }
942 
943     AddCompilableFunctionScope(func->Scope());
944 }
945 
BuildFunctionName(const ir::ScriptFunction * func) const946 void ETSBinder::BuildFunctionName(const ir::ScriptFunction *func) const
947 {
948     auto *funcScope = func->Scope();
949 
950     std::stringstream ss;
951     ASSERT(func->IsArrow() || !funcScope->Name().Empty());
952     ss << (func->IsExternalOverload() ? funcScope->InternalName() : funcScope->Name())
953        << compiler::Signatures::METHOD_SEPARATOR;
954 
955     const auto *signature = func->Signature();
956 
957     if (func->IsStaticBlock()) {
958         ss << compiler::Signatures::CCTOR;
959     } else if (func->IsConstructor()) {
960         ss << compiler::Signatures::CTOR;
961     } else {
962         if (func->IsGetter()) {
963             ss << compiler::Signatures::GETTER_BEGIN;
964         } else if (func->IsSetter()) {
965             ss << compiler::Signatures::SETTER_BEGIN;
966         }
967         ss << util::Helpers::FunctionName(Allocator(), func);
968     }
969 
970     signature->ToAssemblerType(ss);
971 
972     util::UString internalName(ss.str(), Allocator());
973     funcScope->BindInternalName(internalName.View());
974 }
975 
InitImplicitThisParam()976 void ETSBinder::InitImplicitThisParam()
977 {
978     thisParam_ = Allocator()->New<ir::Identifier>("this", Allocator());
979 }
980 
BuildProgram()981 void ETSBinder::BuildProgram()
982 {
983     for (auto &[_, extPrograms] : Program()->ExternalSources()) {
984         (void)_;
985         for (auto *extProg : extPrograms) {
986             BuildExternalProgram(extProg);
987         }
988     }
989 
990     for (auto *defaultImport : defaultImports_) {
991         BuildImportDeclaration(defaultImport);
992     }
993 
994     auto &stmts = Program()->Ast()->Statements();
995     const auto etsGlobal = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
996         return stmt->IsClassDeclaration() &&
997                stmt->AsClassDeclaration()->Definition()->Ident()->Name().Is(compiler::Signatures::ETS_GLOBAL);
998     });
999     if (etsGlobal != stmts.end()) {
1000         const auto begin = std::find_if(stmts.rbegin(), stmts.rend(), [](const ir::Statement *stmt) {
1001                                return stmt->IsETSImportDeclaration() || stmt->IsETSPackageDeclaration();
1002                            }).base();
1003 
1004         const auto index = std::distance(begin, etsGlobal);
1005         std::rotate(begin, begin + index, begin + index + 1);
1006     }
1007 
1008     for (auto *stmt : stmts) {
1009         ResolveReference(stmt);
1010     }
1011 }
1012 
BuildExternalProgram(parser::Program * extProgram)1013 void ETSBinder::BuildExternalProgram(parser::Program *extProgram)
1014 {
1015     auto *savedProgram = Program();
1016     auto *savedRecordTable = recordTable_;
1017     auto *savedTopScope = TopScope();
1018 
1019     auto flags = Program()->VarBinder()->IsGenStdLib() ? RecordTableFlags::NONE : RecordTableFlags::EXTERNAL;
1020     auto *extRecordTable = Allocator()->New<RecordTable>(Allocator(), extProgram, flags);
1021     externalRecordTable_.insert({extProgram, extRecordTable});
1022 
1023     ResetTopScope(extProgram->GlobalScope());
1024     recordTable_ = extRecordTable;
1025     SetProgram(extProgram);
1026 
1027     BuildProgram();
1028 
1029     SetProgram(savedProgram);
1030     recordTable_ = savedRecordTable;
1031     ResetTopScope(savedTopScope);
1032 }
1033 
BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression * classInstance)1034 void ETSBinder::BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classInstance)
1035 {
1036     BoundContext boundCtx(recordTable_, classInstance->ClassDefinition());
1037     ResolveReference(classInstance->GetTypeRef());
1038 
1039     for (auto *arg : classInstance->GetArguments()) {
1040         ResolveReference(arg);
1041     }
1042 
1043     if (classInstance->ClassDefinition() == nullptr) {
1044         return;
1045     }
1046 
1047     ResolveReference(classInstance->ClassDefinition());
1048 }
1049 
BuildImportDeclaration(ir::ETSImportDeclaration * decl)1050 void ETSBinder::BuildImportDeclaration(ir::ETSImportDeclaration *decl)
1051 {
1052     if (decl->Source()->Str() == Program()->SourceFile().GetAbsolutePath()) {
1053         return;
1054     }
1055 
1056     const auto &specifiers = decl->Specifiers();
1057 
1058     for (auto specifier : specifiers) {
1059         AddSpecifiersToTopBindings(specifier, decl, decl->Source());
1060     }
1061 }
1062 
ImportGlobalPropertiesForNotDefaultedExports(varbinder::Variable * var,const util::StringView & name,const ir::ClassElement * classElement)1063 bool ETSBinder::ImportGlobalPropertiesForNotDefaultedExports(varbinder::Variable *var, const util::StringView &name,
1064                                                              const ir::ClassElement *classElement)
1065 {
1066     if (var->Declaration()->Node()->IsDefaultExported()) {
1067         return false;
1068     }
1069 
1070     auto variable = Program()->GlobalClassScope()->FindLocal(name, ResolveBindingOptions::ALL);
1071 
1072     bool isStdLib = util::Helpers::IsStdLib(Program());
1073     if (variable != nullptr && var != variable) {
1074         if (variable->Declaration()->IsFunctionDecl() && var->Declaration()->IsFunctionDecl()) {
1075             AddOverloadFlag(Allocator(), isStdLib, var, variable);
1076             return true;
1077         }
1078 
1079         ThrowError(classElement->Id()->Start(), RedeclarationErrorMessageAssembler(var, variable, name.Utf8()));
1080     }
1081 
1082     const auto insRes = TopScope()->InsertForeignBinding(name, var);
1083     if (!(!insRes.second && insRes.first != TopScope()->Bindings().end()) || !(insRes.first->second != var)) {
1084         return true;
1085     }
1086     if (insRes.first->second->Declaration()->IsFunctionDecl() && var->Declaration()->IsFunctionDecl()) {
1087         AddOverloadFlag(Allocator(), isStdLib, var, insRes.first->second);
1088         return true;
1089     }
1090 
1091     ThrowError(classElement->Id()->Start(), RedeclarationErrorMessageAssembler(var, insRes.first->second, name.Utf8()));
1092 }
1093 
ImportGlobalProperties(const ir::ClassDefinition * const classDef)1094 void ETSBinder::ImportGlobalProperties(const ir::ClassDefinition *const classDef)
1095 {
1096     const auto scopeCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope()->AsClassScope());
1097 
1098     for (const auto *const prop : classDef->Body()) {
1099         const auto *const classElement = prop->AsClassElement();
1100 
1101         if (classElement->IsClassStaticBlock()) {
1102             continue;
1103         }
1104 
1105         ASSERT(classElement->IsStatic());
1106         const auto &name = classElement->Id()->Name();
1107         auto *const var = scopeCtx.GetScope()->FindLocal(name, ResolveBindingOptions::ALL);
1108         ASSERT(var != nullptr);
1109 
1110         if (ImportGlobalPropertiesForNotDefaultedExports(var, name, classElement)) {
1111             return;
1112         }
1113     }
1114 }
1115 
DynamicImportDataForVar(const Variable * var) const1116 const DynamicImportData *ETSBinder::DynamicImportDataForVar(const Variable *var) const
1117 {
1118     auto it = dynamicImportVars_.find(var);
1119     if (it == dynamicImportVars_.cend()) {
1120         return nullptr;
1121     }
1122 
1123     return &it->second;
1124 }
1125 
IsDynamicModuleVariable(const Variable * var) const1126 bool ETSBinder::IsDynamicModuleVariable(const Variable *var) const
1127 {
1128     auto *data = DynamicImportDataForVar(var);
1129     if (data == nullptr) {
1130         return false;
1131     }
1132 
1133     return data->specifier->IsImportSpecifier();
1134 }
1135 
IsDynamicNamespaceVariable(const Variable * var) const1136 bool ETSBinder::IsDynamicNamespaceVariable(const Variable *var) const
1137 {
1138     auto *data = DynamicImportDataForVar(var);
1139     if (data == nullptr) {
1140         return false;
1141     }
1142 
1143     return data->specifier->IsImportNamespaceSpecifier();
1144 }
1145 
1146 }  // namespace ark::es2panda::varbinder
1147