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