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 29namespace panda::es2panda::ir { 30 31bool 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 78ValidationInfo 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 120void 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 131void 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 139void 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 147void 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 208checker::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 CHECK_NOT_NULL(desc); 243 uint32_t index = 0; 244 245 for (auto it = elementTypes.begin(); it != elementTypes.end(); it++, index++) { 246 util::StringView memberIndex = util::Helpers::ToStringView(checker->Allocator(), index); 247 binder::LocalVariable *tupleMember = 248 binder::Scope::CreateVar(checker->Allocator(), memberIndex, binder::VariableFlags::PROPERTY, nullptr); 249 CHECK_NOT_NULL(tupleMember); 250 if (inConstContext) { 251 tupleMember->AddFlag(binder::VariableFlags::READONLY); 252 } 253 254 tupleMember->SetTsType(*it); 255 desc->properties.push_back(tupleMember); 256 } 257 258 return checker->CreateTupleType(desc, std::move(elementFlags), checker::ElementFlags::REQUIRED, index, index, 259 inConstContext); 260 } 261 262 checker::Type *arrayElementType = nullptr; 263 if (elementTypes.empty()) { 264 arrayElementType = checker->GlobalAnyType(); 265 } else { 266 arrayElementType = checker->CreateUnionType(std::move(elementTypes)); 267 } 268 269 return checker->Allocator()->New<checker::ArrayType>(arrayElementType); 270} 271 272checker::Type *ArrayExpression::CheckPattern(checker::Checker *checker) const 273{ 274 checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator()); 275 CHECK_NOT_NULL(desc); 276 ArenaVector<checker::ElementFlags> elementFlags(checker->Allocator()->Adapter()); 277 checker::ElementFlags combinedFlags = checker::ElementFlags::NO_OPTS; 278 uint32_t minLength = 0; 279 uint32_t index = elements_.size(); 280 bool addOptional = true; 281 282 for (auto it = elements_.rbegin(); it != elements_.rend(); it++) { 283 checker::Type *elementType = nullptr; 284 checker::ElementFlags memberFlag = checker::ElementFlags::NO_OPTS; 285 286 switch ((*it)->Type()) { 287 case ir::AstNodeType::REST_ELEMENT: { 288 elementType = checker->Allocator()->New<checker::ArrayType>(checker->GlobalAnyType()); 289 memberFlag = checker::ElementFlags::REST; 290 addOptional = false; 291 break; 292 } 293 case ir::AstNodeType::OBJECT_PATTERN: { 294 elementType = (*it)->AsObjectPattern()->CheckPattern(checker); 295 memberFlag = checker::ElementFlags::REQUIRED; 296 addOptional = false; 297 break; 298 } 299 case ir::AstNodeType::ARRAY_PATTERN: { 300 elementType = (*it)->AsArrayPattern()->CheckPattern(checker); 301 memberFlag = checker::ElementFlags::REQUIRED; 302 addOptional = false; 303 break; 304 } 305 case ir::AstNodeType::ASSIGNMENT_PATTERN: { 306 const ir::AssignmentExpression *assignmentPattern = (*it)->AsAssignmentPattern(); 307 308 if (assignmentPattern->Left()->IsIdentifier()) { 309 const ir::Identifier *ident = assignmentPattern->Left()->AsIdentifier(); 310 ASSERT(ident->Variable()); 311 binder::Variable *bindingVar = ident->Variable(); 312 checker::Type *initializerType = 313 checker->GetBaseTypeOfLiteralType(assignmentPattern->Right()->Check(checker)); 314 bindingVar->SetTsType(initializerType); 315 elementType = initializerType; 316 } else if (assignmentPattern->Left()->IsArrayPattern()) { 317 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE); 318 auto destructuringContext = 319 checker::ArrayDestructuringContext(checker, assignmentPattern->Left()->AsArrayPattern(), false, 320 true, nullptr, assignmentPattern->Right()); 321 destructuringContext.Start(); 322 elementType = destructuringContext.InferedType(); 323 } else { 324 ASSERT(assignmentPattern->Left()->IsObjectPattern()); 325 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE); 326 auto destructuringContext = 327 checker::ObjectDestructuringContext(checker, assignmentPattern->Left()->AsObjectPattern(), 328 false, true, nullptr, assignmentPattern->Right()); 329 destructuringContext.Start(); 330 elementType = destructuringContext.InferedType(); 331 } 332 333 if (addOptional) { 334 memberFlag = checker::ElementFlags::OPTIONAL; 335 } else { 336 memberFlag = checker::ElementFlags::REQUIRED; 337 } 338 339 break; 340 } 341 case ir::AstNodeType::OMITTED_EXPRESSION: { 342 elementType = checker->GlobalAnyType(); 343 memberFlag = checker::ElementFlags::REQUIRED; 344 addOptional = false; 345 break; 346 } 347 case ir::AstNodeType::IDENTIFIER: { 348 const ir::Identifier *ident = (*it)->AsIdentifier(); 349 ASSERT(ident->Variable()); 350 elementType = checker->GlobalAnyType(); 351 ident->Variable()->SetTsType(elementType); 352 memberFlag = checker::ElementFlags::REQUIRED; 353 addOptional = false; 354 break; 355 } 356 default: { 357 UNREACHABLE(); 358 } 359 } 360 361 util::StringView memberIndex = util::Helpers::ToStringView(checker->Allocator(), index - 1); 362 363 auto *memberVar = 364 binder::Scope::CreateVar(checker->Allocator(), memberIndex, binder::VariableFlags::PROPERTY, *it); 365 366 if (memberFlag == checker::ElementFlags::OPTIONAL) { 367 memberVar->AddFlag(binder::VariableFlags::OPTIONAL); 368 } else { 369 minLength++; 370 } 371 372 memberVar->SetTsType(elementType); 373 elementFlags.push_back(memberFlag); 374 desc->properties.insert(desc->properties.begin(), memberVar); 375 376 combinedFlags |= memberFlag; 377 index--; 378 } 379 380 return checker->CreateTupleType(desc, std::move(elementFlags), combinedFlags, minLength, desc->properties.size(), 381 false); 382} 383 384void ArrayExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder) 385{ 386 for (auto iter = elements_.begin(); iter != elements_.end(); iter++) { 387 *iter = std::get<ir::AstNode *>(cb(*iter))->AsExpression(); 388 } 389} 390 391} // namespace panda::es2panda::ir 392