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