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