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