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