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 "destructuringContext.h" 17 18#include "util/helpers.h" 19#include "varbinder/scope.h" 20#include "ir/typeNode.h" 21#include "ir/expressions/identifier.h" 22#include "ir/expressions/objectExpression.h" 23#include "ir/expressions/assignmentExpression.h" 24#include "ir/expressions/arrayExpression.h" 25#include "ir/base/spreadElement.h" 26#include "ir/base/property.h" 27#include "ir/expression.h" 28 29namespace ark::es2panda::checker { 30void DestructuringContext::Prepare(ir::TypeNode *typeAnnotation, ir::Expression *initializer, 31 const lexer::SourcePosition &loc) 32{ 33 if (typeAnnotation != nullptr) { 34 typeAnnotation->Check(checker_); 35 Type *annotationType = typeAnnotation->GetType(checker_); 36 37 if (initializer != nullptr) { 38 checker_->ElaborateElementwise(annotationType, initializer, loc); 39 } 40 41 validateTypeAnnotation_ = true; 42 inferredType_ = annotationType; 43 return; 44 } 45 46 if (initializer != nullptr) { 47 if (!initializer->IsObjectExpression()) { 48 validateObjectPatternInitializer_ = false; 49 } 50 51 inferredType_ = initializer->Check(checker_); 52 } 53} 54 55void DestructuringContext::HandleDestructuringAssignment(ir::Identifier *ident, Type *inferredType, Type *defaultType) 56{ 57 if (ident->Variable() == nullptr) { 58 checker_->ThrowTypeError({"Cannot find name '", ident->Name(), "'."}, ident->Start()); 59 } 60 61 varbinder::Variable *variable = ident->Variable(); 62 ASSERT(variable->TsType()); 63 64 if (defaultType != nullptr && !checker_->IsTypeAssignableTo(defaultType, variable->TsType())) { 65 checker_->ThrowAssignmentError(defaultType, variable->TsType(), ident->Start()); 66 } 67 68 if (inferredType != nullptr && !checker_->IsTypeAssignableTo(inferredType, variable->TsType())) { 69 checker_->ThrowAssignmentError(inferredType, variable->TsType(), ident->Start()); 70 } 71} 72 73void DestructuringContext::SetInferredTypeForVariable(varbinder::Variable *var, Type *inferredType, 74 const lexer::SourcePosition &loc) 75{ 76 ASSERT(var); 77 78 if (!checker_->HasStatus(CheckerStatus::IN_CONST_CONTEXT)) { 79 inferredType = checker_->GetBaseTypeOfLiteralType(inferredType); 80 } 81 82 if (var->TsType() != nullptr) { 83 checker_->IsTypeIdenticalTo(var->TsType(), inferredType, 84 {"Subsequent variable declaration must have the same type. Variable '", var->Name(), 85 "' must be of type '", var->TsType(), "', but here has type '", inferredType, 86 "'."}, 87 loc); 88 return; 89 } 90 91 if (signatureInfo_ != nullptr) { 92 signatureInfo_->params.push_back(var->AsLocalVariable()); 93 signatureInfo_->minArgCount++; 94 } 95 96 var->SetTsType(inferredType); 97} 98 99void DestructuringContext::ValidateObjectLiteralType(ObjectType *objType, ir::ObjectExpression *objPattern) 100{ 101 for (const auto *sourceProp : objType->Properties()) { 102 const util::StringView &sourceName = sourceProp->Name(); 103 bool found = false; 104 105 for (const auto *targetProp : objPattern->Properties()) { 106 if (targetProp->IsRestElement()) { 107 continue; 108 } 109 110 ASSERT(targetProp->IsProperty()); 111 const util::StringView &targetName = targetProp->AsProperty()->Key()->AsIdentifier()->Name(); 112 113 if (sourceName == targetName) { 114 found = true; 115 break; 116 } 117 } 118 119 if (!found) { 120 checker_->ThrowTypeError({"Object literal may only specify known properties, and property '", sourceName, 121 "' does not exist in the pattern."}, 122 objPattern->Start()); 123 } 124 } 125} 126 127// Helper function to reduce HandleAssignmentPattern and pass code checker 128void DestructuringContext::HandleAssignmentPatternArrayPattern(ir::AssignmentExpression *assignmentPattern, 129 Type *inferredType) 130{ 131 ArrayDestructuringContext nextContext = ArrayDestructuringContext( 132 {checker_, assignmentPattern->Left(), inAssignment_, convertTupleToArray_, nullptr, nullptr}); 133 nextContext.SetInferredType(inferredType); 134 nextContext.Start(); 135} 136 137// Helper function to reduce HandleAssignmentPattern and pass code checker 138void DestructuringContext::HandleAssignmentPatternIdentifier(ir::AssignmentExpression *assignmentPattern, 139 Type *defaultType, Type *inferredType) 140{ 141 if (validateTypeAnnotation_ && !checker_->IsTypeAssignableTo(defaultType, inferredType)) { 142 checker_->ThrowAssignmentError(defaultType, inferredType, assignmentPattern->Left()->Start()); 143 } 144 145 SetInferredTypeForVariable(assignmentPattern->Left()->AsIdentifier()->Variable(), inferredType, 146 assignmentPattern->Start()); 147} 148 149void DestructuringContext::HandleAssignmentPattern(ir::AssignmentExpression *assignmentPattern, Type *inferredType, 150 bool validateDefault) 151{ 152 if (!assignmentPattern->Left()->IsArrayPattern()) { 153 checker_->RemoveStatus(CheckerStatus::FORCE_TUPLE); 154 } 155 156 Type *defaultType = assignmentPattern->Right()->Check(checker_); 157 if (!checker_->HasStatus(CheckerStatus::IN_CONST_CONTEXT)) { 158 defaultType = checker_->GetBaseTypeOfLiteralType(defaultType); 159 } 160 161 if (validateDefault && assignmentPattern->Right()->IsObjectExpression() && 162 assignmentPattern->Left()->IsObjectPattern()) { 163 ValidateObjectLiteralType(defaultType->AsObjectType(), assignmentPattern->Left()->AsObjectPattern()); 164 } 165 166 Type *initType = inferredType; 167 checker_->AddStatus(CheckerStatus::FORCE_TUPLE); 168 169 if (validateTypeAnnotation_) { 170 if (inferredType == nullptr) { 171 inferredType = checker_->GlobalUndefinedType(); 172 } 173 } else { 174 if (inferredType == nullptr) { 175 inferredType = defaultType; 176 } else if (inferredType->IsUnionType()) { 177 inferredType->AsUnionType()->AddConstituentType(defaultType, checker_->Relation()); 178 } else { 179 inferredType = checker_->CreateUnionType({inferredType, defaultType}); 180 } 181 } 182 183 if (assignmentPattern->Left()->IsIdentifier()) { 184 if (inAssignment_) { 185 HandleDestructuringAssignment(assignmentPattern->Left()->AsIdentifier(), initType, defaultType); 186 return; 187 } 188 189 HandleAssignmentPatternIdentifier(assignmentPattern, defaultType, inferredType); 190 return; 191 } 192 193 if (assignmentPattern->Left()->IsArrayPattern()) { 194 HandleAssignmentPatternArrayPattern(assignmentPattern, inferredType); 195 return; 196 } 197 198 ASSERT(assignmentPattern->Left()->IsObjectPattern()); 199 ObjectDestructuringContext nextContext = ObjectDestructuringContext( 200 {checker_, assignmentPattern->Left(), inAssignment_, convertTupleToArray_, nullptr, nullptr}); 201 nextContext.SetInferredType(inferredType); 202 nextContext.Start(); 203} 204 205void ArrayDestructuringContext::ValidateInferredType() 206{ 207 if (!inferredType_->IsArrayType() && !inferredType_->IsUnionType() && 208 (!inferredType_->IsObjectType() || !inferredType_->AsObjectType()->IsTupleType())) { 209 checker_->ThrowTypeError( 210 {"Type ", inferredType_, " must have a '[Symbol.iterator]()' method that returns an iterator."}, 211 id_->Start()); 212 } 213 214 if (inferredType_->IsUnionType()) { 215 for (auto *it : inferredType_->AsUnionType()->ConstituentTypes()) { 216 if (!it->IsArrayType() && (!it->IsObjectType() || !it->AsObjectType()->IsTupleType())) { 217 checker_->ThrowTypeError( 218 {"Type ", inferredType_, " must have a '[Symbol.iterator]()' method that returns an iterator."}, 219 id_->Start()); 220 } 221 } 222 } 223} 224 225Type *ArrayDestructuringContext::GetTypeFromTupleByIndex(TupleType *tuple) 226{ 227 util::StringView memberIndex = util::Helpers::ToStringView(checker_->Allocator(), index_); 228 varbinder::Variable *memberVar = tuple->GetProperty(memberIndex, false); 229 230 if (memberVar == nullptr) { 231 return nullptr; 232 } 233 234 return memberVar->TsType(); 235} 236 237Type *ArrayDestructuringContext::NextInferredType([[maybe_unused]] const util::StringView &searchName, bool throwError) 238{ 239 if (inferredType_->IsArrayType()) { 240 return inferredType_->AsArrayType()->ElementType(); 241 } 242 243 if (inferredType_->IsObjectType()) { 244 ASSERT(inferredType_->AsObjectType()->IsTupleType()); 245 Type *returnType = GetTypeFromTupleByIndex(inferredType_->AsObjectType()->AsTupleType()); 246 247 if (returnType == nullptr && throwError) { 248 if (!validateTypeAnnotation_ && checker_->HasStatus(CheckerStatus::IN_PARAMETER)) { 249 return returnType; 250 } 251 252 checker_->ThrowTypeError({"Tuple type ", inferredType_, " of length ", 253 inferredType_->AsObjectType()->AsTupleType()->FixedLength(), 254 " has no element at index ", index_, "."}, 255 id_->Start()); 256 } 257 258 return returnType; 259 } 260 261 ASSERT(inferredType_->IsUnionType()); 262 263 ArenaVector<Type *> unionTypes(checker_->Allocator()->Adapter()); 264 265 for (auto *type : inferredType_->AsUnionType()->ConstituentTypes()) { 266 if (type->IsArrayType()) { 267 unionTypes.push_back(type->AsArrayType()->ElementType()); 268 continue; 269 } 270 271 ASSERT(type->IsObjectType() && type->AsObjectType()->IsTupleType()); 272 Type *elementType = GetTypeFromTupleByIndex(type->AsObjectType()->AsTupleType()); 273 274 if (elementType == nullptr) { 275 continue; 276 } 277 278 unionTypes.push_back(elementType); 279 } 280 281 if (unionTypes.empty()) { 282 if (throwError) { 283 checker_->ThrowTypeError({"Property ", index_, " does not exist on type ", inferredType_, "."}, 284 id_->Start()); 285 } 286 287 return nullptr; 288 } 289 290 return checker_->CreateUnionType(std::move(unionTypes)); 291} 292 293Type *ArrayDestructuringContext::CreateArrayTypeForRest(UnionType *inferredType) 294{ 295 ArenaVector<Type *> unionTypes(checker_->Allocator()->Adapter()); 296 uint32_t savedIdx = index_; 297 298 for (auto *it : inferredType->ConstituentTypes()) { 299 if (it->IsArrayType()) { 300 unionTypes.push_back(it->AsArrayType()->ElementType()); 301 continue; 302 } 303 304 ASSERT(it->IsObjectType() && it->AsObjectType()->IsTupleType()); 305 Type *tupleElementType = GetTypeFromTupleByIndex(it->AsObjectType()->AsTupleType()); 306 307 while (tupleElementType != nullptr) { 308 unionTypes.push_back(tupleElementType); 309 index_++; 310 tupleElementType = GetTypeFromTupleByIndex(it->AsObjectType()->AsTupleType()); 311 } 312 313 index_ = savedIdx; 314 } 315 316 Type *restArrayElementType = checker_->CreateUnionType(std::move(unionTypes)); 317 return checker_->Allocator()->New<ArrayType>(restArrayElementType); 318} 319 320Type *ArrayDestructuringContext::CreateTupleTypeForRest(TupleType *tuple) 321{ 322 ObjectDescriptor *desc = checker_->Allocator()->New<ObjectDescriptor>(checker_->Allocator()); 323 ArenaVector<ElementFlags> elementFlags(checker_->Allocator()->Adapter()); 324 uint32_t savedIdx = index_; 325 uint32_t iterIndex = 0; 326 327 Type *tupleElementType = GetTypeFromTupleByIndex(tuple); 328 329 while (tupleElementType != nullptr) { 330 ElementFlags memberFlag = ElementFlags::REQUIRED; 331 util::StringView memberIndex = util::Helpers::ToStringView(checker_->Allocator(), iterIndex); 332 auto *memberVar = varbinder::Scope::CreateVar(checker_->Allocator(), memberIndex, 333 varbinder::VariableFlags::PROPERTY, nullptr); 334 memberVar->SetTsType(tupleElementType); 335 elementFlags.push_back(memberFlag); 336 desc->properties.push_back(memberVar); 337 338 index_++; 339 iterIndex++; 340 341 tupleElementType = GetTypeFromTupleByIndex(tuple); 342 } 343 344 index_ = savedIdx; 345 const checker::TupleTypeInfo tupleTypeInfo = {ElementFlags::REQUIRED, iterIndex, iterIndex, false}; 346 return checker_->CreateTupleType(desc, std::move(elementFlags), tupleTypeInfo); 347} 348 349Type *ArrayDestructuringContext::GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) 350{ 351 if (inferredType_->IsArrayType()) { 352 return inferredType_; 353 } 354 355 if (inferredType_->IsObjectType() && inferredType_->AsObjectType()->IsTupleType()) { 356 return CreateTupleTypeForRest(inferredType_->AsObjectType()->AsTupleType()); 357 } 358 359 ASSERT(inferredType_->IsUnionType()); 360 bool createArrayType = false; 361 362 for (auto *it : inferredType_->AsUnionType()->ConstituentTypes()) { 363 if (it->IsArrayType()) { 364 createArrayType = true; 365 break; 366 } 367 } 368 369 if (createArrayType) { 370 return CreateArrayTypeForRest(inferredType_->AsUnionType()); 371 } 372 373 ArenaVector<Type *> tupleUnion(checker_->Allocator()->Adapter()); 374 375 for (auto *it : inferredType_->AsUnionType()->ConstituentTypes()) { 376 ASSERT(it->IsObjectType() && it->AsObjectType()->IsTupleType()); 377 Type *newTuple = CreateTupleTypeForRest(it->AsObjectType()->AsTupleType()); 378 tupleUnion.push_back(newTuple); 379 } 380 381 return checker_->CreateUnionType(std::move(tupleUnion)); 382} 383 384void ArrayDestructuringContext::HandleRest(ir::SpreadElement *rest) 385{ 386 Type *inferredRestType = GetRestType(rest->Start()); 387 388 if (rest->Argument()->IsIdentifier()) { 389 if (inAssignment_) { 390 HandleDestructuringAssignment(rest->Argument()->AsIdentifier(), inferredRestType, nullptr); 391 return; 392 } 393 394 SetInferredTypeForVariable(rest->Argument()->AsIdentifier()->Variable(), inferredRestType, rest->Start()); 395 return; 396 } 397 398 if (rest->Argument()->IsArrayPattern()) { 399 ArrayDestructuringContext nextContext = ArrayDestructuringContext( 400 {checker_, rest->Argument(), inAssignment_, convertTupleToArray_, nullptr, nullptr}); 401 nextContext.SetInferredType(inferredRestType); 402 nextContext.Start(); 403 return; 404 } 405 406 ASSERT(rest->Argument()->IsObjectPattern()); 407 ObjectDestructuringContext nextContext = 408 ObjectDestructuringContext({checker_, rest->Argument(), inAssignment_, convertTupleToArray_, nullptr, nullptr}); 409 nextContext.SetInferredType(inferredRestType); 410 nextContext.Start(); 411} 412 413Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) 414{ 415 if (!convertTupleToArray_) { 416 return type; 417 } 418 419 if (type == nullptr) { 420 return type; 421 } 422 423 if (node->IsArrayPattern() || 424 (node->IsAssignmentPattern() && node->AsAssignmentPattern()->Left()->IsArrayPattern())) { 425 return type; 426 } 427 428 if (type->IsObjectType() && type->AsObjectType()->IsTupleType()) { 429 return type->AsObjectType()->AsTupleType()->ConvertToArrayType(checker_); 430 } 431 432 return type; 433} 434 435static void SetParameterType(ir::AstNode *parent, Type *type) 436{ 437 parent->Iterate([type](ir::AstNode *childNode) -> void { 438 if (childNode->IsIdentifier() && childNode->AsIdentifier()->Variable() != nullptr) { 439 childNode->AsIdentifier()->Variable()->SetTsType(type); 440 return; 441 } 442 443 SetParameterType(childNode, type); 444 }); 445} 446 447void ArrayDestructuringContext::SetRemainingParameterTypes() 448{ 449 do { 450 auto *it = id_->AsArrayPattern()->Elements()[index_]; 451 ASSERT(it); 452 SetParameterType(it, checker_->GlobalAnyType()); 453 } while (++index_ != id_->AsArrayPattern()->Elements().size()); 454} 455 456void ArrayDestructuringContext::HandleElement(ir::Expression *element, Type *nextInferredType) 457{ 458 switch (element->Type()) { 459 case ir::AstNodeType::IDENTIFIER: { 460 if (inAssignment_) { 461 HandleDestructuringAssignment(element->AsIdentifier(), nextInferredType, nullptr); 462 break; 463 } 464 465 SetInferredTypeForVariable(element->AsIdentifier()->Variable(), nextInferredType, element->Start()); 466 break; 467 } 468 case ir::AstNodeType::ARRAY_PATTERN: { 469 ArrayDestructuringContext nextContext = 470 ArrayDestructuringContext({checker_, element, inAssignment_, convertTupleToArray_, nullptr, nullptr}); 471 nextContext.SetInferredType(nextInferredType); 472 nextContext.Start(); 473 break; 474 } 475 case ir::AstNodeType::OBJECT_PATTERN: { 476 ObjectDestructuringContext nextContext = 477 ObjectDestructuringContext({checker_, element, inAssignment_, convertTupleToArray_, nullptr, nullptr}); 478 nextContext.SetInferredType(nextInferredType); 479 nextContext.Start(); 480 break; 481 } 482 case ir::AstNodeType::ASSIGNMENT_PATTERN: { 483 HandleAssignmentPattern(element->AsAssignmentPattern(), nextInferredType, false); 484 break; 485 } 486 case ir::AstNodeType::OMITTED_EXPRESSION: { 487 break; 488 } 489 default: { 490 UNREACHABLE(); 491 } 492 } 493} 494 495void ArrayDestructuringContext::Start() 496{ 497 ASSERT(id_->IsArrayPattern()); 498 499 ValidateInferredType(); 500 501 util::StringView name = util::Helpers::ToStringView(checker_->Allocator(), 0); 502 503 for (auto *it : id_->AsArrayPattern()->Elements()) { 504 if (it->IsRestElement()) { 505 HandleRest(it->AsRestElement()); 506 break; 507 } 508 509 Type *nextInferredType = 510 ConvertTupleTypeToArrayTypeIfNecessary(it, NextInferredType(name, !it->IsAssignmentPattern())); 511 512 if (nextInferredType == nullptr && checker_->HasStatus(CheckerStatus::IN_PARAMETER)) { 513 SetRemainingParameterTypes(); 514 return; 515 } 516 517 if (convertTupleToArray_ && nextInferredType != nullptr && inferredType_->IsObjectType()) { 518 ASSERT(inferredType_->AsObjectType()->IsTupleType()); 519 520 varbinder::Variable *currentTupleElement = inferredType_->AsObjectType()->Properties()[index_]; 521 522 if (currentTupleElement != nullptr) { 523 currentTupleElement->SetTsType(nextInferredType); 524 } 525 } 526 527 HandleElement(it, nextInferredType); 528 index_++; 529 } 530} 531 532void ObjectDestructuringContext::ValidateInferredType() 533{ 534 if (!inferredType_->IsObjectType()) { 535 return; 536 } 537 538 ValidateObjectLiteralType(inferredType_->AsObjectType(), id_->AsObjectPattern()); 539} 540 541void ObjectDestructuringContext::HandleRest(ir::SpreadElement *rest) 542{ 543 Type *inferredRestType = GetRestType(rest->Start()); 544 ASSERT(rest->Argument()->IsIdentifier()); 545 546 if (inAssignment_) { 547 HandleDestructuringAssignment(rest->Argument()->AsIdentifier(), inferredRestType, nullptr); 548 return; 549 } 550 551 SetInferredTypeForVariable(rest->Argument()->AsIdentifier()->Variable(), inferredRestType, rest->Start()); 552} 553 554Type *ObjectDestructuringContext::CreateObjectTypeForRest(ObjectType *objType) 555{ 556 ObjectDescriptor *desc = checker_->Allocator()->New<ObjectDescriptor>(checker_->Allocator()); 557 558 for (auto *it : objType->AsObjectType()->Properties()) { 559 if (!it->HasFlag(varbinder::VariableFlags::INFERRED_IN_PATTERN)) { 560 auto *memberVar = 561 varbinder::Scope::CreateVar(checker_->Allocator(), it->Name(), varbinder::VariableFlags::NONE, nullptr); 562 memberVar->SetTsType(it->TsType()); 563 memberVar->AddFlag(it->Flags()); 564 desc->properties.push_back(memberVar); 565 } 566 } 567 568 Type *returnType = checker_->Allocator()->New<ObjectLiteralType>(desc); 569 returnType->AsObjectType()->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); 570 return returnType; 571} 572 573Type *ObjectDestructuringContext::GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) 574{ 575 if (inferredType_->IsUnionType()) { 576 ArenaVector<Type *> unionTypes(checker_->Allocator()->Adapter()); 577 578 for (auto *it : inferredType_->AsUnionType()->ConstituentTypes()) { 579 if (it->IsObjectType()) { 580 unionTypes.push_back(CreateObjectTypeForRest(it->AsObjectType())); 581 continue; 582 } 583 584 checker_->ThrowTypeError("Rest types may only be created from object types.", loc); 585 } 586 587 return checker_->CreateUnionType(std::move(unionTypes)); 588 } 589 590 if (inferredType_->IsObjectType()) { 591 return CreateObjectTypeForRest(inferredType_->AsObjectType()); 592 } 593 594 checker_->ThrowTypeError("Rest types may only be created from object types.", loc); 595} 596 597Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) 598{ 599 if (!convertTupleToArray_) { 600 return type; 601 } 602 603 if (type == nullptr) { 604 return type; 605 } 606 607 ASSERT(node->IsProperty()); 608 609 ir::Property *property = node->AsProperty(); 610 611 if (property->Value()->IsArrayPattern()) { 612 return type; 613 } 614 615 if (property->Value()->IsAssignmentPattern() && 616 property->Value()->AsAssignmentPattern()->Left()->IsArrayPattern()) { 617 return type; 618 } 619 620 if (type->IsObjectType() && type->AsObjectType()->IsTupleType()) { 621 return type->AsObjectType()->AsTupleType()->ConvertToArrayType(checker_); 622 } 623 624 return type; 625} 626 627Type *ObjectDestructuringContext::NextInferredType([[maybe_unused]] const util::StringView &searchName, bool throwError) 628{ 629 varbinder::Variable *prop = checker_->GetPropertyOfType(inferredType_, searchName, !throwError, 630 varbinder::VariableFlags::INFERRED_IN_PATTERN); 631 632 if (prop != nullptr) { 633 prop->AddFlag(varbinder::VariableFlags::INFERRED_IN_PATTERN); 634 return prop->TsType(); 635 } 636 637 if (inferredType_->IsObjectType()) { 638 checker::ObjectType *objType = inferredType_->AsObjectType(); 639 640 if (objType->StringIndexInfo() != nullptr) { 641 return objType->StringIndexInfo()->GetType(); 642 } 643 } 644 645 if (throwError) { 646 checker_->ThrowTypeError({"Property ", searchName, " does not exist on type ", inferredType_, "."}, 647 id_->Start()); 648 } 649 650 return nullptr; 651} 652 653void ObjectDestructuringContext::Start() 654{ 655 ASSERT(id_->IsObjectPattern()); 656 657 if (!id_->AsObjectPattern()->Properties().back()->IsRestElement() && validateObjectPatternInitializer_) { 658 ValidateInferredType(); 659 } 660 661 for (auto *it : id_->AsObjectPattern()->Properties()) { 662 switch (it->Type()) { 663 case ir::AstNodeType::PROPERTY: { 664 ir::Property *property = it->AsProperty(); 665 666 if (property->IsComputed()) { 667 // NOTE: aszilagyi. 668 return; 669 } 670 671 Type *nextInferredType = ConvertTupleTypeToArrayTypeIfNecessary( 672 it->AsProperty(), 673 NextInferredType(property->Key()->AsIdentifier()->Name(), 674 (!property->Value()->IsAssignmentPattern() || validateTypeAnnotation_))); 675 676 if (property->Value()->IsIdentifier()) { 677 if (inAssignment_) { 678 HandleDestructuringAssignment(property->Value()->AsIdentifier(), nextInferredType, nullptr); 679 break; 680 } 681 682 SetInferredTypeForVariable(property->Value()->AsIdentifier()->Variable(), nextInferredType, 683 it->Start()); 684 break; 685 } 686 687 if (property->Value()->IsArrayPattern()) { 688 ArrayDestructuringContext nextContext = 689 ArrayDestructuringContext({checker_, property->Value()->AsArrayPattern(), inAssignment_, 690 convertTupleToArray_, nullptr, nullptr}); 691 nextContext.SetInferredType(nextInferredType); 692 nextContext.Start(); 693 break; 694 } 695 696 if (property->Value()->IsObjectPattern()) { 697 ObjectDestructuringContext nextContext = 698 ObjectDestructuringContext({checker_, property->Value()->AsObjectPattern(), inAssignment_, 699 convertTupleToArray_, nullptr, nullptr}); 700 nextContext.SetInferredType(nextInferredType); 701 nextContext.Start(); 702 break; 703 } 704 705 ASSERT(property->Value()->IsAssignmentPattern()); 706 HandleAssignmentPattern(property->Value()->AsAssignmentPattern(), nextInferredType, true); 707 break; 708 } 709 case ir::AstNodeType::REST_ELEMENT: { 710 HandleRest(it->AsRestElement()); 711 break; 712 } 713 default: { 714 UNREACHABLE(); 715 } 716 } 717 } 718} 719} // namespace ark::es2panda::checker 720