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 "ir/expressions/literals/bigIntLiteral.h" 17#include "ir/expressions/literals/numberLiteral.h" 18#include "ir/expressions/literals/stringLiteral.h" 19#include "ir/expressions/functionExpression.h" 20#include "ir/expressions/memberExpression.h" 21#include "ir/expressions/identifier.h" 22#include "ir/base/property.h" 23#include "ir/base/scriptFunction.h" 24#include "ir/base/spreadElement.h" 25#include "ir/base/tsIndexSignature.h" 26#include "ir/base/tsMethodSignature.h" 27#include "ir/base/tsPropertySignature.h" 28#include "ir/base/tsSignatureDeclaration.h" 29#include "ir/ts/tsTypeLiteral.h" 30#include "ir/ts/tsInterfaceDeclaration.h" 31#include "ir/ts/tsInterfaceHeritage.h" 32#include "ir/ts/tsInterfaceBody.h" 33#include "util/helpers.h" 34#include "varbinder/variable.h" 35#include "varbinder/scope.h" 36 37#include "checker/TSchecker.h" 38#include "checker/types/ts/indexInfo.h" 39 40namespace ark::es2panda::checker { 41void TSChecker::CheckIndexConstraints(Type *type) 42{ 43 if (!type->IsObjectType()) { 44 return; 45 } 46 47 ObjectType *objType = type->AsObjectType(); 48 ResolveStructuredTypeMembers(objType); 49 50 IndexInfo *numberInfo = objType->NumberIndexInfo(); 51 IndexInfo *stringInfo = objType->StringIndexInfo(); 52 const ArenaVector<varbinder::LocalVariable *> &properties = objType->Properties(); 53 54 if (numberInfo != nullptr) { 55 for (auto *it : properties) { 56 if (it->HasFlag(varbinder::VariableFlags::NUMERIC_NAME)) { 57 Type *propType = GetTypeOfVariable(it); 58 IsTypeAssignableTo(propType, numberInfo->GetType(), 59 {"Property '", it->Name(), "' of type '", propType, 60 "' is not assignable to numeric index type '", numberInfo->GetType(), "'."}, 61 it->Declaration()->Node()->Start()); 62 } 63 } 64 } 65 66 if (stringInfo != nullptr) { 67 for (auto *it : properties) { 68 Type *propType = GetTypeOfVariable(it); 69 IsTypeAssignableTo(propType, stringInfo->GetType(), 70 {"Property '", it->Name(), "' of type '", propType, 71 "' is not assignable to string index type '", stringInfo->GetType(), "'."}, 72 it->Declaration()->Node()->Start()); 73 } 74 75 if (numberInfo != nullptr && !IsTypeAssignableTo(numberInfo->GetType(), stringInfo->GetType())) { 76 ThrowTypeError({"Number index info type ", numberInfo->GetType(), 77 " is not assignable to string index info type ", stringInfo->GetType(), "."}, 78 numberInfo->Pos()); 79 } 80 } 81} 82 83void TSChecker::ResolveStructuredTypeMembers(Type *type) 84{ 85 if (type->IsObjectType()) { 86 ObjectType *objType = type->AsObjectType(); 87 88 if (objType->IsObjectLiteralType()) { 89 ResolveObjectTypeMembers(objType); 90 return; 91 } 92 93 if (objType->IsInterfaceType()) { 94 ResolveInterfaceOrClassTypeMembers(objType->AsInterfaceType()); 95 return; 96 } 97 } 98 99 if (type->IsUnionType()) { 100 ResolveUnionTypeMembers(type->AsUnionType()); 101 return; 102 } 103} 104 105void TSChecker::ResolveUnionTypeMembers(UnionType *type) 106{ 107 if (type->MergedObjectType() != nullptr) { 108 return; 109 } 110 111 ObjectDescriptor *desc = Allocator()->New<ObjectDescriptor>(Allocator()); 112 ArenaVector<Type *> stringInfoTypes(Allocator()->Adapter()); 113 ArenaVector<Type *> numberInfoTypes(Allocator()->Adapter()); 114 ArenaVector<Signature *> callSignatures(Allocator()->Adapter()); 115 ArenaVector<Signature *> constructSignatures(Allocator()->Adapter()); 116 117 for (auto *it : type->AsUnionType()->ConstituentTypes()) { 118 if (!it->IsObjectType()) { 119 continue; 120 } 121 122 ObjectType *objType = it->AsObjectType(); 123 ResolveObjectTypeMembers(objType); 124 125 if (!objType->CallSignatures().empty()) { 126 for (auto *signature : objType->CallSignatures()) { 127 callSignatures.push_back(signature); 128 } 129 } 130 131 if (!objType->ConstructSignatures().empty()) { 132 for (auto *signature : objType->ConstructSignatures()) { 133 constructSignatures.push_back(signature); 134 } 135 } 136 137 if (objType->StringIndexInfo() != nullptr) { 138 stringInfoTypes.push_back(objType->StringIndexInfo()->GetType()); 139 } 140 141 if (objType->NumberIndexInfo() != nullptr) { 142 numberInfoTypes.push_back(objType->NumberIndexInfo()->GetType()); 143 } 144 } 145 146 desc->callSignatures = callSignatures; 147 desc->constructSignatures = constructSignatures; 148 149 if (!stringInfoTypes.empty()) { 150 desc->stringIndexInfo = Allocator()->New<IndexInfo>(CreateUnionType(std::move(stringInfoTypes)), "x", false); 151 } 152 153 if (!numberInfoTypes.empty()) { 154 desc->numberIndexInfo = Allocator()->New<IndexInfo>(CreateUnionType(std::move(numberInfoTypes)), "x", false); 155 } 156 157 ObjectType *mergedType = Allocator()->New<ObjectLiteralType>(desc); 158 mergedType->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); 159 type->SetMergedObjectType(mergedType); 160} 161 162void TSChecker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) 163{ 164 if (type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) { 165 return; 166 } 167 168 ResolveDeclaredMembers(type); 169 GetBaseTypes(type); 170 171 type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); 172} 173 174void TSChecker::ResolveObjectTypeMembers(ObjectType *type) 175{ 176 if (!type->IsObjectLiteralType() || type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) { 177 return; 178 } 179 180 ASSERT(type->Variable() && type->Variable()->Declaration()->Node()->IsTSTypeLiteral()); 181 auto *typeLiteral = type->Variable()->Declaration()->Node()->AsTSTypeLiteral(); 182 ArenaVector<ir::TSSignatureDeclaration *> signatureDeclarations(Allocator()->Adapter()); 183 ArenaVector<ir::TSIndexSignature *> indexDeclarations(Allocator()->Adapter()); 184 185 for (auto *it : typeLiteral->Members()) { 186 ResolvePropertiesOfObjectType(type, it, signatureDeclarations, indexDeclarations, false); 187 } 188 189 type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); 190 191 ResolveSignaturesOfObjectType(type, signatureDeclarations); 192 ResolveIndexInfosOfObjectType(type, indexDeclarations); 193} 194 195void TSChecker::ResolvePropertiesOfObjectType(ObjectType *type, ir::AstNode *member, 196 ArenaVector<ir::TSSignatureDeclaration *> &signatureDeclarations, 197 ArenaVector<ir::TSIndexSignature *> &indexDeclarations, bool isInterface) 198{ 199 if (member->IsTSPropertySignature()) { 200 varbinder::Variable *prop = member->AsTSPropertySignature()->Variable(); 201 202 if (!isInterface || 203 ValidateInterfaceMemberRedeclaration(type, prop, member->AsTSPropertySignature()->Key()->Start())) { 204 type->AddProperty(prop->AsLocalVariable()); 205 } 206 207 return; 208 } 209 210 if (member->IsTSMethodSignature()) { 211 varbinder::Variable *method = member->AsTSMethodSignature()->Variable(); 212 213 if (!isInterface || 214 ValidateInterfaceMemberRedeclaration(type, method, member->AsTSMethodSignature()->Key()->Start())) { 215 type->AddProperty(method->AsLocalVariable()); 216 } 217 218 return; 219 } 220 221 if (member->IsTSSignatureDeclaration()) { 222 signatureDeclarations.push_back(member->AsTSSignatureDeclaration()); 223 return; 224 } 225 226 ASSERT(member->IsTSIndexSignature()); 227 indexDeclarations.push_back(member->AsTSIndexSignature()); 228} 229 230void TSChecker::ResolveSignaturesOfObjectType(ObjectType *type, 231 ArenaVector<ir::TSSignatureDeclaration *> &signatureDeclarations) 232{ 233 for (auto *it : signatureDeclarations) { 234 Type *placeholderObj = it->Check(this); 235 236 if (it->AsTSSignatureDeclaration()->Kind() == 237 ir::TSSignatureDeclaration::TSSignatureDeclarationKind::CALL_SIGNATURE) { 238 type->AddCallSignature(placeholderObj->AsObjectType()->CallSignatures()[0]); 239 continue; 240 } 241 242 type->AddConstructSignature(placeholderObj->AsObjectType()->ConstructSignatures()[0]); 243 } 244} 245void TSChecker::ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector<ir::TSIndexSignature *> &indexDeclarations) 246{ 247 for (auto *it : indexDeclarations) { 248 Type *placeholderObj = it->Check(this); 249 250 if (it->AsTSIndexSignature()->Kind() == ir::TSIndexSignature::TSIndexSignatureKind::NUMBER) { 251 IndexInfo *numberInfo = placeholderObj->AsObjectType()->NumberIndexInfo(); 252 253 if (type->NumberIndexInfo() != nullptr) { 254 ThrowTypeError("Duplicated index signature for type 'number'", it->Start()); 255 } 256 257 type->Desc()->numberIndexInfo = numberInfo; 258 continue; 259 } 260 261 IndexInfo *stringInfo = placeholderObj->AsObjectType()->StringIndexInfo(); 262 263 if (type->StringIndexInfo() != nullptr) { 264 ThrowTypeError("Duplicated index signature for type 'string'", it->Start()); 265 } 266 267 type->Desc()->stringIndexInfo = stringInfo; 268 } 269} 270 271varbinder::Variable *TSChecker::GetPropertyOfType(Type *type, const util::StringView &name, bool getPartial, 272 varbinder::VariableFlags propagateFlags) 273{ 274 if (type->IsObjectType()) { 275 ResolveObjectTypeMembers(type->AsObjectType()); 276 return type->AsObjectType()->GetProperty(name, true); 277 } 278 279 if (type->IsUnionType()) { 280 return GetPropertyOfUnionType(type->AsUnionType(), name, getPartial, propagateFlags); 281 } 282 283 return nullptr; 284} 285 286varbinder::Variable *TSChecker::GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, 287 varbinder::VariableFlags propagateFlags) 288{ 289 auto found = type->CachedSyntheticProperties().find(name); 290 if (found != type->CachedSyntheticProperties().end()) { 291 return found->second; 292 } 293 294 varbinder::VariableFlags flags = varbinder::VariableFlags::PROPERTY; 295 ArenaVector<Type *> collectedTypes(Allocator()->Adapter()); 296 297 for (auto *it : type->ConstituentTypes()) { 298 varbinder::Variable *prop = GetPropertyOfType(it, name); 299 300 if (prop == nullptr) { 301 if (it->IsArrayType()) { 302 collectedTypes.push_back(it->AsArrayType()->ElementType()); 303 continue; 304 } 305 306 if (!it->IsObjectType() && getPartial) { 307 continue; 308 } 309 if (!it->IsObjectType() && !getPartial) { 310 return nullptr; 311 } 312 313 ObjectType *objType = it->AsObjectType(); 314 315 if (objType->StringIndexInfo() == nullptr && getPartial) { 316 continue; 317 } 318 if (objType->StringIndexInfo() == nullptr && !getPartial) { 319 return nullptr; 320 } 321 322 collectedTypes.push_back(objType->StringIndexInfo()->GetType()); 323 continue; 324 } 325 326 prop->AddFlag(propagateFlags); 327 328 if (prop->HasFlag(varbinder::VariableFlags::OPTIONAL)) { 329 flags |= varbinder::VariableFlags::OPTIONAL; 330 } 331 332 collectedTypes.push_back(GetTypeOfVariable(prop)); 333 } 334 335 if (collectedTypes.empty()) { 336 return nullptr; 337 } 338 339 varbinder::Variable *syntheticProp = varbinder::Scope::CreateVar(Allocator(), name, flags, nullptr); 340 syntheticProp->SetTsType(CreateUnionType(std::move(collectedTypes))); 341 type->CachedSyntheticProperties().insert({name, syntheticProp}); 342 return syntheticProp; 343} 344 345Type *TSChecker::CheckComputedPropertyName(ir::Expression *key) 346{ 347 if (key->TsType() != nullptr) { 348 return key->TsType(); 349 } 350 351 Type *keyType = key->Check(this); 352 353 if (!keyType->HasTypeFlag(TypeFlag::STRING_LIKE | TypeFlag::NUMBER_LIKE)) { 354 ThrowTypeError( 355 "A computed property name in a type literal must refer to an expression whose type is a literal " 356 "type " 357 "or a 'unique symbol' type", 358 key->Start()); 359 } 360 361 key->SetTsType(keyType); 362 return keyType; 363} 364 365IndexInfo *TSChecker::GetApplicableIndexInfo(Type *type, Type *indexType) 366{ 367 ResolveStructuredTypeMembers(type); 368 bool getNumberInfo = indexType->HasTypeFlag(TypeFlag::NUMBER_LIKE); 369 370 if (type->IsObjectType()) { 371 if (getNumberInfo) { 372 return type->AsObjectType()->NumberIndexInfo(); 373 } 374 375 return type->AsObjectType()->StringIndexInfo(); 376 } 377 378 if (type->IsUnionType()) { 379 ASSERT(type->AsUnionType()->MergedObjectType()); 380 381 if (getNumberInfo) { 382 return type->AsUnionType()->MergedObjectType()->NumberIndexInfo(); 383 } 384 385 return type->AsUnionType()->MergedObjectType()->StringIndexInfo(); 386 } 387 388 return nullptr; 389} 390 391Type *TSChecker::GetPropertyTypeForIndexType(Type *type, Type *indexType) 392{ 393 if (type->IsArrayType()) { 394 return type->AsArrayType()->ElementType(); 395 } 396 397 if (indexType->HasTypeFlag(TypeFlag::STRING_LITERAL | TypeFlag::NUMBER_LITERAL)) { 398 varbinder::Variable *prop = nullptr; 399 400 if (indexType->IsStringLiteralType()) { 401 prop = GetPropertyOfType(type, indexType->AsStringLiteralType()->Value()); 402 } else { 403 util::StringView propName = 404 util::Helpers::ToStringView(Allocator(), indexType->AsNumberLiteralType()->Value()); 405 prop = GetPropertyOfType(type, propName); 406 } 407 408 if (prop != nullptr) { 409 Type *propType = GetTypeOfVariable(prop); 410 411 if (prop->HasFlag(varbinder::VariableFlags::READONLY)) { 412 propType->AddTypeFlag(TypeFlag::READONLY); 413 } 414 415 return propType; 416 } 417 } 418 419 if (indexType->HasTypeFlag(TypeFlag::STRING_LIKE | TypeFlag::NUMBER_LIKE)) { 420 IndexInfo *indexInfo = GetApplicableIndexInfo(type, indexType); 421 422 if (indexInfo != nullptr) { 423 Type *indexInfoType = indexInfo->GetType(); 424 425 if (indexInfo->Readonly()) { 426 indexInfoType->AddTypeFlag(TypeFlag::READONLY); 427 } 428 429 return indexInfoType; 430 } 431 } 432 433 return nullptr; 434} 435 436ArenaVector<ObjectType *> TSChecker::GetBaseTypes(InterfaceType *type) 437{ 438 if (type->HasObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES)) { 439 return type->Bases(); 440 } 441 442 ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl()); 443 varbinder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl(); 444 445 TypeStackElement tse(this, type, {"Type ", type->Name(), " recursively references itself as a base type."}, 446 decl->Node()->AsTSInterfaceDeclaration()->Id()->Start()); 447 if (tse.HasTypeError()) { 448 type->Bases().clear(); 449 return type->Bases(); 450 } 451 452 for (const auto *declaration : decl->Decls()) { 453 if (declaration->Extends().empty()) { 454 continue; 455 } 456 457 for (auto *extends : declaration->Extends()) { 458 Type *baseType = extends->Expr()->GetType(this); 459 460 if (!baseType->HasTypeFlag(TypeFlag::OBJECT | TypeFlag::NON_PRIMITIVE | TypeFlag::ANY)) { 461 ThrowTypeError( 462 "An interface can only extend an object type or intersection of object types with statically " 463 "known " 464 "members", 465 extends->Start()); 466 } 467 468 if (!baseType->IsObjectType()) { 469 continue; 470 } 471 472 ObjectType *baseObj = baseType->AsObjectType(); 473 474 if (baseType == type) { 475 ThrowTypeError({"Type ", type->Name(), " recursively references itself as a base type."}, 476 decl->Node()->AsTSInterfaceDeclaration()->Id()->Start()); 477 } 478 479 type->AddBase(baseObj); 480 481 if (!baseObj->IsInterfaceType()) { 482 continue; 483 } 484 485 CheckExtendsBases(baseObj, type, decl); 486 } 487 } 488 489 type->AddObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES); 490 return type->Bases(); 491} 492 493void TSChecker::CheckExtendsBases(ObjectType *&baseObj, InterfaceType *&type, varbinder::InterfaceDecl *&decl) 494{ 495 ArenaVector<ObjectType *> extendsBases = GetBaseTypes(baseObj->AsInterfaceType()); 496 for (auto *extendBase : extendsBases) { 497 if (extendBase == type) { 498 ThrowTypeError({"Type ", type->Name(), " recursively references itself as a base type."}, 499 decl->Node()->AsTSInterfaceDeclaration()->Id()->Start()); 500 } 501 } 502} 503 504void TSChecker::ResolveDeclaredMembers(InterfaceType *type) 505{ 506 if (type->HasObjectFlag(ObjectFlags::RESOLVED_DECLARED_MEMBERS)) { 507 return; 508 } 509 510 ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl()); 511 varbinder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl(); 512 513 ArenaVector<ir::TSSignatureDeclaration *> signatureDeclarations(Allocator()->Adapter()); 514 ArenaVector<ir::TSIndexSignature *> indexDeclarations(Allocator()->Adapter()); 515 516 for (const auto *declaration : decl->Decls()) { 517 for (auto *member : declaration->Body()->Body()) { 518 ResolvePropertiesOfObjectType(type, member, signatureDeclarations, indexDeclarations, true); 519 } 520 521 type->AddObjectFlag(ObjectFlags::RESOLVED_DECLARED_MEMBERS); 522 523 ResolveSignaturesOfObjectType(type, signatureDeclarations); 524 ResolveIndexInfosOfObjectType(type, indexDeclarations); 525 } 526} 527 528bool TSChecker::ValidateInterfaceMemberRedeclaration(ObjectType *type, varbinder::Variable *prop, 529 const lexer::SourcePosition &locInfo) 530{ 531 if (prop->HasFlag(varbinder::VariableFlags::COMPUTED)) { 532 return true; 533 } 534 535 varbinder::Variable *found = type->GetProperty(prop->Name(), false); 536 537 if (found == nullptr) { 538 return true; 539 } 540 541 Type *targetType = GetTypeOfVariable(prop); 542 Type *sourceType = GetTypeOfVariable(found); 543 IsTypeIdenticalTo(targetType, sourceType, 544 {"Subsequent property declarations must have the same type. Property ", prop->Name(), 545 " must be of type ", sourceType, ", but here has type ", targetType, "."}, 546 locInfo); 547 return false; 548} 549} // namespace ark::es2panda::checker 550