1/** 2 * Copyright (c) 2021-2024 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 "checker/ETSchecker.h" 19#include "checker/TSchecker.h" 20#include "checker/types/ets/etsTupleType.h" 21#include "checker/ets/typeRelationContext.h" 22#include "checker/ts/destructuringContext.h" 23#include "compiler/core/ETSGen.h" 24#include "compiler/core/pandagen.h" 25#include "ir/astDump.h" 26#include "ir/base/decorator.h" 27#include "ir/srcDump.h" 28#include "ir/typeNode.h" 29#include "ir/base/spreadElement.h" 30#include "ir/expressions/assignmentExpression.h" 31#include "ir/expressions/identifier.h" 32#include "ir/expressions/objectExpression.h" 33#include "util/helpers.h" 34 35namespace ark::es2panda::ir { 36ArrayExpression::ArrayExpression([[maybe_unused]] Tag const tag, ArrayExpression const &other, 37 ArenaAllocator *const allocator) 38 : AnnotatedExpression(static_cast<AnnotatedExpression const &>(other), allocator), 39 decorators_(allocator->Adapter()), 40 elements_(allocator->Adapter()) 41{ 42 preferredType_ = other.preferredType_; 43 isDeclaration_ = other.isDeclaration_; 44 trailingComma_ = other.trailingComma_; 45 optional_ = other.optional_; 46 47 for (auto *element : other.elements_) { 48 elements_.emplace_back(element->Clone(allocator, this)->AsExpression()); 49 } 50 51 for (auto *decorator : other.decorators_) { 52 decorators_.emplace_back(decorator->Clone(allocator, this)); 53 } 54} 55 56ArrayExpression *ArrayExpression::Clone(ArenaAllocator *const allocator, AstNode *const parent) 57{ 58 if (auto *const clone = allocator->New<ArrayExpression>(Tag {}, *this, allocator); clone != nullptr) { 59 if (parent != nullptr) { 60 clone->SetParent(parent); 61 } 62 return clone; 63 } 64 throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR); 65} 66 67bool ArrayExpression::ConvertibleToArrayPattern() 68{ 69 bool restFound = false; 70 bool convResult = true; 71 for (auto *it : elements_) { 72 switch (it->Type()) { 73 case AstNodeType::ARRAY_EXPRESSION: { 74 convResult = it->AsArrayExpression()->ConvertibleToArrayPattern(); 75 break; 76 } 77 case AstNodeType::SPREAD_ELEMENT: { 78 if (!restFound && it == elements_.back() && !trailingComma_) { 79 convResult = it->AsSpreadElement()->ConvertibleToRest(isDeclaration_); 80 } else { 81 convResult = false; 82 } 83 restFound = true; 84 break; 85 } 86 case AstNodeType::OBJECT_EXPRESSION: { 87 convResult = it->AsObjectExpression()->ConvertibleToObjectPattern(); 88 break; 89 } 90 case AstNodeType::ASSIGNMENT_EXPRESSION: { 91 convResult = it->AsAssignmentExpression()->ConvertibleToAssignmentPattern(); 92 break; 93 } 94 case AstNodeType::MEMBER_EXPRESSION: 95 case AstNodeType::OMITTED_EXPRESSION: 96 case AstNodeType::IDENTIFIER: 97 case AstNodeType::ARRAY_PATTERN: 98 case AstNodeType::OBJECT_PATTERN: 99 case AstNodeType::ASSIGNMENT_PATTERN: 100 case AstNodeType::REST_ELEMENT: { 101 break; 102 } 103 default: { 104 convResult = false; 105 break; 106 } 107 } 108 109 if (!convResult) { 110 break; 111 } 112 } 113 114 SetType(AstNodeType::ARRAY_PATTERN); 115 return convResult; 116} 117 118ValidationInfo ArrayExpression::ValidateExpression() 119{ 120 if (optional_) { 121 return {"Unexpected token '?'.", Start()}; 122 } 123 124 if (TypeAnnotation() != nullptr) { 125 return {"Unexpected token.", TypeAnnotation()->Start()}; 126 } 127 128 ValidationInfo info; 129 130 for (auto *it : elements_) { 131 switch (it->Type()) { 132 case AstNodeType::OBJECT_EXPRESSION: { 133 info = it->AsObjectExpression()->ValidateExpression(); 134 break; 135 } 136 case AstNodeType::ARRAY_EXPRESSION: { 137 info = it->AsArrayExpression()->ValidateExpression(); 138 break; 139 } 140 case AstNodeType::ASSIGNMENT_EXPRESSION: { 141 auto *assignmentExpr = it->AsAssignmentExpression(); 142 143 if (assignmentExpr->Left()->IsArrayExpression()) { 144 info = assignmentExpr->Left()->AsArrayExpression()->ValidateExpression(); 145 } else if (assignmentExpr->Left()->IsObjectExpression()) { 146 info = assignmentExpr->Left()->AsObjectExpression()->ValidateExpression(); 147 } 148 149 break; 150 } 151 case AstNodeType::SPREAD_ELEMENT: { 152 info = it->AsSpreadElement()->ValidateExpression(); 153 break; 154 } 155 default: { 156 break; 157 } 158 } 159 160 if (info.Fail()) { 161 break; 162 } 163 } 164 165 return info; 166} 167 168void ArrayExpression::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) 169{ 170 for (auto *&it : decorators_) { 171 if (auto *transformedNode = cb(it); it != transformedNode) { 172 it->SetTransformedNode(transformationName, transformedNode); 173 it = transformedNode->AsDecorator(); 174 } 175 } 176 177 for (auto *&it : elements_) { 178 if (auto *transformedNode = cb(it); it != transformedNode) { 179 it->SetTransformedNode(transformationName, transformedNode); 180 it = transformedNode->AsExpression(); 181 } 182 } 183 184 if (auto *typeAnnotation = TypeAnnotation(); typeAnnotation != nullptr) { 185 if (auto *transformedNode = cb(typeAnnotation); typeAnnotation != transformedNode) { 186 typeAnnotation->SetTransformedNode(transformationName, transformedNode); 187 SetTsTypeAnnotation(static_cast<TypeNode *>(transformedNode)); 188 } 189 } 190} 191 192void ArrayExpression::Iterate(const NodeTraverser &cb) const 193{ 194 for (auto *it : decorators_) { 195 cb(it); 196 } 197 198 for (auto *it : elements_) { 199 cb(it); 200 } 201 202 if (TypeAnnotation() != nullptr) { 203 cb(TypeAnnotation()); 204 } 205} 206 207void ArrayExpression::Dump(ir::AstDumper *dumper) const 208{ 209 dumper->Add({{"type", type_ == AstNodeType::ARRAY_EXPRESSION ? "ArrayExpression" : "ArrayPattern"}, 210 {"decorators", AstDumper::Optional(decorators_)}, 211 {"elements", elements_}, 212 {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}, 213 {"optional", AstDumper::Optional(optional_)}}); 214} 215 216void ArrayExpression::Dump(ir::SrcDumper *dumper) const 217{ 218 dumper->Add("["); 219 for (auto element : elements_) { 220 element->Dump(dumper); 221 if (element != elements_.back()) { 222 dumper->Add(", "); 223 } 224 } 225 dumper->Add("]"); 226} 227 228void ArrayExpression::Compile(compiler::PandaGen *pg) const 229{ 230 pg->GetAstCompiler()->Compile(this); 231} 232 233void ArrayExpression::Compile(compiler::ETSGen *const etsg) const 234{ 235 etsg->GetAstCompiler()->Compile(this); 236} 237 238checker::Type *ArrayExpression::Check(checker::TSChecker *checker) 239{ 240 return checker->GetAnalyzer()->Check(this); 241} 242 243checker::Type *CheckAssignmentPattern(Expression *it, checker::TSChecker *checker, checker::Type *elementType, 244 bool &addOptional, checker::ElementFlags &memberFlag) 245{ 246 auto *assignmentPattern = it->AsAssignmentPattern(); 247 if (assignmentPattern->Left()->IsIdentifier()) { 248 const ir::Identifier *ident = assignmentPattern->Left()->AsIdentifier(); 249 ASSERT(ident->Variable()); 250 varbinder::Variable *bindingVar = ident->Variable(); 251 checker::Type *initializerType = checker->GetBaseTypeOfLiteralType(assignmentPattern->Right()->Check(checker)); 252 bindingVar->SetTsType(initializerType); 253 elementType = initializerType; 254 } else if (assignmentPattern->Left()->IsArrayPattern()) { 255 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE); 256 auto destructuringContext = checker::ArrayDestructuringContext( 257 {checker, assignmentPattern->Left()->AsArrayPattern(), false, true, nullptr, assignmentPattern->Right()}); 258 destructuringContext.Start(); 259 elementType = destructuringContext.InferredType(); 260 } else { 261 ASSERT(assignmentPattern->Left()->IsObjectPattern()); 262 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE); 263 auto destructuringContext = checker::ObjectDestructuringContext( 264 {checker, assignmentPattern->Left()->AsObjectPattern(), false, true, nullptr, assignmentPattern->Right()}); 265 destructuringContext.Start(); 266 elementType = destructuringContext.InferredType(); 267 } 268 269 if (addOptional) { 270 memberFlag = checker::ElementFlags::OPTIONAL; 271 } else { 272 memberFlag = checker::ElementFlags::REQUIRED; 273 } 274 return elementType; 275} 276 277checker::Type *CheckElementPattern(Expression *it, checker::Type *elementType, checker::TSChecker *checker, 278 bool &addOptional, checker::ElementFlags &memberFlag) 279{ 280 switch (it->Type()) { 281 case ir::AstNodeType::REST_ELEMENT: { 282 elementType = checker->Allocator()->New<checker::ArrayType>(checker->GlobalAnyType()); 283 memberFlag = checker::ElementFlags::REST; 284 addOptional = false; 285 return elementType; 286 } 287 case ir::AstNodeType::OBJECT_PATTERN: { 288 elementType = it->AsObjectPattern()->CheckPattern(checker); 289 memberFlag = checker::ElementFlags::REQUIRED; 290 addOptional = false; 291 return elementType; 292 } 293 case ir::AstNodeType::ARRAY_PATTERN: { 294 elementType = it->AsArrayPattern()->CheckPattern(checker); 295 memberFlag = checker::ElementFlags::REQUIRED; 296 addOptional = false; 297 return elementType; 298 } 299 case ir::AstNodeType::ASSIGNMENT_PATTERN: { 300 return CheckAssignmentPattern(it, checker, elementType, addOptional, memberFlag); 301 } 302 case ir::AstNodeType::OMITTED_EXPRESSION: { 303 elementType = checker->GlobalAnyType(); 304 memberFlag = checker::ElementFlags::REQUIRED; 305 addOptional = false; 306 return elementType; 307 } 308 case ir::AstNodeType::IDENTIFIER: { 309 const ir::Identifier *ident = it->AsIdentifier(); 310 ASSERT(ident->Variable()); 311 elementType = checker->GlobalAnyType(); 312 ident->Variable()->SetTsType(elementType); 313 memberFlag = checker::ElementFlags::REQUIRED; 314 addOptional = false; 315 return elementType; 316 } 317 default: { 318 UNREACHABLE(); 319 } 320 } 321} 322 323checker::Type *ArrayExpression::CheckPattern(checker::TSChecker *checker) 324{ 325 checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator()); 326 ArenaVector<checker::ElementFlags> elementFlags(checker->Allocator()->Adapter()); 327 checker::ElementFlags combinedFlags = checker::ElementFlags::NO_OPTS; 328 uint32_t minLength = 0; 329 uint32_t index = elements_.size(); 330 bool addOptional = true; 331 332 for (auto it = elements_.rbegin(); it != elements_.rend(); it++) { 333 checker::Type *elementType = nullptr; 334 checker::ElementFlags memberFlag = checker::ElementFlags::NO_OPTS; 335 336 elementType = CheckElementPattern(*it, elementType, checker, addOptional, memberFlag); 337 338 util::StringView memberIndex = util::Helpers::ToStringView(checker->Allocator(), index - 1); 339 340 auto *memberVar = 341 varbinder::Scope::CreateVar(checker->Allocator(), memberIndex, varbinder::VariableFlags::PROPERTY, *it); 342 343 if (memberFlag == checker::ElementFlags::OPTIONAL) { 344 memberVar->AddFlag(varbinder::VariableFlags::OPTIONAL); 345 } else { 346 minLength++; 347 } 348 349 memberVar->SetTsType(elementType); 350 elementFlags.push_back(memberFlag); 351 desc->properties.insert(desc->properties.begin(), memberVar); 352 353 combinedFlags |= memberFlag; 354 index--; 355 } 356 357 const checker::TupleTypeInfo tupleTypeInfo = {combinedFlags, minLength, 358 static_cast<uint32_t>(desc->properties.size()), false}; 359 return checker->CreateTupleType(desc, std::move(elementFlags), tupleTypeInfo); 360} 361 362bool ArrayExpression::HandleNestedArrayExpression(checker::ETSChecker *const checker, 363 ArrayExpression *const currentElement, const bool isPreferredTuple, 364 const std::size_t idx) 365{ 366 if (isPreferredTuple) { 367 currentElement->SetPreferredType(preferredType_->AsETSTupleType()->GetTypeAtIndex(idx)); 368 369 if (currentElement->GetPreferredType()->IsETSTupleType()) { 370 if (!checker->ValidateTupleMinElementSize(currentElement, 371 currentElement->GetPreferredType()->AsETSTupleType())) { 372 return false; 373 } 374 } 375 376 return true; 377 } 378 379 if (preferredType_->IsETSArrayType()) { 380 if (preferredType_->AsETSArrayType()->ElementType()->IsETSTupleType()) { 381 if (!checker->ValidateTupleMinElementSize( 382 currentElement, preferredType_->AsETSArrayType()->ElementType()->AsETSTupleType())) { 383 return false; 384 } 385 } 386 387 currentElement->SetPreferredType(preferredType_->AsETSArrayType()->ElementType()); 388 return true; 389 } 390 391 if (currentElement->GetPreferredType() == nullptr) { 392 currentElement->SetPreferredType(preferredType_); 393 } 394 return true; 395} 396 397checker::Type *ArrayExpression::Check(checker::ETSChecker *checker) 398{ 399 return checker->GetAnalyzer()->Check(this); 400} 401 402void ArrayExpression::GetPrefferedTypeFromFuncParam(checker::ETSChecker *checker, Expression *param, 403 checker::TypeRelationFlag flags) 404{ 405 if (preferredType_ != nullptr) { 406 return; 407 } 408 auto paramType = param->Check(checker); 409 if (paramType->IsETSArrayType()) { 410 auto *elementType = paramType->AsETSArrayType()->ElementType(); 411 bool isAssignable = true; 412 for (auto elem : elements_) { 413 auto assignCtx = 414 checker::AssignmentContext(checker->Relation(), elem, elem->Check(checker), elementType, elem->Start(), 415 {""}, checker::TypeRelationFlag::NO_THROW | flags); 416 isAssignable &= assignCtx.IsAssignable(); 417 } 418 if (isAssignable) { 419 preferredType_ = paramType; 420 } 421 } 422} 423 424} // namespace ark::es2panda::ir 425