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 "ETSchecker.h" 17 18#include "es2panda.h" 19#include "ir/base/classDefinition.h" 20#include "ir/expression.h" 21#include "ir/expressions/callExpression.h" 22#include "ir/ts/tsInterfaceDeclaration.h" 23#include "ir/statements/blockStatement.h" 24#include "varbinder/ETSBinder.h" 25#include "parser/program/program.h" 26#include "checker/ets/aliveAnalyzer.h" 27#include "checker/ets/assignAnalyzer.h" 28#include "checker/ets/etsWarningAnalyzer.h" 29#include "checker/types/globalTypesHolder.h" 30#include "ir/base/scriptFunction.h" 31#include "util/helpers.h" 32#include "evaluate/scopedDebugInfoPlugin.h" 33 34namespace ark::es2panda::checker { 35 36static util::StringView InitBuiltin(ETSChecker *checker, std::string_view signature) 37{ 38 const auto varMap = checker->VarBinder()->TopScope()->Bindings(); 39 const auto iterator = varMap.find(signature); 40 ASSERT(iterator != varMap.end()); 41 auto *var = iterator->second; 42 Type *type {nullptr}; 43 if (var->Declaration()->Node()->IsClassDefinition()) { 44 type = checker->BuildBasicClassProperties(var->Declaration()->Node()->AsClassDefinition()); 45 } else { 46 ASSERT(var->Declaration()->Node()->IsTSInterfaceDeclaration()); 47 type = checker->BuildBasicInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration()); 48 } 49 checker->GetGlobalTypesHolder()->InitializeBuiltin(iterator->first, type); 50 return iterator->first; 51} 52 53static void SetupFunctionalInterface(ETSObjectType *type) 54{ 55 type->AddObjectFlag(ETSObjectFlags::FUNCTIONAL); 56 auto *invoke = type->GetOwnProperty<PropertyType::INSTANCE_METHOD>(FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME); 57 auto *invokeType = invoke->TsType()->AsETSFunctionType(); 58 ASSERT(invokeType->CallSignatures().size() == 1); 59 auto *signature = invokeType->CallSignatures()[0]; 60 signature->AddSignatureFlag(SignatureFlags::FUNCTIONAL_INTERFACE_SIGNATURE); 61} 62 63static void SetupBuiltinMember(varbinder::Variable *var) 64{ 65 auto *type = var->TsType(); 66 if (type == nullptr || !type->IsETSObjectType()) { 67 return; 68 } 69} 70 71// NOLINTNEXTLINE(modernize-avoid-c-arrays) 72static constexpr std::string_view BUILTINS_TO_INIT[] = { 73 compiler::Signatures::BUILTIN_BOOLEAN_CLASS, 74 compiler::Signatures::BUILTIN_BYTE_CLASS, 75 compiler::Signatures::BUILTIN_CHAR_CLASS, 76 compiler::Signatures::BUILTIN_SHORT_CLASS, 77 compiler::Signatures::BUILTIN_INT_CLASS, 78 compiler::Signatures::BUILTIN_LONG_CLASS, 79 compiler::Signatures::BUILTIN_FLOAT_CLASS, 80 compiler::Signatures::BUILTIN_DOUBLE_CLASS, 81 compiler::Signatures::BUILTIN_FUNCTION0_CLASS, 82 compiler::Signatures::BUILTIN_FUNCTION1_CLASS, 83 compiler::Signatures::BUILTIN_FUNCTION2_CLASS, 84 compiler::Signatures::BUILTIN_FUNCTION3_CLASS, 85 compiler::Signatures::BUILTIN_FUNCTION4_CLASS, 86 compiler::Signatures::BUILTIN_FUNCTION5_CLASS, 87 compiler::Signatures::BUILTIN_FUNCTION6_CLASS, 88 compiler::Signatures::BUILTIN_FUNCTION7_CLASS, 89 compiler::Signatures::BUILTIN_FUNCTION8_CLASS, 90 compiler::Signatures::BUILTIN_FUNCTION9_CLASS, 91 compiler::Signatures::BUILTIN_FUNCTION10_CLASS, 92 compiler::Signatures::BUILTIN_FUNCTION11_CLASS, 93 compiler::Signatures::BUILTIN_FUNCTION12_CLASS, 94 compiler::Signatures::BUILTIN_FUNCTION13_CLASS, 95 compiler::Signatures::BUILTIN_FUNCTION14_CLASS, 96 compiler::Signatures::BUILTIN_FUNCTION15_CLASS, 97 compiler::Signatures::BUILTIN_FUNCTION16_CLASS, 98 compiler::Signatures::BUILTIN_FUNCTIONN_CLASS, 99 compiler::Signatures::BUILTIN_THROWING_FUNCTION0_CLASS, 100 compiler::Signatures::BUILTIN_THROWING_FUNCTION1_CLASS, 101 compiler::Signatures::BUILTIN_THROWING_FUNCTION2_CLASS, 102 compiler::Signatures::BUILTIN_THROWING_FUNCTION3_CLASS, 103 compiler::Signatures::BUILTIN_THROWING_FUNCTION4_CLASS, 104 compiler::Signatures::BUILTIN_THROWING_FUNCTION5_CLASS, 105 compiler::Signatures::BUILTIN_THROWING_FUNCTION6_CLASS, 106 compiler::Signatures::BUILTIN_THROWING_FUNCTION7_CLASS, 107 compiler::Signatures::BUILTIN_THROWING_FUNCTION8_CLASS, 108 compiler::Signatures::BUILTIN_THROWING_FUNCTION9_CLASS, 109 compiler::Signatures::BUILTIN_THROWING_FUNCTION10_CLASS, 110 compiler::Signatures::BUILTIN_THROWING_FUNCTION11_CLASS, 111 compiler::Signatures::BUILTIN_THROWING_FUNCTION12_CLASS, 112 compiler::Signatures::BUILTIN_THROWING_FUNCTION13_CLASS, 113 compiler::Signatures::BUILTIN_THROWING_FUNCTION14_CLASS, 114 compiler::Signatures::BUILTIN_THROWING_FUNCTION15_CLASS, 115 compiler::Signatures::BUILTIN_THROWING_FUNCTION16_CLASS, 116 compiler::Signatures::BUILTIN_THROWING_FUNCTIONN_CLASS, 117 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION0_CLASS, 118 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION1_CLASS, 119 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION2_CLASS, 120 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION3_CLASS, 121 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION4_CLASS, 122 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION5_CLASS, 123 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION6_CLASS, 124 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION7_CLASS, 125 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION8_CLASS, 126 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION9_CLASS, 127 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION10_CLASS, 128 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION11_CLASS, 129 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION12_CLASS, 130 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION13_CLASS, 131 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION14_CLASS, 132 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION15_CLASS, 133 compiler::Signatures::BUILTIN_RETHROWING_FUNCTION16_CLASS, 134 compiler::Signatures::BUILTIN_RETHROWING_FUNCTIONN_CLASS, 135}; 136 137void ETSChecker::InitializeBuiltins(varbinder::ETSBinder *varbinder) 138{ 139 if (HasStatus(CheckerStatus::BUILTINS_INITIALIZED)) { 140 return; 141 } 142 143 const auto varMap = varbinder->TopScope()->Bindings(); 144 145 auto const objectName = InitBuiltin(this, compiler::Signatures::BUILTIN_OBJECT_CLASS); 146 147 for (auto sig : BUILTINS_TO_INIT) { 148 InitBuiltin(this, sig); 149 } 150 151 for (size_t id = static_cast<size_t>(GlobalTypeId::ETS_THROWING_FUNCTION0_CLASS), nargs = 0; 152 id <= static_cast<size_t>(GlobalTypeId::ETS_THROWING_FUNCTIONN_CLASS); id++, nargs++) { 153 auto *type = GetGlobalTypesHolder() 154 ->GlobalFunctionBuiltinType(nargs, ir::ScriptFunctionFlags::THROWS) 155 ->AsETSObjectType(); 156 SetupFunctionalInterface(type); 157 } 158 159 for (size_t id = static_cast<size_t>(GlobalTypeId::ETS_RETHROWING_FUNCTION0_CLASS), nargs = 0; 160 id <= static_cast<size_t>(GlobalTypeId::ETS_RETHROWING_FUNCTIONN_CLASS); id++, nargs++) { 161 auto *type = GetGlobalTypesHolder() 162 ->GlobalFunctionBuiltinType(nargs, ir::ScriptFunctionFlags::RETHROWS) 163 ->AsETSObjectType(); 164 SetupFunctionalInterface(type); 165 // note(gergocs): type->Interfaces().front() should be the same as the type in throwing functions 166 // and adding the functional flag to the interface should be deleted 167 type->Interfaces().front()->AddObjectFlag(ETSObjectFlags::FUNCTIONAL); 168 } 169 170 for (size_t id = static_cast<size_t>(GlobalTypeId::ETS_FUNCTION0_CLASS), nargs = 0; 171 id <= static_cast<size_t>(GlobalTypeId::ETS_FUNCTIONN_CLASS); id++, nargs++) { 172 auto *type = 173 GetGlobalTypesHolder()->GlobalFunctionBuiltinType(nargs, ir::ScriptFunctionFlags::NONE)->AsETSObjectType(); 174 SetupFunctionalInterface(type); 175 // note(gergocs): type->Interfaces().front() should be the same as the type in rethrowing functions 176 // and adding the functional flag to the interface should be deleted 177 type->Interfaces().front()->AddObjectFlag(ETSObjectFlags::FUNCTIONAL); 178 type->Interfaces().front()->Interfaces().front()->AddObjectFlag(ETSObjectFlags::FUNCTIONAL); 179 } 180 181 for (const auto &[name, var] : varMap) { 182 (void)name; 183 SetupBuiltinMember(var); 184 } 185 186 for (const auto &[name, var] : varMap) { 187 if (name == objectName) { 188 continue; 189 } 190 191 if (var->HasFlag(varbinder::VariableFlags::BUILTIN_TYPE)) { 192 if (var->TsType() == nullptr) { 193 InitializeBuiltin(var, name); 194 } else { 195 GetGlobalTypesHolder()->InitializeBuiltin(name, var->TsType()); 196 } 197 } 198 } 199 200 AddStatus(CheckerStatus::BUILTINS_INITIALIZED); 201} 202 203void ETSChecker::InitializeBuiltin(varbinder::Variable *var, const util::StringView &name) 204{ 205 Type *type {nullptr}; 206 if (var->Declaration()->Node()->IsClassDefinition()) { 207 type = BuildBasicClassProperties(var->Declaration()->Node()->AsClassDefinition()); 208 } else { 209 ASSERT(var->Declaration()->Node()->IsTSInterfaceDeclaration()); 210 type = BuildBasicInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration()); 211 } 212 GetGlobalTypesHolder()->InitializeBuiltin(name, type); 213} 214 215bool ETSChecker::StartChecker(varbinder::VarBinder *varbinder, const CompilerOptions &options) 216{ 217 Initialize(varbinder); 218 219 if (options.parseOnly) { 220 return false; 221 } 222 223 auto *etsBinder = varbinder->AsETSBinder(); 224 InitializeBuiltins(etsBinder); 225 226 for (auto &entry : etsBinder->DynamicImportVars()) { 227 auto &data = entry.second; 228 if (data.import->IsPureDynamic()) { 229 data.variable->SetTsType(GlobalBuiltinDynamicType(data.import->Language())); 230 } 231 } 232 233 bool isEvalMode = (debugInfoPlugin_ != nullptr); 234 if (UNLIKELY(isEvalMode)) { 235 debugInfoPlugin_->PreCheck(); 236 } 237 238 CheckProgram(Program(), true); 239 240 if (UNLIKELY(isEvalMode)) { 241 debugInfoPlugin_->PostCheck(); 242 } 243 244 BuildDynamicImportClass(); 245 246#ifndef NDEBUG 247 for (auto *func : varbinder->Functions()) { 248 ASSERT(!func->Node()->AsScriptFunction()->Scope()->InternalName().Empty()); 249 } 250#endif 251 252 if (options.dumpCheckedAst) { 253 std::cout << Program()->Dump() << std::endl; 254 } 255 256 if (options.etsHasWarnings) { 257 CheckWarnings(Program(), options); 258 } 259 260 return !ErrorLogger()->IsAnyError(); 261} 262 263evaluate::ScopedDebugInfoPlugin *ETSChecker::GetDebugInfoPlugin() 264{ 265 return debugInfoPlugin_; 266} 267 268const evaluate::ScopedDebugInfoPlugin *ETSChecker::GetDebugInfoPlugin() const 269{ 270 return debugInfoPlugin_; 271} 272 273void ETSChecker::SetDebugInfoPlugin(evaluate::ScopedDebugInfoPlugin *debugInfo) 274{ 275 debugInfoPlugin_ = debugInfo; 276} 277 278void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis) 279{ 280 auto *savedProgram = Program(); 281 SetProgram(program); 282 283 for (auto &[_, extPrograms] : program->ExternalSources()) { 284 (void)_; 285 for (auto *extProg : extPrograms) { 286 checker::SavedCheckerContext savedContext(this, Context().Status(), Context().ContainingClass()); 287 AddStatus(checker::CheckerStatus::IN_EXTERNAL); 288 CheckProgram(extProg, VarBinder()->IsGenStdLib()); 289 } 290 } 291 292 ASSERT(Program()->Ast()->IsProgram()); 293 Program()->Ast()->Check(this); 294 295 if (ErrorLogger()->IsAnyError()) { 296 return; 297 } 298 299 if (runAnalysis) { 300 AliveAnalyzer aliveAnalyzer(Program()->Ast(), this); 301 AssignAnalyzer(this).Analyze(Program()->Ast()); 302 } 303 304 ASSERT(VarBinder()->AsETSBinder()->GetExternalRecordTable().find(program)->second); 305 306 SetProgram(savedProgram); 307} 308 309void ETSChecker::CheckWarnings(parser::Program *program, const CompilerOptions &options) 310{ 311 const auto etsWarningCollection = options.etsWarningCollection; 312 for (const auto warning : etsWarningCollection) { 313 ETSWarningAnalyzer(Program()->Ast(), program, warning, options.etsWerror); 314 } 315} 316 317Type *ETSChecker::CheckTypeCached(ir::Expression *expr) 318{ 319 if (expr->TsType() == nullptr) { 320 expr->SetTsType(expr->Check(this)); 321 } 322 323 return expr->TsType(); 324} 325 326template <typename... Args> 327ETSObjectType *ETSChecker::AsETSObjectType(Type *(GlobalTypesHolder::*typeFunctor)(Args...), Args... args) const 328{ 329 auto *ret = (GetGlobalTypesHolder()->*typeFunctor)(args...); 330 return ret != nullptr ? ret->AsETSObjectType() : nullptr; 331} 332 333Type *ETSChecker::GlobalByteType() const 334{ 335 return GetGlobalTypesHolder()->GlobalByteType(); 336} 337 338Type *ETSChecker::GlobalShortType() const 339{ 340 return GetGlobalTypesHolder()->GlobalShortType(); 341} 342 343Type *ETSChecker::GlobalIntType() const 344{ 345 return GetGlobalTypesHolder()->GlobalIntType(); 346} 347 348Type *ETSChecker::GlobalLongType() const 349{ 350 return GetGlobalTypesHolder()->GlobalLongType(); 351} 352 353Type *ETSChecker::GlobalFloatType() const 354{ 355 return GetGlobalTypesHolder()->GlobalFloatType(); 356} 357 358Type *ETSChecker::GlobalDoubleType() const 359{ 360 return GetGlobalTypesHolder()->GlobalDoubleType(); 361} 362 363Type *ETSChecker::GlobalCharType() const 364{ 365 return GetGlobalTypesHolder()->GlobalCharType(); 366} 367 368Type *ETSChecker::GlobalETSBooleanType() const 369{ 370 return GetGlobalTypesHolder()->GlobalETSBooleanType(); 371} 372 373Type *ETSChecker::GlobalVoidType() const 374{ 375 return GetGlobalTypesHolder()->GlobalETSVoidType(); 376} 377 378Type *ETSChecker::GlobalETSNullType() const 379{ 380 return GetGlobalTypesHolder()->GlobalETSNullType(); 381} 382 383Type *ETSChecker::GlobalETSUndefinedType() const 384{ 385 return GetGlobalTypesHolder()->GlobalETSUndefinedType(); 386} 387 388Type *ETSChecker::GlobalETSStringLiteralType() const 389{ 390 return GetGlobalTypesHolder()->GlobalETSStringLiteralType(); 391} 392 393Type *ETSChecker::GlobalETSBigIntType() const 394{ 395 return GetGlobalTypesHolder()->GlobalETSBigIntBuiltinType(); 396} 397 398Type *ETSChecker::GlobalWildcardType() const 399{ 400 return GetGlobalTypesHolder()->GlobalWildcardType(); 401} 402 403ETSObjectType *ETSChecker::GlobalETSObjectType() const 404{ 405 return AsETSObjectType(&GlobalTypesHolder::GlobalETSObjectType); 406} 407 408ETSUnionType *ETSChecker::GlobalETSNullishType() const 409{ 410 auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSNullishType)(); 411 return ret != nullptr ? ret->AsETSUnionType() : nullptr; 412} 413 414ETSUnionType *ETSChecker::GlobalETSNullishObjectType() const 415{ 416 auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSNullishObjectType)(); 417 return ret != nullptr ? ret->AsETSUnionType() : nullptr; 418} 419 420ETSObjectType *ETSChecker::GlobalBuiltinETSStringType() const 421{ 422 return AsETSObjectType(&GlobalTypesHolder::GlobalETSStringBuiltinType); 423} 424 425ETSObjectType *ETSChecker::GlobalBuiltinETSBigIntType() const 426{ 427 return AsETSObjectType(&GlobalTypesHolder::GlobalETSBigIntBuiltinType); 428} 429 430ETSObjectType *ETSChecker::GlobalBuiltinTypeType() const 431{ 432 return AsETSObjectType(&GlobalTypesHolder::GlobalTypeBuiltinType); 433} 434 435ETSObjectType *ETSChecker::GlobalBuiltinExceptionType() const 436{ 437 return AsETSObjectType(&GlobalTypesHolder::GlobalExceptionBuiltinType); 438} 439 440ETSObjectType *ETSChecker::GlobalBuiltinErrorType() const 441{ 442 return AsETSObjectType(&GlobalTypesHolder::GlobalErrorBuiltinType); 443} 444 445ETSObjectType *ETSChecker::GlobalStringBuilderBuiltinType() const 446{ 447 return AsETSObjectType(&GlobalTypesHolder::GlobalStringBuilderBuiltinType); 448} 449 450ETSObjectType *ETSChecker::GlobalBuiltinPromiseType() const 451{ 452 return AsETSObjectType(&GlobalTypesHolder::GlobalPromiseBuiltinType); 453} 454 455ETSObjectType *ETSChecker::GlobalBuiltinJSRuntimeType() const 456{ 457 return AsETSObjectType(&GlobalTypesHolder::GlobalJSRuntimeBuiltinType); 458} 459 460ETSObjectType *ETSChecker::GlobalBuiltinJSValueType() const 461{ 462 return AsETSObjectType(&GlobalTypesHolder::GlobalJSValueBuiltinType); 463} 464 465ETSObjectType *ETSChecker::GlobalBuiltinFunctionType(size_t nargs, ir::ScriptFunctionFlags flags) const 466{ 467 return AsETSObjectType(&GlobalTypesHolder::GlobalFunctionBuiltinType, nargs, flags); 468} 469 470size_t ETSChecker::GlobalBuiltinFunctionTypeVariadicThreshold() const 471{ 472 return GetGlobalTypesHolder()->VariadicFunctionTypeThreshold(); 473} 474 475ETSObjectType *ETSChecker::GlobalBuiltinDynamicType(Language lang) const 476{ 477 if (lang.GetId() == Language::Id::JS) { 478 return GlobalBuiltinJSValueType(); 479 } 480 return nullptr; 481} 482 483ETSObjectType *ETSChecker::GlobalBuiltinBoxType(Type *contents) 484{ 485 switch (TypeKind(contents)) { 486 case TypeFlag::ETS_BOOLEAN: 487 return AsETSObjectType(&GlobalTypesHolder::GlobalBooleanBoxBuiltinType); 488 case TypeFlag::BYTE: 489 return AsETSObjectType(&GlobalTypesHolder::GlobalByteBoxBuiltinType); 490 case TypeFlag::CHAR: 491 return AsETSObjectType(&GlobalTypesHolder::GlobalCharBoxBuiltinType); 492 case TypeFlag::SHORT: 493 return AsETSObjectType(&GlobalTypesHolder::GlobalShortBoxBuiltinType); 494 case TypeFlag::INT: 495 return AsETSObjectType(&GlobalTypesHolder::GlobalIntBoxBuiltinType); 496 case TypeFlag::LONG: 497 return AsETSObjectType(&GlobalTypesHolder::GlobalLongBoxBuiltinType); 498 case TypeFlag::FLOAT: 499 return AsETSObjectType(&GlobalTypesHolder::GlobalFloatBoxBuiltinType); 500 case TypeFlag::DOUBLE: 501 return AsETSObjectType(&GlobalTypesHolder::GlobalDoubleBoxBuiltinType); 502 default: { 503 auto *base = AsETSObjectType(&GlobalTypesHolder::GlobalBoxBuiltinType); 504 auto *substitution = NewSubstitution(); 505 substitution->emplace(base->TypeArguments()[0]->AsETSTypeParameter(), contents); 506 return base->Substitute(Relation(), substitution); 507 } 508 } 509} 510 511const checker::WrapperDesc &ETSChecker::PrimitiveWrapper() const 512{ 513 return primitiveWrappers_.Wrappers(); 514} 515 516GlobalArraySignatureMap &ETSChecker::GlobalArrayTypes() 517{ 518 return globalArraySignatures_; 519} 520 521const GlobalArraySignatureMap &ETSChecker::GlobalArrayTypes() const 522{ 523 return globalArraySignatures_; 524} 525 526Type *ETSChecker::GlobalTypeError() const 527{ 528 return GetGlobalTypesHolder()->GlobalTypeError(); 529} 530 531void ETSChecker::HandleUpdatedCallExpressionNode(ir::CallExpression *callExpr) 532{ 533 VarBinder()->AsETSBinder()->HandleCustomNodes(callExpr); 534} 535 536Type *ETSChecker::SelectGlobalIntegerTypeForNumeric(Type *type) 537{ 538 switch (ETSType(type)) { 539 case checker::TypeFlag::FLOAT: { 540 return GlobalIntType(); 541 } 542 case checker::TypeFlag::DOUBLE: { 543 return GlobalLongType(); 544 } 545 default: { 546 return type; 547 } 548 } 549} 550 551} // namespace ark::es2panda::checker 552