• 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 "arrayExpression.h"
17 
18 #include <typescript/core/destructuringContext.h>
19 #include <compiler/core/pandagen.h>
20 #include <ir/astDump.h>
21 #include <ir/base/spreadElement.h>
22 #include <ir/expressions/assignmentExpression.h>
23 #include <ir/expressions/objectExpression.h>
24 #include <ir/expressions/identifier.h>
25 
26 namespace panda::es2panda::ir {
27 
ConvertibleToArrayPattern()28 bool ArrayExpression::ConvertibleToArrayPattern()
29 {
30     bool restFound = false;
31     bool convResult = true;
32     for (auto *it : elements_) {
33         switch (it->Type()) {
34             case AstNodeType::ARRAY_EXPRESSION: {
35                 convResult = it->AsArrayExpression()->ConvertibleToArrayPattern();
36                 break;
37             }
38             case AstNodeType::SPREAD_ELEMENT: {
39                 if (!restFound && it == elements_.back() && !trailingComma_) {
40                     convResult = it->AsSpreadElement()->ConvertibleToRest(isDeclaration_);
41                 } else {
42                     convResult = false;
43                 }
44                 restFound = true;
45                 break;
46             }
47             case AstNodeType::OBJECT_EXPRESSION: {
48                 convResult = it->AsObjectExpression()->ConvertibleToObjectPattern();
49                 break;
50             }
51             case AstNodeType::ASSIGNMENT_EXPRESSION: {
52                 convResult = it->AsAssignmentExpression()->ConvertibleToAssignmentPattern();
53                 break;
54             }
55             case AstNodeType::META_PROPERTY_EXPRESSION:
56             case AstNodeType::CHAIN_EXPRESSION:
57             case AstNodeType::SEQUENCE_EXPRESSION: {
58                 convResult = false;
59                 break;
60             }
61             default: {
62                 break;
63             }
64         }
65 
66         if (!convResult) {
67             break;
68         }
69     }
70 
71     SetType(AstNodeType::ARRAY_PATTERN);
72     return convResult;
73 }
74 
ValidateExpression()75 ValidationInfo ArrayExpression::ValidateExpression()
76 {
77     ValidationInfo info;
78 
79     for (auto *it : elements_) {
80         switch (it->Type()) {
81             case AstNodeType::OBJECT_EXPRESSION: {
82                 info = it->AsObjectExpression()->ValidateExpression();
83                 break;
84             }
85             case AstNodeType::ARRAY_EXPRESSION: {
86                 info = it->AsArrayExpression()->ValidateExpression();
87                 break;
88             }
89             case AstNodeType::ASSIGNMENT_EXPRESSION: {
90                 auto *assignmentExpr = it->AsAssignmentExpression();
91 
92                 if (assignmentExpr->Left()->IsArrayExpression()) {
93                     info = assignmentExpr->Left()->AsArrayExpression()->ValidateExpression();
94                 } else if (assignmentExpr->Left()->IsObjectExpression()) {
95                     info = assignmentExpr->Left()->AsObjectExpression()->ValidateExpression();
96                 }
97 
98                 break;
99             }
100             case AstNodeType::SPREAD_ELEMENT: {
101                 info = it->AsSpreadElement()->ValidateExpression();
102                 break;
103             }
104             default: {
105                 break;
106             }
107         }
108 
109         if (info.Fail()) {
110             break;
111         }
112     }
113 
114     return info;
115 }
116 
Iterate(const NodeTraverser & cb) const117 void ArrayExpression::Iterate(const NodeTraverser &cb) const
118 {
119     for (auto *it : elements_) {
120         cb(it);
121     }
122 
123     if (typeAnnotation_) {
124         cb(typeAnnotation_);
125     }
126 }
127 
Dump(ir::AstDumper * dumper) const128 void ArrayExpression::Dump(ir::AstDumper *dumper) const
129 {
130     dumper->Add({{"type", type_ == AstNodeType::ARRAY_EXPRESSION ? "ArrayExpression" : "ArrayPattern"},
131                  {"elements", elements_},
132                  {"typeAnnotation", AstDumper::Optional(typeAnnotation_)},
133                  {"optional", AstDumper::Optional(optional_)}});
134 }
135 
Compile(compiler::PandaGen * pg) const136 void ArrayExpression::Compile(compiler::PandaGen *pg) const
137 {
138     compiler::RegScope rs(pg);
139     compiler::VReg arrayObj = pg->AllocReg();
140 
141     pg->CreateArray(this, elements_, arrayObj);
142 }
143 
GetSpreadElementType(checker::Checker * checker,checker::Type * spreadType,ArenaVector<checker::Type * > & elementTypes,const lexer::SourcePosition & loc)144 void GetSpreadElementType(checker::Checker *checker, checker::Type *spreadType,
145                           ArenaVector<checker::Type *> &elementTypes, const lexer::SourcePosition &loc)
146 {
147     bool inConstContext = checker->HasStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
148 
149     if (spreadType->IsObjectType() && spreadType->AsObjectType()->IsTupleType()) {
150         ArenaVector<checker::Type *> tupleElementTypes(checker->Allocator()->Adapter());
151         checker::TupleType *spreadTuple = spreadType->AsObjectType()->AsTupleType();
152 
153         for (auto *it : spreadTuple->Properties()) {
154             if (inConstContext) {
155                 elementTypes.push_back(it->TsType());
156                 continue;
157             }
158 
159             tupleElementTypes.push_back(it->TsType());
160         }
161 
162         if (inConstContext) {
163             return;
164         }
165 
166         elementTypes.push_back(checker->CreateUnionType(std::move(tupleElementTypes)));
167         return;
168     }
169 
170     // TODO(aszilagyi) handle const context cases in case of union spread type
171     if (spreadType->IsUnionType()) {
172         ArenaVector<checker::Type *> spreadTypes(checker->Allocator()->Adapter());
173         bool throwError = false;
174 
175         for (auto *type : spreadType->AsUnionType()->ConstituentTypes()) {
176             if (type->IsArrayType()) {
177                 spreadTypes.push_back(type->AsArrayType()->ElementType());
178                 continue;
179             }
180 
181             if (type->IsObjectType() && type->AsObjectType()->IsTupleType()) {
182                 checker::TupleType *tuple = type->AsObjectType()->AsTupleType();
183 
184                 for (auto *it : tuple->Properties()) {
185                     spreadTypes.push_back(it->TsType());
186                 }
187 
188                 continue;
189             }
190 
191             throwError = true;
192             break;
193         }
194 
195         if (!throwError) {
196             elementTypes.push_back(checker->CreateUnionType(std::move(spreadTypes)));
197             return;
198         }
199     }
200 
201     checker->ThrowTypeError(
202         {"Type '", spreadType, "' must have a '[Symbol.iterator]()' method that returns an iterator."}, loc);
203 }
204 
Check(checker::Checker * checker) const205 checker::Type *ArrayExpression::Check(checker::Checker *checker) const
206 {
207     ArenaVector<checker::Type *> elementTypes(checker->Allocator()->Adapter());
208     ArenaVector<checker::ElementFlags> elementFlags(checker->Allocator()->Adapter());
209     bool inConstContext = checker->HasStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
210     bool createTuple = checker->HasStatus(checker::CheckerStatus::FORCE_TUPLE);
211 
212     for (auto *it : elements_) {
213         if (it->IsSpreadElement()) {
214             checker::Type *spreadType = it->AsSpreadElement()->Argument()->Check(checker);
215 
216             if (spreadType->IsArrayType()) {
217                 elementTypes.push_back(inConstContext ? spreadType : spreadType->AsArrayType()->ElementType());
218                 elementFlags.push_back(checker::ElementFlags::VARIADIC);
219                 continue;
220             }
221 
222             GetSpreadElementType(checker, spreadType, elementTypes, it->Start());
223             elementFlags.push_back(checker::ElementFlags::REST);
224             continue;
225         }
226 
227         checker::Type *elementType = it->Check(checker);
228 
229         if (!inConstContext) {
230             elementType = checker->GetBaseTypeOfLiteralType(elementType);
231         }
232 
233         elementFlags.push_back(checker::ElementFlags::REQUIRED);
234         elementTypes.push_back(elementType);
235     }
236 
237     if (inConstContext || createTuple) {
238         checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
239         CHECK_NOT_NULL(desc);
240         uint32_t index = 0;
241 
242         for (auto it = elementTypes.begin(); it != elementTypes.end(); it++, index++) {
243             util::StringView memberIndex = util::Helpers::ToStringView(checker->Allocator(), index);
244             binder::LocalVariable *tupleMember =
245                 binder::Scope::CreateVar(checker->Allocator(), memberIndex, binder::VariableFlags::PROPERTY, nullptr);
246             CHECK_NOT_NULL(tupleMember);
247             if (inConstContext) {
248                 tupleMember->AddFlag(binder::VariableFlags::READONLY);
249             }
250 
251             tupleMember->SetTsType(*it);
252             desc->properties.push_back(tupleMember);
253         }
254 
255         return checker->CreateTupleType(desc, std::move(elementFlags), checker::ElementFlags::REQUIRED, index, index,
256                                         inConstContext);
257     }
258 
259     checker::Type *arrayElementType = nullptr;
260     if (elementTypes.empty()) {
261         arrayElementType = checker->GlobalAnyType();
262     } else {
263         arrayElementType = checker->CreateUnionType(std::move(elementTypes));
264     }
265 
266     return checker->Allocator()->New<checker::ArrayType>(arrayElementType);
267 }
268 
CheckPattern(checker::Checker * checker) const269 checker::Type *ArrayExpression::CheckPattern(checker::Checker *checker) const
270 {
271     checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
272     CHECK_NOT_NULL(desc);
273     ArenaVector<checker::ElementFlags> elementFlags(checker->Allocator()->Adapter());
274     checker::ElementFlags combinedFlags = checker::ElementFlags::NO_OPTS;
275     uint32_t minLength = 0;
276     uint32_t index = elements_.size();
277     bool addOptional = true;
278 
279     for (auto it = elements_.rbegin(); it != elements_.rend(); it++) {
280         checker::Type *elementType = nullptr;
281         checker::ElementFlags memberFlag = checker::ElementFlags::NO_OPTS;
282 
283         switch ((*it)->Type()) {
284             case ir::AstNodeType::REST_ELEMENT: {
285                 elementType = checker->Allocator()->New<checker::ArrayType>(checker->GlobalAnyType());
286                 memberFlag = checker::ElementFlags::REST;
287                 addOptional = false;
288                 break;
289             }
290             case ir::AstNodeType::OBJECT_PATTERN: {
291                 elementType = (*it)->AsObjectPattern()->CheckPattern(checker);
292                 memberFlag = checker::ElementFlags::REQUIRED;
293                 addOptional = false;
294                 break;
295             }
296             case ir::AstNodeType::ARRAY_PATTERN: {
297                 elementType = (*it)->AsArrayPattern()->CheckPattern(checker);
298                 memberFlag = checker::ElementFlags::REQUIRED;
299                 addOptional = false;
300                 break;
301             }
302             case ir::AstNodeType::ASSIGNMENT_PATTERN: {
303                 const ir::AssignmentExpression *assignmentPattern = (*it)->AsAssignmentPattern();
304 
305                 if (assignmentPattern->Left()->IsIdentifier()) {
306                     const ir::Identifier *ident = assignmentPattern->Left()->AsIdentifier();
307                     ASSERT(ident->Variable());
308                     binder::Variable *bindingVar = ident->Variable();
309                     checker::Type *initializerType =
310                         checker->GetBaseTypeOfLiteralType(assignmentPattern->Right()->Check(checker));
311                     bindingVar->SetTsType(initializerType);
312                     elementType = initializerType;
313                 } else if (assignmentPattern->Left()->IsArrayPattern()) {
314                     auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
315                     auto destructuringContext =
316                         checker::ArrayDestructuringContext(checker, assignmentPattern->Left()->AsArrayPattern(), false,
317                                                            true, nullptr, assignmentPattern->Right());
318                     destructuringContext.Start();
319                     elementType = destructuringContext.InferedType();
320                 } else {
321                     ASSERT(assignmentPattern->Left()->IsObjectPattern());
322                     auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
323                     auto destructuringContext =
324                         checker::ObjectDestructuringContext(checker, assignmentPattern->Left()->AsObjectPattern(),
325                                                             false, true, nullptr, assignmentPattern->Right());
326                     destructuringContext.Start();
327                     elementType = destructuringContext.InferedType();
328                 }
329 
330                 if (addOptional) {
331                     memberFlag = checker::ElementFlags::OPTIONAL;
332                 } else {
333                     memberFlag = checker::ElementFlags::REQUIRED;
334                 }
335 
336                 break;
337             }
338             case ir::AstNodeType::OMITTED_EXPRESSION: {
339                 elementType = checker->GlobalAnyType();
340                 memberFlag = checker::ElementFlags::REQUIRED;
341                 addOptional = false;
342                 break;
343             }
344             case ir::AstNodeType::IDENTIFIER: {
345                 const ir::Identifier *ident = (*it)->AsIdentifier();
346                 ASSERT(ident->Variable());
347                 elementType = checker->GlobalAnyType();
348                 ident->Variable()->SetTsType(elementType);
349                 memberFlag = checker::ElementFlags::REQUIRED;
350                 addOptional = false;
351                 break;
352             }
353             default: {
354                 UNREACHABLE();
355             }
356         }
357 
358         util::StringView memberIndex = util::Helpers::ToStringView(checker->Allocator(), index - 1);
359 
360         auto *memberVar =
361             binder::Scope::CreateVar(checker->Allocator(), memberIndex, binder::VariableFlags::PROPERTY, *it);
362 
363         if (memberFlag == checker::ElementFlags::OPTIONAL) {
364             memberVar->AddFlag(binder::VariableFlags::OPTIONAL);
365         } else {
366             minLength++;
367         }
368 
369         memberVar->SetTsType(elementType);
370         elementFlags.push_back(memberFlag);
371         desc->properties.insert(desc->properties.begin(), memberVar);
372 
373         combinedFlags |= memberFlag;
374         index--;
375     }
376 
377     return checker->CreateTupleType(desc, std::move(elementFlags), combinedFlags, minLength, desc->properties.size(),
378                                     false);
379 }
380 
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)381 void ArrayExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
382 {
383     for (auto iter = elements_.begin(); iter != elements_.end(); iter++) {
384         *iter = std::get<ir::AstNode *>(cb(*iter))->AsExpression();
385     }
386 }
387 
388 }  // namespace panda::es2panda::ir
389