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/objectExpression.h"
21 #include "ir/expressions/thisExpression.h"
22 #include "ir/expressions/typeofExpression.h"
23 #include "ir/expressions/memberExpression.h"
24 #include "ir/expressions/callExpression.h"
25 #include "ir/expressions/functionExpression.h"
26 #include "ir/base/methodDefinition.h"
27 #include "ir/base/scriptFunction.h"
28 #include "ir/base/classElement.h"
29 #include "ir/base/classDefinition.h"
30 #include "ir/base/classProperty.h"
31 #include "ir/base/classStaticBlock.h"
32 #include "ir/base/decorator.h"
33 #include "ir/statements/annotationDeclaration.h"
34 #include "ir/statements/blockStatement.h"
35 #include "ir/statements/classDeclaration.h"
36 #include "ir/statements/variableDeclarator.h"
37 #include "ir/statements/functionDeclaration.h"
38 #include "ir/statements/returnStatement.h"
39 #include "ir/ets/etsPrimitiveType.h"
40 #include "ir/ets/etsTypeReferencePart.h"
41 #include "ir/ets/etsNewClassInstanceExpression.h"
42 #include "ir/ets/etsTypeReference.h"
43 #include "ir/ets/etsFunctionType.h"
44 #include "ir/ets/etsNeverType.h"
45 #include "ir/ets/etsScript.h"
46 #include "ir/ets/etsImportDeclaration.h"
47 #include "ir/ts/tsInterfaceDeclaration.h"
48 #include "ir/ts/tsTypeParameterDeclaration.h"
49 #include "ir/ts/tsTypeParameterInstantiation.h"
50 #include "ir/ts/tsClassImplements.h"
51 #include "ir/ts/tsEnumDeclaration.h"
52 #include "ir/ts/tsEnumMember.h"
53 #include "ir/ts/tsInterfaceHeritage.h"
54 #include "ir/ts/tsInterfaceBody.h"
55 #include "ir/ts/tsFunctionType.h"
56 #include "ir/ts/tsQualifiedName.h"
57 #include "ir/module/importDefaultSpecifier.h"
58 #include "ir/module/importNamespaceSpecifier.h"
59 #include "ir/module/importDeclaration.h"
60 #include "ir/module/importSpecifier.h"
61 #include "ir/expressions/literals/stringLiteral.h"
62 #include "mem/arena_allocator.h"
63 #include "os/filesystem.h"
64 #include "recordTable.h"
65 #include "util/helpers.h"
66 #include "util/ustring.h"
67 #include "checker/ETSchecker.h"
68 #include "checker/types/type.h"
69 #include "checker/types/ets/types.h"
70 #include "evaluate/scopedDebugInfoPlugin.h"
71 #include "public/public.h"
72
73 namespace ark::es2panda::varbinder {
74
IdentifierAnalysis()75 void ETSBinder::IdentifierAnalysis()
76 {
77 ASSERT(Program()->Ast());
78 ASSERT(GetScope() == TopScope());
79 ASSERT(VarScope() == TopScope());
80
81 recordTable_->SetProgram(Program());
82 globalRecordTable_.SetClassDefinition(Program()->GlobalClass());
83 BuildProgram();
84
85 ASSERT(globalRecordTable_.ClassDefinition() == Program()->GlobalClass());
86 }
87
LookupTypeArgumentReferences(ir::ETSTypeReference * typeRef)88 void ETSBinder::LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef)
89 {
90 auto *iter = typeRef->Part();
91
92 while (iter != nullptr) {
93 if (iter->TypeParams() == nullptr) {
94 iter = iter->Previous();
95 continue;
96 }
97
98 ResolveReferences(iter->TypeParams());
99 iter = iter->Previous();
100 }
101 }
102
LookupTypeReference(ir::Identifier * ident,bool allowDynamicNamespaces)103 void ETSBinder::LookupTypeReference(ir::Identifier *ident, bool allowDynamicNamespaces)
104 {
105 const auto &name = ident->Name();
106 if (name == compiler::Signatures::UNDEFINED || name == compiler::Signatures::NULL_LITERAL ||
107 name == compiler::Signatures::READONLY_TYPE_NAME || name == compiler::Signatures::PARTIAL_TYPE_NAME ||
108 name == compiler::Signatures::REQUIRED_TYPE_NAME) {
109 return;
110 }
111 auto *iter = GetScope();
112
113 while (iter != nullptr) {
114 auto res = iter->Find(name, ResolveBindingOptions::DECLARATION | ResolveBindingOptions::TYPE_ALIASES);
115 if (res.variable == nullptr) {
116 break;
117 }
118
119 if (IsDynamicModuleVariable(res.variable)) {
120 ident->SetVariable(res.variable);
121 return;
122 }
123
124 if (allowDynamicNamespaces && IsDynamicNamespaceVariable(res.variable)) {
125 ident->SetVariable(res.variable);
126 return;
127 }
128
129 switch (res.variable->Declaration()->Node()->Type()) {
130 case ir::AstNodeType::CLASS_DECLARATION:
131 case ir::AstNodeType::CLASS_DEFINITION:
132 case ir::AstNodeType::STRUCT_DECLARATION:
133 case ir::AstNodeType::TS_ENUM_DECLARATION:
134 case ir::AstNodeType::TS_INTERFACE_DECLARATION:
135 case ir::AstNodeType::TS_TYPE_PARAMETER:
136 case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION:
137 case ir::AstNodeType::ANNOTATION_DECLARATION:
138 case ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER: {
139 ident->SetVariable(res.variable);
140 return;
141 }
142 default: {
143 iter = iter->Parent();
144 }
145 }
146 }
147
148 auto *checker = GetContext()->checker->AsETSChecker();
149 auto *debugInfoPlugin = checker->GetDebugInfoPlugin();
150 if (UNLIKELY(debugInfoPlugin)) {
151 auto *var = debugInfoPlugin->FindClass(ident);
152 if (var != nullptr) {
153 ident->SetVariable(var);
154 return;
155 }
156 // NOTE: search an imported module's name in case of 'import "file" as xxx'.
157 }
158
159 ThrowUnresolvableType(ident->Start(), name);
160 }
161
ResolveReferencesForScope(ir::AstNode const * const parent,Scope * const scope)162 void ETSBinder::ResolveReferencesForScope(ir::AstNode const *const parent, Scope *const scope)
163 {
164 parent->Iterate([this, scope](auto *node) { ResolveReferenceForScope(node, scope); });
165 }
166
ResolveReferenceForScope(ir::AstNode * const node,Scope * const scope)167 void ETSBinder::ResolveReferenceForScope(ir::AstNode *const node, Scope *const scope)
168 {
169 switch (node->Type()) {
170 case ir::AstNodeType::IDENTIFIER: {
171 auto *ident = node->AsIdentifier();
172 if (ident->Variable() != nullptr) {
173 break;
174 }
175 if (auto const res = scope->Find(ident->Name(), ResolveBindingOptions::ALL); res.variable != nullptr) {
176 ident->SetVariable(res.variable);
177 }
178 break;
179 }
180 case ir::AstNodeType::VARIABLE_DECLARATOR: {
181 auto scopeCtx = LexicalScope<Scope>::Enter(this, scope);
182 BuildVarDeclarator(node->AsVariableDeclarator());
183 break;
184 }
185 /* Maybe will be used
186 case ir::AstNodeType::BLOCK_STATEMENT: {
187 auto scope_ctx = LexicalScope<Scope>::Enter(this, node->AsBlockStatement()->Scope());
188 ResolveReferences(node);
189 break;
190 }
191 */
192 case ir::AstNodeType::BLOCK_EXPRESSION: {
193 auto scopeCtx = LexicalScope<Scope>::Enter(this, node->AsBlockExpression()->Scope());
194 ResolveReferences(node);
195 break;
196 }
197 default: {
198 ResolveReferencesForScope(node, scope);
199 break;
200 }
201 }
202 }
203
ResolveReferencesForScopeWithContext(ir::AstNode * node,Scope * scope)204 void ETSBinder::ResolveReferencesForScopeWithContext(ir::AstNode *node, Scope *scope)
205 {
206 auto lexScope = LexicalScope<Scope>::Enter(this, scope);
207 ResolveReference(node);
208 }
209
LookupIdentReference(ir::Identifier * ident)210 void ETSBinder::LookupIdentReference(ir::Identifier *ident)
211 {
212 const auto &name = ident->Name();
213 auto res = GetScope()->Find(name, ResolveBindingOptions::ALL);
214 if (res.level != 0) {
215 ASSERT(res.variable != nullptr);
216
217 auto *outerFunction = GetScope()->EnclosingVariableScope()->Node();
218
219 if ((!outerFunction->IsScriptFunction() || !outerFunction->AsScriptFunction()->IsArrow()) &&
220 !res.variable->IsGlobalVariable() && res.variable->HasFlag(VariableFlags::LOCAL) && res.level > 1) {
221 ThrowInvalidCapture(ident->Start(), name);
222 }
223 }
224
225 if (res.variable == nullptr) {
226 return;
227 }
228
229 if (ident->IsReference(Extension()) && res.variable->Declaration()->IsLetOrConstDecl() &&
230 !res.variable->HasFlag(VariableFlags::INITIALIZED)) {
231 ThrowTDZ(ident->Start(), name);
232 }
233 }
234
BuildClassProperty(const ir::ClassProperty * prop)235 void ETSBinder::BuildClassProperty(const ir::ClassProperty *prop)
236 {
237 ResolveReferences(prop);
238 }
239
BuildETSTypeReference(ir::ETSTypeReference * typeRef)240 void ETSBinder::BuildETSTypeReference(ir::ETSTypeReference *typeRef)
241 {
242 auto *baseName = typeRef->BaseName();
243 ASSERT(baseName->IsReference(Extension()));
244
245 // We allow to resolve following types in pure dynamic mode:
246 // import * as I from "@dynamic"
247 // let x : I.X.Y
248 bool allowDynamicNamespaces = typeRef->Part()->Name() != baseName;
249 LookupTypeReference(baseName, allowDynamicNamespaces);
250 LookupTypeArgumentReferences(typeRef);
251 }
252
BuildObjectExpression(ir::ObjectExpression * obj)253 void ETSBinder::BuildObjectExpression(ir::ObjectExpression *obj)
254 {
255 for (auto *it : obj->Decorators()) {
256 ResolveReference(it);
257 }
258
259 // NOTE: when we try to resolve references for Object Expression
260 // we visit properties, example:
261 // class C { x : boolean }
262 // let x: C = { x: true }
263 //
264 // However we visit Object Expression with _outer_ scope, not class scope.
265 // That means that varbinder will try to resolve `x` as `x` from outer scope, _not from the class scope_.
266 // The following code will skip resolving LHS of the property.
267 // We can do it because currently LHS is still checked in the `ETSAnalyzer::CheckObjectExprProps` function.
268 for (auto expr : obj->Properties()) {
269 if (expr->IsProperty()) {
270 auto *prop = expr->AsProperty();
271 ResolveReference(prop->Value());
272 }
273 }
274
275 if (obj->TypeAnnotation() != nullptr) {
276 ResolveReference(obj->TypeAnnotation());
277 }
278 }
279
InitializeInterfaceIdent(ir::TSInterfaceDeclaration * decl)280 void ETSBinder::InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl)
281 {
282 auto res = GetScope()->Find(decl->Id()->Name());
283
284 ASSERT(res.variable && res.variable->Declaration()->IsInterfaceDecl());
285 res.variable->AddFlag(VariableFlags::INITIALIZED);
286 decl->Id()->SetVariable(res.variable);
287 }
288
ResolveEnumDeclaration(ir::TSEnumDeclaration * enumDecl)289 void ETSBinder::ResolveEnumDeclaration(ir::TSEnumDeclaration *enumDecl)
290 {
291 auto enumScopeCtx = LexicalScope<LocalScope>::Enter(this, enumDecl->Scope());
292
293 for (auto *member : enumDecl->Members()) {
294 ResolveReference(member);
295 }
296 }
297
ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration * decl)298 void ETSBinder::ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl)
299 {
300 auto boundCtx = BoundContext(recordTable_, decl);
301
302 for (auto *extend : decl->Extends()) {
303 ResolveReference(extend);
304 }
305
306 auto scopeCtx = LexicalScope<ClassScope>::Enter(this, decl->Scope()->AsClassScope());
307
308 for (auto *stmt : decl->Body()->Body()) {
309 if (!stmt->IsClassProperty()) {
310 continue;
311 }
312
313 ResolveReference(stmt);
314
315 auto fieldVar =
316 ResolvePropertyReference(stmt->AsClassProperty(), decl->Scope()->AsClassScope())
317 ->FindLocal(stmt->AsClassProperty()->Id()->Name(), varbinder::ResolveBindingOptions::BINDINGS);
318 fieldVar->AddFlag(VariableFlags::INITIALIZED);
319 }
320
321 for (auto *stmt : decl->Body()->Body()) {
322 if (stmt->IsClassProperty()) {
323 continue;
324 }
325 ResolveReference(stmt);
326 }
327 }
328
BuildInterfaceDeclaration(ir::TSInterfaceDeclaration * decl)329 void ETSBinder::BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl)
330 {
331 if (decl->TypeParams() != nullptr) {
332 auto typeParamScopeCtx = LexicalScope<LocalScope>::Enter(this, decl->TypeParams()->Scope());
333 ResolveReferences(decl->TypeParams());
334 ResolveInterfaceDeclaration(decl);
335 return;
336 }
337
338 ResolveInterfaceDeclaration(decl);
339 }
340
BuildMethodDefinition(ir::MethodDefinition * methodDef)341 void ETSBinder::BuildMethodDefinition(ir::MethodDefinition *methodDef)
342 {
343 if (methodDef->Function()->TypeParams() != nullptr) {
344 auto scopeCtx = LexicalScope<LocalScope>::Enter(this, methodDef->Function()->TypeParams()->Scope());
345 ResolveReferences(methodDef->Function()->TypeParams());
346 }
347 ResolveMethodDefinition(methodDef);
348 }
349
BuildAnnotationDeclaration(ir::AnnotationDeclaration * annoDecl)350 void ETSBinder::BuildAnnotationDeclaration(ir::AnnotationDeclaration *annoDecl)
351 {
352 auto boundCtx = BoundContext(recordTable_, annoDecl);
353 if (annoDecl->Expr()->IsIdentifier()) {
354 LookupTypeReference(annoDecl->AsAnnotationDeclaration()->Expr()->AsIdentifier(), false);
355 } else {
356 ResolveReference(annoDecl->Expr());
357 }
358 auto scopeCtx = LexicalScope<LocalScope>::Enter(this, annoDecl->Scope());
359 for (auto *property : annoDecl->Properties()) {
360 ResolveReference(property);
361 }
362 }
363
BuildAnnotationUsage(ir::AnnotationUsage * annoUsage)364 void ETSBinder::BuildAnnotationUsage(ir::AnnotationUsage *annoUsage)
365 {
366 if (annoUsage->Expr()->IsIdentifier()) {
367 LookupTypeReference(annoUsage->AsAnnotationUsage()->Expr()->AsIdentifier(), false);
368 } else {
369 ResolveReference(annoUsage->Expr());
370 }
371
372 for (auto *property : annoUsage->Properties()) {
373 ResolveReference(property);
374 }
375 }
376
ResolveMethodDefinition(ir::MethodDefinition * methodDef)377 void ETSBinder::ResolveMethodDefinition(ir::MethodDefinition *methodDef)
378 {
379 methodDef->ResolveReferences([this](auto *childNode) { ResolveReference(childNode); });
380
381 auto *func = methodDef->Function();
382 for (auto *anno : func->Annotations()) {
383 ResolveReference(anno);
384 }
385 if (methodDef->IsStatic() || func->IsStaticBlock()) {
386 return;
387 }
388
389 auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, func->Scope()->ParamScope());
390
391 auto params = func->Scope()->ParamScope()->Params();
392 if (!params.empty() && params.front()->Name() == MANDATORY_PARAM_THIS) {
393 return; // Implicit this parameter is already inserted by ResolveReferences(), don't insert it twice.
394 }
395
396 auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS);
397 thisParam->Declaration()->BindNode(thisParam_);
398 }
399
BuildMemberExpression(ir::MemberExpression * memberExpr)400 void ETSBinder::BuildMemberExpression(ir::MemberExpression *memberExpr)
401 {
402 ResolveReference(memberExpr->Object());
403
404 if (memberExpr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
405 ResolveReference(memberExpr->Property());
406 }
407 }
408
BuildClassDefinition(ir::ClassDefinition * classDef)409 void ETSBinder::BuildClassDefinition(ir::ClassDefinition *classDef)
410 {
411 auto boundCtx = BoundContext(recordTable_, classDef);
412
413 if (classDef->TypeParams() != nullptr) {
414 auto scopeCtx = LexicalScope<LocalScope>::Enter(this, classDef->TypeParams()->Scope());
415 ResolveReferences(classDef->TypeParams());
416 BuildClassDefinitionImpl(classDef);
417 return;
418 }
419
420 BuildClassDefinitionImpl(classDef);
421 }
422
ResolvePropertyReference(ir::ClassProperty * prop,ClassScope * scope)423 LocalScope *ETSBinder::ResolvePropertyReference(ir::ClassProperty *prop, ClassScope *scope)
424 {
425 ResolveReferences(prop);
426
427 if (prop->IsStatic()) {
428 return scope->StaticFieldScope();
429 }
430
431 return scope->InstanceFieldScope();
432 }
433
BuildClassDefinitionImpl(ir::ClassDefinition * classDef)434 void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *classDef)
435 {
436 auto classCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope()->AsClassScope());
437
438 if (classDef->Super() != nullptr) {
439 ResolveReference(classDef->Super());
440 }
441
442 for (auto *impl : classDef->Implements()) {
443 ResolveReference(impl);
444 }
445 for (auto *anno : classDef->Annotations()) {
446 ResolveReference(anno);
447 }
448
449 for (auto *stmt : classDef->Body()) {
450 if (!stmt->IsClassProperty()) {
451 continue;
452 }
453
454 auto fieldScope = ResolvePropertyReference(stmt->AsClassProperty(), classDef->Scope()->AsClassScope());
455 auto fieldName = stmt->AsClassProperty()->Id()->Name();
456 auto fieldVar = fieldScope->FindLocal(fieldName, varbinder::ResolveBindingOptions::BINDINGS);
457 fieldVar->AddFlag(VariableFlags::INITIALIZED);
458 if ((fieldVar->Declaration()->IsConstDecl() || fieldVar->Declaration()->IsReadonlyDecl()) &&
459 stmt->AsClassProperty()->Value() == nullptr) {
460 fieldVar->AddFlag(VariableFlags::EXPLICIT_INIT_REQUIRED);
461 }
462 }
463
464 for (auto *stmt : classDef->Body()) {
465 if (stmt->IsClassProperty()) {
466 continue;
467 }
468 ResolveReference(stmt);
469 }
470 }
471
AddFunctionThisParam(ir::ScriptFunction * func)472 void ETSBinder::AddFunctionThisParam(ir::ScriptFunction *func)
473 {
474 auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, func->Scope()->ParamScope());
475 auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS);
476 thisParam->Declaration()->BindNode(thisParam_);
477 }
478
BuildProxyMethod(ir::ScriptFunction * func,const util::StringView & containingClassName,bool isExternal)479 void ETSBinder::BuildProxyMethod(ir::ScriptFunction *func, const util::StringView &containingClassName, bool isExternal)
480 {
481 ASSERT(!containingClassName.Empty());
482 func->Scope()->BindName(containingClassName);
483
484 if (!func->IsAsyncFunc() && !isExternal) {
485 Functions().push_back(func->Scope());
486 }
487 }
488
AddDynamicSpecifiersToTopBindings(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import)489 void ETSBinder::AddDynamicSpecifiersToTopBindings(ir::AstNode *const specifier,
490 const ir::ETSImportDeclaration *const import)
491 {
492 const auto name = [specifier]() {
493 if (specifier->IsImportNamespaceSpecifier()) {
494 return specifier->AsImportNamespaceSpecifier()->Local()->Name();
495 }
496
497 return specifier->AsImportSpecifier()->Local()->Name();
498 }();
499
500 ASSERT(GetScope()->Find(name, ResolveBindingOptions::DECLARATION).variable != nullptr);
501 auto specDecl = GetScope()->Find(name, ResolveBindingOptions::DECLARATION);
502 dynamicImportVars_.emplace(specDecl.variable, DynamicImportData {import, specifier, specDecl.variable});
503
504 if (specifier->IsImportSpecifier()) {
505 auto importSpecifier = specifier->AsImportSpecifier();
506 importSpecifier->Imported()->SetVariable(specDecl.variable);
507 importSpecifier->Local()->SetVariable(specDecl.variable);
508 }
509 }
510
InsertForeignBinding(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import,const util::StringView & name,Variable * var)511 void ETSBinder::InsertForeignBinding(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import,
512 const util::StringView &name, Variable *var)
513 {
514 if (import->Language().IsDynamic()) {
515 dynamicImportVars_.emplace(var, DynamicImportData {import, specifier, var});
516 }
517
518 TopScope()->InsertForeignBinding(name, var);
519 }
520
RedeclarationErrorMessageAssembler(const Variable * const var,const Variable * const variable,util::StringView localName)521 std::string RedeclarationErrorMessageAssembler(const Variable *const var, const Variable *const variable,
522 util::StringView localName)
523 {
524 auto type = var->Declaration()->Node()->IsClassDefinition() ? "Class '"
525 : var->Declaration()->IsFunctionDecl() ? "Function '"
526 : "Variable '";
527 auto str = util::Helpers::AppendAll(type, localName.Utf8(), "'");
528 str += variable->Declaration()->Type() == var->Declaration()->Type() ? " is already defined."
529 : " is already defined with different type.";
530
531 return str;
532 }
533
GetPackageName(varbinder::Variable * var)534 static const util::StringView &GetPackageName(varbinder::Variable *var)
535 {
536 Scope *scope = var->GetScope();
537
538 while (scope->Parent() != nullptr) {
539 scope = scope->Parent();
540 }
541
542 ASSERT(scope->Node()->IsETSScript());
543
544 return scope->Node()->AsETSScript()->Program()->ModuleName();
545 }
546
AddOverloadFlag(ArenaAllocator * allocator,bool isStdLib,varbinder::Variable * importedVar,varbinder::Variable * variable)547 void AddOverloadFlag(ArenaAllocator *allocator, bool isStdLib, varbinder::Variable *importedVar,
548 varbinder::Variable *variable)
549 {
550 auto *const currentNode = variable->Declaration()->Node()->AsMethodDefinition();
551 auto *const method = importedVar->Declaration()->Node()->AsMethodDefinition();
552
553 // Necessary because stdlib and escompat handled as same package, it can be removed after fixing package handling
554 if (isStdLib && (GetPackageName(importedVar) != GetPackageName(variable))) {
555 return;
556 }
557
558 if (!method->Overloads().empty() && !method->HasOverload(currentNode)) {
559 method->AddOverload(currentNode);
560 currentNode->Function()->Id()->SetVariable(importedVar);
561 currentNode->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
562 currentNode->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD);
563 util::UString newInternalName(currentNode->Function()->Scope()->Name(), allocator);
564 currentNode->Function()->Scope()->BindInternalName(newInternalName.View());
565 return;
566 }
567
568 if (!currentNode->HasOverload(method)) {
569 currentNode->AddOverload(method);
570 method->Function()->Id()->SetVariable(variable);
571 method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
572 method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD);
573 util::UString newInternalName(method->Function()->Scope()->Name(), allocator);
574 method->Function()->Scope()->BindInternalName(newInternalName.View());
575 }
576 }
577
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)578 void ETSBinder::ImportAllForeignBindings(ir::AstNode *const specifier,
579 const varbinder::Scope::VariableMap &globalBindings,
580 const parser::Program *const importProgram,
581 const varbinder::GlobalScope *const importGlobalScope,
582 const ir::ETSImportDeclaration *const import)
583 {
584 for (const auto [bindingName, var] : globalBindings) {
585 if (bindingName.Is(compiler::Signatures::ETS_GLOBAL)) {
586 const auto *const classDef = var->Declaration()->Node()->AsClassDeclaration()->Definition();
587 ImportGlobalProperties(classDef);
588 continue;
589 }
590
591 if (!importGlobalScope->IsForeignBinding(bindingName) && !var->Declaration()->Node()->IsDefaultExported() &&
592 (var->AsLocalVariable()->Declaration()->Node()->IsExported() ||
593 var->AsLocalVariable()->Declaration()->Node()->IsExportedType())) {
594 auto variable = Program()->GlobalClassScope()->FindLocal(bindingName, ResolveBindingOptions::ALL);
595 if (variable != nullptr && var != variable && variable->Declaration()->IsFunctionDecl() &&
596 var->Declaration()->IsFunctionDecl()) {
597 bool isStdLib = util::Helpers::IsStdLib(Program());
598 AddOverloadFlag(Allocator(), isStdLib, var, variable);
599 continue;
600 }
601 if (variable != nullptr && var != variable) {
602 ThrowError(import->Source()->Start(), RedeclarationErrorMessageAssembler(var, variable, bindingName));
603 }
604 InsertForeignBinding(specifier, import, bindingName, var);
605 }
606 }
607
608 for (const auto [bindingName, var] : importProgram->GlobalClassScope()->StaticMethodScope()->Bindings()) {
609 if (!var->Declaration()->Node()->IsDefaultExported()) {
610 InsertForeignBinding(specifier, import, bindingName, var);
611 }
612 }
613
614 for (const auto [bindingName, var] : importProgram->GlobalClassScope()->StaticFieldScope()->Bindings()) {
615 if (!var->Declaration()->Node()->IsDefaultExported()) {
616 InsertForeignBinding(specifier, import, bindingName, var);
617 }
618 }
619 }
620
ReexportPathMatchesImportPath(const ir::ETSReExportDeclaration * const reexport,const ir::ETSImportDeclaration * const import) const621 bool ETSBinder::ReexportPathMatchesImportPath(const ir::ETSReExportDeclaration *const reexport,
622 const ir::ETSImportDeclaration *const import) const
623 {
624 auto importSource = import->ResolvedSource()->Str();
625 auto reexportSource = reexport->GetProgramPath();
626 return importSource == reexportSource;
627 }
628
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)629 bool ETSBinder::AddImportNamespaceSpecifiersToTopBindings(ir::AstNode *const specifier,
630 const varbinder::Scope::VariableMap &globalBindings,
631 const parser::Program *const importProgram,
632 const varbinder::GlobalScope *const importGlobalScope,
633 const ir::ETSImportDeclaration *const import)
634 {
635 if (!specifier->IsImportNamespaceSpecifier()) {
636 return false;
637 }
638 const auto *const namespaceSpecifier = specifier->AsImportNamespaceSpecifier();
639
640 if (namespaceSpecifier->Local()->Name().Empty()) {
641 ImportAllForeignBindings(specifier, globalBindings, importProgram, importGlobalScope, import);
642 }
643
644 for (auto item : ReExportImports()) {
645 // NOTE(rsipka): this should be refactored or eliminated
646 if (!ReexportPathMatchesImportPath(item, import)) {
647 continue;
648 }
649
650 for (auto it : item->GetETSImportDeclarations()->Specifiers()) {
651 if (it->IsImportNamespaceSpecifier() && !namespaceSpecifier->Local()->Name().Empty()) {
652 continue;
653 }
654
655 AddSpecifiersToTopBindings(it, item->GetETSImportDeclarations(),
656 item->GetETSImportDeclarations()->Source());
657 }
658 }
659
660 return true;
661 }
662
FindImportSpecifiersVariable(const util::StringView & imported,const varbinder::Scope::VariableMap & globalBindings,const ArenaVector<parser::Program * > & recordRes)663 Variable *ETSBinder::FindImportSpecifiersVariable(const util::StringView &imported,
664 const varbinder::Scope::VariableMap &globalBindings,
665 const ArenaVector<parser::Program *> &recordRes)
666 {
667 auto foundVar = globalBindings.find(imported);
668 if (foundVar == globalBindings.end()) {
669 const auto &staticMethodBindings = recordRes.front()->GlobalClassScope()->StaticMethodScope()->Bindings();
670 foundVar = staticMethodBindings.find(imported);
671 if (foundVar != staticMethodBindings.end()) {
672 return foundVar->second;
673 }
674 bool found = false;
675 for (auto res : recordRes) {
676 const auto &staticFieldBindings = res->GlobalClassScope()->StaticFieldScope()->Bindings();
677 foundVar = staticFieldBindings.find(imported);
678 if (foundVar != staticFieldBindings.end()) {
679 found = true;
680 foundVar->second->AsLocalVariable()->AddFlag(VariableFlags::INITIALIZED);
681 break;
682 }
683 }
684 if (!found) {
685 return nullptr;
686 }
687 }
688
689 return foundVar->second;
690 }
691
FindImportDeclInReExports(const ir::ETSImportDeclaration * const import,std::vector<ir::ETSImportDeclaration * > & viewedReExport,const util::StringView & imported,const ir::StringLiteral * const importPath)692 ir::ETSImportDeclaration *ETSBinder::FindImportDeclInReExports(const ir::ETSImportDeclaration *const import,
693 std::vector<ir::ETSImportDeclaration *> &viewedReExport,
694 const util::StringView &imported,
695 const ir::StringLiteral *const importPath)
696 {
697 ir::ETSImportDeclaration *implDecl = nullptr;
698 for (auto item : ReExportImports()) {
699 if (!ReexportPathMatchesImportPath(item, import)) {
700 continue;
701 }
702
703 viewedReExport.push_back(item->GetETSImportDeclarations());
704
705 auto specifiers = item->GetETSImportDeclarations()->Specifiers();
706 if (specifiers[0]->IsImportSpecifier()) {
707 if (!std::any_of(specifiers.begin(), specifiers.end(), [&imported](auto it) {
708 return it->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8());
709 })) {
710 continue;
711 }
712 implDecl = item->GetETSImportDeclarations();
713 } else {
714 ArenaVector<parser::Program *> record =
715 GetExternalProgram(item->GetETSImportDeclarations()->ResolvedSource()->Str(), importPath);
716 auto *const var = FindImportSpecifiersVariable(imported, record.front()->GlobalScope()->Bindings(), record);
717 if (var != nullptr) {
718 implDecl = item->GetETSImportDeclarations();
719 continue;
720 }
721 auto reExportImport = item->GetETSImportDeclarations();
722 auto reExportImportPath = reExportImport->Source();
723 auto implDeclOrNullptr =
724 FindImportDeclInReExports(reExportImport, viewedReExport, imported, reExportImportPath);
725 if (implDeclOrNullptr != nullptr) {
726 implDecl = implDeclOrNullptr;
727 }
728 }
729 }
730 return implDecl;
731 }
732
ValidateImportVariable(varbinder::Variable * const var,const ir::ETSImportDeclaration * const import,const util::StringView & imported,const ir::StringLiteral * const importPath)733 void ETSBinder::ValidateImportVariable(varbinder::Variable *const var, const ir::ETSImportDeclaration *const import,
734 const util::StringView &imported, const ir::StringLiteral *const importPath)
735 {
736 if (var->Declaration()->Node()->IsDefaultExported()) {
737 ThrowError(importPath->Start(), "Use the default import syntax to import a default exported element");
738 }
739
740 if (import->IsTypeKind() && !var->Declaration()->Node()->IsExportedType()) {
741 ThrowError(importPath->Start(),
742 "Cannot import '" + imported.Mutf8() + "', imported type imports only exported types.");
743 }
744
745 if (!var->Declaration()->Node()->IsExported() && !var->Declaration()->Node()->IsExportedType()) {
746 ThrowError(importPath->Start(), "Imported element not exported '" + var->Declaration()->Name().Mutf8() + "'");
747 }
748 }
749
ImportLocalName(const ir::ImportSpecifier * importSpecifier,const ir::StringLiteral * importPath,util::StringView imported,ArenaVector<std::pair<util::StringView,util::StringView>> & importSpecifiers,GlobalScope * topScope)750 static util::StringView ImportLocalName(const ir::ImportSpecifier *importSpecifier, const ir::StringLiteral *importPath,
751 util::StringView imported,
752 ArenaVector<std::pair<util::StringView, util::StringView>> &importSpecifiers,
753 GlobalScope *topScope)
754 {
755 if (importSpecifier->Local() != nullptr) {
756 auto fnc = [&importPath, &imported](const auto &savedSpecifier) {
757 return importPath->Str() != savedSpecifier.first && imported == savedSpecifier.second;
758 };
759 if (!std::any_of(importSpecifiers.begin(), importSpecifiers.end(), fnc)) {
760 topScope->EraseBinding(imported);
761 }
762
763 importSpecifiers.push_back(std::make_pair(importPath->Str(), imported));
764
765 return importSpecifier->Local()->Name();
766 }
767
768 return imported;
769 }
770
DetectNameConflict(const util::StringView localName,Variable * const var,Variable * const otherVar,const ir::StringLiteral * const importPath,bool overloadAllowed)771 bool ETSBinder::DetectNameConflict(const util::StringView localName, Variable *const var, Variable *const otherVar,
772 const ir::StringLiteral *const importPath, bool overloadAllowed)
773 {
774 if (otherVar == nullptr || var == otherVar) {
775 return false;
776 }
777
778 if (overloadAllowed && var->Declaration()->IsFunctionDecl() && otherVar->Declaration()->IsFunctionDecl()) {
779 AddOverloadFlag(Allocator(), util::Helpers::IsStdLib(Program()), var, otherVar);
780 return true;
781 }
782
783 bool isAmbient = var->Declaration()->Node()->IsDeclare() && !otherVar->Declaration()->Node()->IsDeclare();
784 if (isAmbient) {
785 return false;
786 }
787
788 ThrowError(importPath->Start(), RedeclarationErrorMessageAssembler(var, otherVar, localName));
789 }
790
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)791 bool ETSBinder::AddImportSpecifiersToTopBindings(ir::AstNode *const specifier,
792 const varbinder::Scope::VariableMap &globalBindings,
793 const ir::ETSImportDeclaration *const import,
794 const ArenaVector<parser::Program *> &recordRes,
795 std::vector<ir::ETSImportDeclaration *> viewedReExport)
796 {
797 if (!specifier->IsImportSpecifier()) {
798 return false;
799 }
800 const ir::StringLiteral *const importPath = import->Source();
801
802 auto importSpecifier = specifier->AsImportSpecifier();
803 if (!importSpecifier->Imported()->IsIdentifier()) {
804 return true;
805 }
806
807 auto imported = importSpecifier->Imported()->Name();
808
809 for (auto const item : import->Specifiers()) {
810 if (item->IsImportSpecifier() && item->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8()) &&
811 !item->AsImportSpecifier()->Local()->Name().Is(item->AsImportSpecifier()->Imported()->Name().Mutf8())) {
812 imported = item->AsImportSpecifier()->Imported()->Name();
813 }
814 }
815
816 util::StringView nameToSearchFor = FindNameInAliasMap(import->ResolvedSource()->Str(), imported);
817 if (nameToSearchFor.Empty()) {
818 nameToSearchFor = imported;
819 }
820
821 auto *const var = FindImportSpecifiersVariable(nameToSearchFor, globalBindings, recordRes);
822 importSpecifier->Imported()->SetVariable(var);
823 importSpecifier->Local()->SetVariable(var);
824
825 const auto localName = ImportLocalName(importSpecifier, importPath, imported, importSpecifiers_, TopScope());
826
827 if (var == nullptr) {
828 ir::ETSImportDeclaration *implDecl = FindImportDeclInReExports(import, viewedReExport, imported, importPath);
829 if (implDecl != nullptr) {
830 AddSpecifiersToTopBindings(specifier, implDecl, implDecl->Source(), viewedReExport);
831 return true;
832 }
833
834 ThrowError(importPath->Start(), "Cannot find imported element '" + imported.Mutf8() + "'");
835 }
836
837 ValidateImportVariable(var, import, imported, importPath);
838
839 auto varInGlobalClassScope = Program()->GlobalClassScope()->FindLocal(localName, ResolveBindingOptions::ALL);
840 auto previouslyImportedVariable = TopScope()->FindLocal(localName, ResolveBindingOptions::ALL);
841 if (DetectNameConflict(localName, var, varInGlobalClassScope, importPath, true) ||
842 DetectNameConflict(localName, var, previouslyImportedVariable, importPath, false)) {
843 return true;
844 }
845
846 if (var->Declaration()->Node()->IsAnnotationDeclaration() &&
847 var->Declaration()->Node()->AsAnnotationDeclaration()->GetBaseName()->Name() != localName) {
848 ThrowError(importPath->Start(), "Can not rename annotation '" + var->Declaration()->Name().Mutf8() +
849 "' in export or import statements.");
850 }
851
852 // The first part of the condition will be true, if something was given an alias when exported, but we try
853 // to import it using its original name.
854 if (nameToSearchFor == imported && var->Declaration()->Node()->HasExportAlias()) {
855 ThrowError(specifier->Start(), "Cannot find imported element '" + imported.Mutf8() + "'");
856 }
857
858 InsertForeignBinding(specifier, import, localName, var);
859 return true;
860 }
861
FindStaticBinding(const ArenaVector<parser::Program * > & recordRes,const ir::StringLiteral * const importPath)862 varbinder::Variable *ETSBinder::FindStaticBinding(const ArenaVector<parser::Program *> &recordRes,
863 const ir::StringLiteral *const importPath)
864 {
865 auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); };
866 const auto &staticMethodBindings = recordRes.front()->GlobalClassScope()->StaticMethodScope()->Bindings();
867 auto result = std::find_if(staticMethodBindings.begin(), staticMethodBindings.end(), predicateFunc);
868 if (result == staticMethodBindings.end()) {
869 const auto &staticFieldBindings = recordRes.front()->GlobalClassScope()->StaticFieldScope()->Bindings();
870 result = std::find_if(staticFieldBindings.begin(), staticFieldBindings.end(), predicateFunc);
871 if (result == staticFieldBindings.end()) {
872 ThrowError(importPath->Start(), "Cannot find default imported element in the target");
873 }
874 }
875 return result->second;
876 }
877
GetExternalProgram(const util::StringView & sourceName,const ir::StringLiteral * importPath)878 ArenaVector<parser::Program *> ETSBinder::GetExternalProgram(const util::StringView &sourceName,
879 const ir::StringLiteral *importPath)
880 {
881 // NOTE: quick fix to make sure not to look for the global program among the external sources
882 if (sourceName.Compare(globalRecordTable_.Program()->AbsoluteName()) == 0) {
883 ArenaVector<parser::Program *> mainModule(Allocator()->Adapter());
884 mainModule.emplace_back(globalRecordTable_.Program());
885 return mainModule;
886 }
887
888 auto programList = GetProgramList(sourceName);
889 if (programList.empty()) {
890 // NOTE(rsipka): it is not clear that an error should be thrown in these cases
891 if (ark::os::file::File::IsDirectory(sourceName.Mutf8())) {
892 ThrowError(importPath->Start(),
893 "Cannot find index.[sts|ts] or package module in folder: " + importPath->Str().Mutf8());
894 }
895
896 ThrowError(importPath->Start(), "Cannot find import: " + importPath->Str().Mutf8());
897 }
898
899 return programList;
900 }
901
AddSpecifiersToTopBindings(ir::AstNode * const specifier,const ir::ETSImportDeclaration * const import,ir::StringLiteral * path,std::vector<ir::ETSImportDeclaration * > viewedReExport)902 void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import,
903 ir::StringLiteral *path,
904 std::vector<ir::ETSImportDeclaration *> viewedReExport)
905 {
906 const ir::StringLiteral *const importPath = path;
907
908 if (import->IsPureDynamic()) {
909 AddDynamicSpecifiersToTopBindings(specifier, import);
910 return;
911 }
912
913 const util::StringView sourceName = import->ResolvedSource()->Str();
914
915 auto record = GetExternalProgram(sourceName, importPath);
916 const auto *const importProgram = record.front();
917 const auto *const importGlobalScope = importProgram->GlobalScope();
918 const auto &globalBindings = importGlobalScope->Bindings();
919
920 if (AddImportNamespaceSpecifiersToTopBindings(specifier, globalBindings, importProgram, importGlobalScope,
921 import) ||
922 AddImportSpecifiersToTopBindings(specifier, globalBindings, import, record, std::move(viewedReExport))) {
923 return;
924 }
925
926 ASSERT(specifier->IsImportDefaultSpecifier());
927 auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); };
928
929 auto item = std::find_if(globalBindings.begin(), globalBindings.end(), predicateFunc);
930 if (item == globalBindings.end()) {
931 auto var = FindStaticBinding(record, importPath);
932 specifier->AsImportDefaultSpecifier()->Local()->SetVariable(var);
933 InsertForeignBinding(specifier, import, specifier->AsImportDefaultSpecifier()->Local()->Name(), var);
934 return;
935 }
936
937 specifier->AsImportDefaultSpecifier()->Local()->SetVariable(item->second);
938 InsertForeignBinding(specifier, import, specifier->AsImportDefaultSpecifier()->Local()->Name(), item->second);
939 }
940
HandleCustomNodes(ir::AstNode * childNode)941 void ETSBinder::HandleCustomNodes(ir::AstNode *childNode)
942 {
943 switch (childNode->Type()) {
944 case ir::AstNodeType::ETS_TYPE_REFERENCE: {
945 return BuildETSTypeReference(childNode->AsETSTypeReference());
946 }
947 case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
948 return BuildInterfaceDeclaration(childNode->AsTSInterfaceDeclaration());
949 }
950 case ir::AstNodeType::TS_ENUM_DECLARATION: {
951 return ResolveEnumDeclaration(childNode->AsTSEnumDeclaration());
952 }
953 case ir::AstNodeType::EXPORT_NAMED_DECLARATION: {
954 break;
955 }
956 case ir::AstNodeType::ETS_IMPORT_DECLARATION: {
957 return BuildImportDeclaration(childNode->AsETSImportDeclaration());
958 }
959 case ir::AstNodeType::MEMBER_EXPRESSION: {
960 return BuildMemberExpression(childNode->AsMemberExpression());
961 }
962 case ir::AstNodeType::METHOD_DEFINITION: {
963 return BuildMethodDefinition(childNode->AsMethodDefinition());
964 }
965 case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
966 return BuildETSNewClassInstanceExpression(childNode->AsETSNewClassInstanceExpression());
967 }
968 case ir::AstNodeType::ETS_FUNCTION_TYPE: {
969 return BuildSignatureDeclarationBaseParams(childNode);
970 }
971 case ir::AstNodeType::OBJECT_EXPRESSION: {
972 return BuildObjectExpression(childNode->AsObjectExpression());
973 }
974 case ir::AstNodeType::ANNOTATION_USAGE: {
975 return BuildAnnotationUsage(childNode->AsAnnotationUsage());
976 }
977 case ir::AstNodeType::ANNOTATION_DECLARATION: {
978 BuildAnnotationDeclaration(childNode->AsAnnotationDeclaration());
979 break;
980 }
981 default: {
982 return ResolveReferences(childNode);
983 }
984 }
985 }
986
BuildInternalName(ir::ScriptFunction * scriptFunc)987 bool ETSBinder::BuildInternalName(ir::ScriptFunction *scriptFunc)
988 {
989 const bool isExternal = recordTable_->IsExternal();
990 if (isExternal) {
991 scriptFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
992 }
993
994 if (scriptFunc->IsArrow()) {
995 return true;
996 }
997
998 auto *funcScope = scriptFunc->Scope();
999 funcScope->BindName(recordTable_->RecordName());
1000
1001 bool compilable = scriptFunc->Body() != nullptr && !isExternal;
1002 if (!compilable) {
1003 recordTable_->Signatures().push_back(funcScope);
1004 }
1005
1006 return compilable;
1007 }
1008
BuildInternalNameWithCustomRecordTable(ir::ScriptFunction * const scriptFunc,RecordTable * const recordTable)1009 bool ETSBinder::BuildInternalNameWithCustomRecordTable(ir::ScriptFunction *const scriptFunc,
1010 RecordTable *const recordTable)
1011 {
1012 const bool isExternal = recordTable->IsExternal();
1013 if (isExternal) {
1014 scriptFunc->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
1015 }
1016
1017 if (scriptFunc->IsArrow()) {
1018 return true;
1019 }
1020
1021 auto *const funcScope = scriptFunc->Scope();
1022 funcScope->BindName(recordTable->RecordName());
1023
1024 const bool compilable = scriptFunc->Body() != nullptr && !isExternal;
1025 if (!compilable) {
1026 recordTable->Signatures().push_back(funcScope);
1027 }
1028
1029 return compilable;
1030 }
1031
AddCompilableFunction(ir::ScriptFunction * func)1032 void ETSBinder::AddCompilableFunction(ir::ScriptFunction *func)
1033 {
1034 if (func->IsArrow() || func->IsAsyncFunc()) {
1035 return;
1036 }
1037
1038 AddCompilableFunctionScope(func->Scope());
1039 }
1040
BuildFunctionName(const ir::ScriptFunction * func) const1041 void ETSBinder::BuildFunctionName(const ir::ScriptFunction *func) const
1042 {
1043 auto *funcScope = func->Scope();
1044
1045 std::stringstream ss;
1046 ASSERT(func->IsArrow() || !funcScope->Name().Empty());
1047 ss << (func->IsExternalOverload() ? funcScope->InternalName() : funcScope->Name())
1048 << compiler::Signatures::METHOD_SEPARATOR;
1049
1050 const auto *signature = func->Signature();
1051
1052 if (func->IsStaticBlock()) {
1053 ss << compiler::Signatures::CCTOR;
1054 } else if (func->IsConstructor()) {
1055 ss << compiler::Signatures::CTOR;
1056 } else {
1057 if (func->IsGetter()) {
1058 ss << compiler::Signatures::GETTER_BEGIN;
1059 } else if (func->IsSetter()) {
1060 ss << compiler::Signatures::SETTER_BEGIN;
1061 }
1062 ss << util::Helpers::FunctionName(Allocator(), func);
1063 }
1064
1065 signature->ToAssemblerType(ss);
1066
1067 util::UString internalName(ss.str(), Allocator());
1068 funcScope->BindInternalName(internalName.View());
1069 }
1070
InitImplicitThisParam()1071 void ETSBinder::InitImplicitThisParam()
1072 {
1073 thisParam_ = Allocator()->New<ir::Identifier>("this", Allocator());
1074 }
1075
BuildProgram()1076 void ETSBinder::BuildProgram()
1077 {
1078 for (auto &[_, extPrograms] : Program()->ExternalSources()) {
1079 (void)_;
1080 for (auto *extProg : extPrograms) {
1081 BuildExternalProgram(extProg);
1082 }
1083 }
1084
1085 for (auto *defaultImport : defaultImports_) {
1086 BuildImportDeclaration(defaultImport);
1087 }
1088
1089 ValidateReexports();
1090
1091 auto &stmts = Program()->Ast()->Statements();
1092 const auto etsGlobal = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
1093 return stmt->IsClassDeclaration() &&
1094 stmt->AsClassDeclaration()->Definition()->Ident()->Name().Is(compiler::Signatures::ETS_GLOBAL);
1095 });
1096 if (etsGlobal != stmts.end()) {
1097 const auto begin = std::find_if(stmts.rbegin(), stmts.rend(), [](const ir::Statement *stmt) {
1098 return stmt->IsETSImportDeclaration() || stmt->IsETSPackageDeclaration();
1099 }).base();
1100
1101 const auto index = std::distance(begin, etsGlobal);
1102 std::rotate(begin, begin + index, begin + index + 1);
1103 }
1104
1105 for (auto *stmt : stmts) {
1106 ResolveReference(stmt);
1107 }
1108 }
1109
BuildExternalProgram(parser::Program * extProgram)1110 void ETSBinder::BuildExternalProgram(parser::Program *extProgram)
1111 {
1112 auto *savedProgram = Program();
1113 auto *savedRecordTable = recordTable_;
1114 auto *savedTopScope = TopScope();
1115
1116 auto flags = Program()->VarBinder()->IsGenStdLib() ? RecordTableFlags::NONE : RecordTableFlags::EXTERNAL;
1117 auto *extRecordTable = Allocator()->New<RecordTable>(Allocator(), extProgram, flags);
1118 externalRecordTable_.insert({extProgram, extRecordTable});
1119
1120 ResetTopScope(extProgram->GlobalScope());
1121 recordTable_ = extRecordTable;
1122 SetProgram(extProgram);
1123
1124 BuildProgram();
1125
1126 SetProgram(savedProgram);
1127 recordTable_ = savedRecordTable;
1128 ResetTopScope(savedTopScope);
1129 }
1130
BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression * classInstance)1131 void ETSBinder::BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classInstance)
1132 {
1133 BoundContext boundCtx(recordTable_, classInstance->ClassDefinition());
1134 ResolveReference(classInstance->GetTypeRef());
1135
1136 for (auto *arg : classInstance->GetArguments()) {
1137 ResolveReference(arg);
1138 }
1139
1140 if (classInstance->ClassDefinition() == nullptr) {
1141 return;
1142 }
1143
1144 ResolveReference(classInstance->ClassDefinition());
1145 }
1146
BuildImportDeclaration(ir::ETSImportDeclaration * decl)1147 void ETSBinder::BuildImportDeclaration(ir::ETSImportDeclaration *decl)
1148 {
1149 if (decl->Source()->Str() == Program()->SourceFile().GetAbsolutePath()) {
1150 return;
1151 }
1152
1153 const auto &specifiers = decl->Specifiers();
1154
1155 for (auto specifier : specifiers) {
1156 AddSpecifiersToTopBindings(specifier, decl, decl->Source());
1157 }
1158 }
1159
ValidateImportSpecifier(const ir::ImportSpecifier * const specifier,const ir::ETSImportDeclaration * const import,std::vector<ir::ETSImportDeclaration * > viewedReExport)1160 Variable *ETSBinder::ValidateImportSpecifier(const ir::ImportSpecifier *const specifier,
1161 const ir::ETSImportDeclaration *const import,
1162 std::vector<ir::ETSImportDeclaration *> viewedReExport)
1163 {
1164 const auto sourceName = import->ResolvedSource()->Str();
1165 const auto &record = GetExternalProgram(sourceName, import->Source());
1166 const auto *const importProgram = record.front();
1167 const auto *const importGlobalScope = importProgram->GlobalScope();
1168 const auto &globalBindings = importGlobalScope->Bindings();
1169
1170 auto imported = specifier->Imported()->Name();
1171 for (const auto *const item : import->Specifiers()) {
1172 // Handle alias
1173 // export {foo as FOO}
1174 if (item->IsImportSpecifier() && item->AsImportSpecifier()->Local()->Name().Is(imported.Mutf8()) &&
1175 !item->AsImportSpecifier()->Local()->Name().Is(item->AsImportSpecifier()->Imported()->Name().Mutf8())) {
1176 imported = item->AsImportSpecifier()->Imported()->Name();
1177 }
1178 }
1179
1180 auto *const var = FindImportSpecifiersVariable(imported, globalBindings, record);
1181 if (var != nullptr) {
1182 return var;
1183 }
1184
1185 // Failed to find variable, go through reexports
1186 const ir::ETSImportDeclaration *const implDecl =
1187 FindImportDeclInReExports(import, viewedReExport, imported, import->Source());
1188 if (implDecl != nullptr) {
1189 return ValidateImportSpecifier(specifier, implDecl, std::move(viewedReExport));
1190 }
1191
1192 return nullptr;
1193 }
1194
ValidateReexports()1195 void ETSBinder::ValidateReexports()
1196 {
1197 // This will throw syntax error if the reexport is incorrect
1198 // This will also set variables and check for ambiguous reexports
1199 for (auto *reexport : reExportImports_) {
1200 ValidateReexportDeclaration(reexport);
1201 }
1202
1203 reexportedNames_.clear();
1204 }
1205
ValidateReexportDeclaration(ir::ETSReExportDeclaration * decl)1206 void ETSBinder::ValidateReexportDeclaration(ir::ETSReExportDeclaration *decl)
1207 {
1208 // Reexport declarations are available in all files, see ReExportImports()
1209 // Check that reexport declaration is in this file
1210 const auto program = Program()->SourceFile().GetAbsolutePath();
1211 const auto reexportSource = os::GetAbsolutePath(decl->GetProgramPath().Utf8());
1212 if (program.Utf8() != reexportSource) {
1213 return;
1214 }
1215
1216 const auto *const import = decl->GetETSImportDeclarations();
1217 const auto &specifiers = import->Specifiers();
1218 for (auto specifier : specifiers) {
1219 // Example: export {foo} from "./A"
1220 if (specifier->IsImportSpecifier()) {
1221 auto importSpecifier = specifier->AsImportSpecifier();
1222 const auto reexported = importSpecifier->Imported()->Name();
1223 auto *const var =
1224 ValidateImportSpecifier(importSpecifier, import, std::vector<ir::ETSImportDeclaration *>());
1225 if (var == nullptr) {
1226 ThrowError(import->Start(), "Incorrect export \"" + reexported.Mutf8() + "\"");
1227 }
1228
1229 importSpecifier->Imported()->SetVariable(var);
1230 importSpecifier->Local()->SetVariable(var);
1231
1232 // Remember reexported name to check for ambiguous reexports
1233 if (!reexportedNames_.insert(reexported).second) {
1234 ThrowError(import->Start(), "Ambiguous export \"" + reexported.Mutf8() + "\"");
1235 }
1236 }
1237
1238 if (specifier->IsImportNamespaceSpecifier()) {
1239 // NOTE(kkonkuznetsov): See #20658
1240 // How to validate ambiguous exports with namespace specifiers?
1241 // Example:
1242 // export * from "./A"
1243 // export * from "./B"
1244 }
1245 }
1246 }
1247
ImportGlobalPropertiesForNotDefaultedExports(varbinder::Variable * var,const util::StringView & name,const ir::ClassElement * classElement)1248 bool ETSBinder::ImportGlobalPropertiesForNotDefaultedExports(varbinder::Variable *var, const util::StringView &name,
1249 const ir::ClassElement *classElement)
1250 {
1251 if (var->Declaration()->Node()->IsDefaultExported()) {
1252 return false;
1253 }
1254
1255 auto variable = Program()->GlobalClassScope()->FindLocal(name, ResolveBindingOptions::ALL);
1256
1257 bool isStdLib = util::Helpers::IsStdLib(Program());
1258 if (variable != nullptr && var != variable) {
1259 if (variable->Declaration()->IsFunctionDecl() && var->Declaration()->IsFunctionDecl()) {
1260 AddOverloadFlag(Allocator(), isStdLib, var, variable);
1261 return true;
1262 }
1263
1264 ThrowError(classElement->Id()->Start(), RedeclarationErrorMessageAssembler(var, variable, name.Utf8()));
1265 }
1266
1267 const auto insRes = TopScope()->InsertForeignBinding(name, var);
1268 if (!(!insRes.second && insRes.first != TopScope()->Bindings().end()) || !(insRes.first->second != var)) {
1269 return true;
1270 }
1271 if (insRes.first->second->Declaration()->IsFunctionDecl() && var->Declaration()->IsFunctionDecl()) {
1272 AddOverloadFlag(Allocator(), isStdLib, var, insRes.first->second);
1273 return true;
1274 }
1275
1276 ThrowError(classElement->Id()->Start(), RedeclarationErrorMessageAssembler(var, insRes.first->second, name.Utf8()));
1277 }
1278
ImportGlobalProperties(const ir::ClassDefinition * const classDef)1279 void ETSBinder::ImportGlobalProperties(const ir::ClassDefinition *const classDef)
1280 {
1281 const auto scopeCtx = LexicalScope<ClassScope>::Enter(this, classDef->Scope()->AsClassScope());
1282
1283 for (const auto *const prop : classDef->Body()) {
1284 const auto *const classElement = prop->AsClassElement();
1285
1286 if (classElement->IsClassStaticBlock()) {
1287 continue;
1288 }
1289
1290 ASSERT(classElement->IsStatic());
1291 const auto &name = classElement->Id()->Name();
1292 auto *const var = scopeCtx.GetScope()->FindLocal(name, ResolveBindingOptions::ALL);
1293 ASSERT(var != nullptr);
1294
1295 if (ImportGlobalPropertiesForNotDefaultedExports(var, name, classElement)) {
1296 return;
1297 }
1298 }
1299 }
1300
DynamicImportDataForVar(const Variable * var) const1301 const DynamicImportData *ETSBinder::DynamicImportDataForVar(const Variable *var) const
1302 {
1303 auto it = dynamicImportVars_.find(var);
1304 if (it == dynamicImportVars_.cend()) {
1305 return nullptr;
1306 }
1307
1308 return &it->second;
1309 }
1310
GetProgramList(const util::StringView & path) const1311 ArenaVector<parser::Program *> ETSBinder::GetProgramList(const util::StringView &path) const
1312 {
1313 for (const auto &extRecords : globalRecordTable_.Program()->ExternalSources()) {
1314 for (const auto &program : extRecords.second) {
1315 if (program->AbsoluteName() == path) {
1316 return extRecords.second;
1317 }
1318
1319 // in case of importing a package folder, the path could not be resolved to a specific file
1320 if (program->IsPackageModule() && program->SourceFileFolder() == path) {
1321 return extRecords.second;
1322 }
1323 }
1324 }
1325
1326 bool globalIsPackage = globalRecordTable_.Program()->IsPackageModule();
1327 if (globalIsPackage && path.Compare(globalRecordTable_.Program()->SourceFileFolder()) == 0) {
1328 return ArenaVector<parser::Program *>({GetContext()->parserProgram}, Allocator()->Adapter());
1329 }
1330
1331 return ArenaVector<parser::Program *>(Allocator()->Adapter());
1332 }
1333
IsDynamicModuleVariable(const Variable * var) const1334 bool ETSBinder::IsDynamicModuleVariable(const Variable *var) const
1335 {
1336 auto *data = DynamicImportDataForVar(var);
1337 if (data == nullptr) {
1338 return false;
1339 }
1340
1341 return data->specifier->IsImportSpecifier();
1342 }
1343
IsDynamicNamespaceVariable(const Variable * var) const1344 bool ETSBinder::IsDynamicNamespaceVariable(const Variable *var) const
1345 {
1346 auto *data = DynamicImportDataForVar(var);
1347 if (data == nullptr) {
1348 return false;
1349 }
1350
1351 return data->specifier->IsImportNamespaceSpecifier();
1352 }
1353
1354 } // namespace ark::es2panda::varbinder
1355