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