• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "etsTupleType.h"
17 
18 #include "checker/ETSchecker.h"
19 #include "checker/ets/conversion.h"
20 #include "ir/ets/etsTuple.h"
21 
22 namespace ark::es2panda::checker {
ToString(std::stringstream & ss,bool precise) const23 void ETSTupleType::ToString(std::stringstream &ss, bool precise) const
24 {
25     if (HasTypeFlag(TypeFlag::READONLY)) {
26         ss << "readonly ";
27     }
28 
29     ss << "[";
30 
31     for (auto it = typeList_.begin(); it != typeList_.end(); it++) {
32         (*it)->ToString(ss, precise);
33 
34         if (std::next(it) != typeList_.end()) {
35             ss << ", ";
36         }
37     }
38 
39     if (spreadType_ != nullptr) {
40         ss << ", ...";
41         spreadType_->ToString(ss, precise);
42         ss << "[]";
43     }
44 
45     ss << "]";
46 }
47 
GetTypeAtIndex(const TupleSizeType index) const48 Type *ETSTupleType::GetTypeAtIndex(const TupleSizeType index) const
49 {
50     return index >= GetTupleSize() ? GetSpreadType() : GetTupleTypesList().at(static_cast<std::size_t>(index));
51 }
52 
Identical(TypeRelation * const relation,Type * const other)53 void ETSTupleType::Identical([[maybe_unused]] TypeRelation *const relation, Type *const other)
54 {
55     if (!other->IsETSTupleType()) {
56         return;
57     }
58 
59     const auto *const otherTuple = other->AsETSTupleType();
60 
61     if (GetMinTupleSize() != otherTuple->GetMinTupleSize()) {
62         return;
63     }
64 
65     for (TupleSizeType idx = 0; idx < GetMinTupleSize(); ++idx) {
66         if (!relation->IsIdenticalTo(GetTypeAtIndex(idx), otherTuple->GetTypeAtIndex(idx))) {
67             relation->Result(false);
68             return;
69         }
70     }
71 
72     if (HasSpreadType() != otherTuple->HasSpreadType()) {
73         relation->Result(false);
74         return;
75     }
76 
77     relation->Result(true);
78 }
79 
AssignmentSource(TypeRelation * const relation,Type * const target)80 bool ETSTupleType::AssignmentSource(TypeRelation *const relation, Type *const target)
81 {
82     if (!(target->IsETSTupleType() || target->IsETSArrayType())) {
83         return false;
84     }
85 
86     if (!target->IsETSTupleType()) {
87         ASSERT(target->IsETSArrayType());
88         auto *const arrayTarget = target->AsETSArrayType();
89 
90         const SavedTypeRelationFlagsContext savedFlagsCtx(
91             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
92 
93         relation->Result(relation->IsAssignableTo(ElementType(), arrayTarget->ElementType()));
94     }
95 
96     return relation->IsTrue();
97 }
98 
AssignmentTarget(TypeRelation * const relation,Type * const source)99 void ETSTupleType::AssignmentTarget(TypeRelation *const relation, Type *const source)
100 {
101     if (source->HasTypeFlag(TypeFlag::READONLY)) {
102         relation->Result(false);
103         return;
104     }
105 
106     if (!(source->IsETSTupleType() || (source->IsETSArrayType() && HasSpreadType()))) {
107         return;
108     }
109 
110     if (!source->IsETSTupleType()) {
111         ASSERT(source->IsETSArrayType());
112         auto *const arraySource = source->AsETSArrayType();
113 
114         const SavedTypeRelationFlagsContext savedFlagsCtx(
115             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
116 
117         relation->Result(relation->IsAssignableTo(arraySource->ElementType(), ElementType()));
118         return;
119     }
120 
121     const auto *const tupleSource = source->AsETSTupleType();
122 
123     if (tupleSource->GetMinTupleSize() != GetMinTupleSize()) {
124         return;
125     }
126 
127     for (int32_t idx = 0; idx < GetMinTupleSize(); ++idx) {
128         // because an array assignment to another array simply copies it's memory address, then it's not possible to
129         // make boxing/unboxing/widening for types. Only conversion allowed is reference widening, which won't generate
130         // bytecode for the conversion, same as for arrays.
131 
132         const SavedTypeRelationFlagsContext savedFlagsCtx(
133             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
134 
135         if (!relation->IsIdenticalTo(GetTypeAtIndex(idx), tupleSource->GetTypeAtIndex(idx))) {
136             relation->Result(false);
137             return;
138         }
139     }
140 
141     if (!HasSpreadType() && tupleSource->HasSpreadType()) {
142         relation->Result(false);
143         return;
144     }
145 
146     relation->Result(true);
147 }
148 
Substitute(TypeRelation * relation,const Substitution * substitution)149 Type *ETSTupleType::Substitute(TypeRelation *relation, const Substitution *substitution)
150 {
151     auto *const checker = relation->GetChecker()->AsETSChecker();
152     ArenaVector<Type *> newTypeList(checker->Allocator()->Adapter());
153 
154     for (auto *const tupleTypeListElement : GetTupleTypesList()) {
155         newTypeList.emplace_back(tupleTypeListElement->Substitute(relation, substitution));
156     }
157 
158     auto *newSpreadType = spreadType_ == nullptr ? nullptr : spreadType_->Substitute(relation, substitution);
159     auto *newElementType = ir::ETSTuple::CalculateLUBForTuple(checker, newTypeList, &newSpreadType);
160     return checker->Allocator()->New<ETSTupleType>(std::move(newTypeList), newElementType, newSpreadType);
161 }
162 
Cast(TypeRelation * const relation,Type * const target)163 void ETSTupleType::Cast(TypeRelation *const relation, Type *const target)
164 {
165     // NOTE(mmartin): Might be not the correct casting rules, as these aren't defined yet
166 
167     if (!(target->IsETSTupleType() || target->IsETSArrayType())) {
168         conversion::Forbidden(relation);
169         return;
170     }
171 
172     if (target->IsETSArrayType() && (!target->IsETSTupleType())) {
173         auto *const arrayTarget = target->AsETSArrayType();
174 
175         if (!arrayTarget->ElementType()->IsETSObjectType()) {
176             conversion::Forbidden(relation);
177             return;
178         }
179 
180         const SavedTypeRelationFlagsContext savedFlagsCtx(
181             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
182 
183         const bool elementsAssignable =
184             std::all_of(GetTupleTypesList().begin(), GetTupleTypesList().end(),
185                         [&relation, &arrayTarget](auto *const tupleTypeAtIdx) {
186                             return relation->IsAssignableTo(tupleTypeAtIdx, arrayTarget->ElementType());
187                         });
188 
189         bool spreadAssignable = true;
190         if (HasSpreadType()) {
191             spreadAssignable = relation->IsAssignableTo(GetSpreadType(), arrayTarget->ElementType());
192         }
193 
194         relation->Result(elementsAssignable && spreadAssignable);
195         return;
196     }
197 
198     const auto *const tupleTarget = target->AsETSTupleType();
199 
200     if (tupleTarget->GetTupleSize() != GetTupleSize()) {
201         return;
202     }
203 
204     for (int32_t idx = 0; idx < GetTupleSize(); ++idx) {
205         const SavedTypeRelationFlagsContext savedFlagsCtx(
206             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
207 
208         if (!relation->IsAssignableTo(tupleTarget->GetTypeAtIndex(idx), GetTypeAtIndex(idx))) {
209             return;
210         }
211     }
212 
213     relation->Result(true);
214 }
215 
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)216 Type *ETSTupleType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation,
217                                 [[maybe_unused]] GlobalTypesHolder *globalTypes)
218 {
219     auto *tupleType = allocator->New<ETSTupleType>(
220         GetTupleTypesList(), ElementType()->Instantiate(allocator, relation, globalTypes), GetSpreadType());
221     tupleType->typeFlags_ = typeFlags_;
222     return tupleType;
223 }
224 
225 }  // namespace ark::es2panda::checker
226