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