1/** 2 * Copyright (c) 2023-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 "etsTuple.h" 17 18#include "checker/types/ets/etsTupleType.h" 19#include "ir/astDump.h" 20 21namespace ark::es2panda::ir { 22 23void ETSTuple::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) 24{ 25 for (auto *&it : GetTupleTypeAnnotationsList()) { 26 if (auto *transformedNode = cb(it); it != transformedNode) { 27 it->SetTransformedNode(transformationName, transformedNode); 28 it = static_cast<TypeNode *>(transformedNode); 29 } 30 } 31 32 if (HasSpreadType()) { 33 if (auto *transformedNode = cb(spreadType_); spreadType_ != transformedNode) { 34 spreadType_->SetTransformedNode(transformationName, transformedNode); 35 spreadType_ = static_cast<TypeNode *>(transformedNode); 36 } 37 } 38} 39 40void ETSTuple::Iterate(const NodeTraverser &cb) const 41{ 42 for (auto *const it : GetTupleTypeAnnotationsList()) { 43 cb(it); 44 } 45 46 if (HasSpreadType()) { 47 cb(spreadType_); 48 } 49} 50 51void ETSTuple::Dump(ir::AstDumper *const dumper) const 52{ 53 dumper->Add({{"type", "ETSTuple"}, 54 {"types", AstDumper::Optional(typeAnnotationList_)}, 55 {"spreadType", AstDumper::Nullish(spreadType_)}}); 56} 57 58void ETSTuple::Dump(ir::SrcDumper *const dumper) const 59{ 60 dumper->Add("["); 61 for (const auto *const typeAnnot : typeAnnotationList_) { 62 typeAnnot->Dump(dumper); 63 if ((typeAnnot != typeAnnotationList_.back()) || (spreadType_ != nullptr)) { 64 dumper->Add(", "); 65 } 66 } 67 if (spreadType_ != nullptr) { 68 dumper->Add("..."); 69 spreadType_->Dump(dumper); 70 } 71 dumper->Add("]"); 72} 73 74void ETSTuple::Compile([[maybe_unused]] compiler::PandaGen *const pg) const {} 75void ETSTuple::Compile([[maybe_unused]] compiler::ETSGen *const etsg) const {} 76 77checker::Type *ETSTuple::Check([[maybe_unused]] checker::TSChecker *const checker) 78{ 79 return nullptr; 80} 81 82checker::Type *ETSTuple::Check([[maybe_unused]] checker::ETSChecker *const checker) 83{ 84 return GetType(checker); 85} 86 87checker::Type *ETSTuple::CalculateLUBForTuple(checker::ETSChecker *const checker, 88 ArenaVector<checker::Type *> &typeList, checker::Type **spreadTypePtr) 89{ 90 auto &spreadType = *spreadTypePtr; 91 if (typeList.empty()) { 92 return spreadType == nullptr ? checker->GlobalETSObjectType() : spreadType; 93 } 94 95 bool allElementsAreSame = std::all_of(typeList.begin(), typeList.end(), [&checker, &typeList](auto *element) { 96 return checker->Relation()->IsIdenticalTo(typeList[0], element); 97 }); 98 99 if (spreadType != nullptr) { 100 allElementsAreSame = allElementsAreSame && checker->Relation()->IsIdenticalTo(typeList[0], spreadType); 101 } 102 103 // If only one type present in the tuple, that will be the holder array type. If any two not identical types 104 // present, primitives will be boxed, and LUB is calculated for all of them. 105 // That makes it possible to assign eg. `[int, int, ...int[]]` tuple type to `int[]` array type. Because a 106 // `short[]` array already isn't assignable to `int[]` array, that preserve that the `[int, short, ...int[]]` 107 // tuple type's element type will be calculated to `Object[]`, which is not assignable to `int[]` array either. 108 if (allElementsAreSame) { 109 return typeList[0]; 110 } 111 // Other case - promote element types 112 // NOTE(vpukhov): #15570 normalization happens or not? 113 std::for_each(typeList.begin(), typeList.end(), [checker](auto &t) { t = checker->MaybePromotedBuiltinType(t); }); 114 115 auto ctypes = typeList; 116 if (spreadType != nullptr) { 117 spreadType = checker->MaybePromotedBuiltinType(spreadType); 118 ctypes.push_back(spreadType); 119 } 120 return checker->CreateETSUnionType(std::move(ctypes)); 121} 122 123checker::Type *ETSTuple::GetType(checker::ETSChecker *const checker) 124{ 125 if (TsType() != nullptr) { 126 return TsType(); 127 } 128 129 ArenaVector<checker::Type *> typeList(checker->Allocator()->Adapter()); 130 131 for (auto *const typeAnnotation : GetTupleTypeAnnotationsList()) { 132 auto *const checkedType = typeAnnotation->GetType(checker); 133 typeList.emplace_back(checkedType); 134 } 135 136 if (HasSpreadType()) { 137 ASSERT(spreadType_->IsTSArrayType()); 138 auto *const arrayType = spreadType_->GetType(checker); 139 ASSERT(arrayType->IsETSArrayType()); 140 spreadType_->SetTsType(arrayType->AsETSArrayType()->ElementType()); 141 } 142 143 auto *spreadElementType = spreadType_ != nullptr ? spreadType_->TsType() : nullptr; 144 145 auto *const tupleType = checker->Allocator()->New<checker::ETSTupleType>( 146 typeList, CalculateLUBForTuple(checker, typeList, &spreadElementType), spreadElementType); 147 148 SetTsType(tupleType); 149 return TsType(); 150} 151 152} // namespace ark::es2panda::ir 153