1 /**
2 * Copyright (c) 2023-2025 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 ss << "]";
40 }
41
ToAssemblerType(std::stringstream & ss) const42 void ETSTupleType::ToAssemblerType(std::stringstream &ss) const
43 {
44 wrapperType_->ToAssemblerType(ss);
45 }
46
ToDebugInfoType(std::stringstream & ss) const47 void ETSTupleType::ToDebugInfoType(std::stringstream &ss) const
48 {
49 if (HasTypeFlag(TypeFlag::READONLY)) {
50 ss << "readonly ";
51 }
52
53 ss << "[";
54
55 for (auto it = typeList_.begin(); it != typeList_.end(); it++) {
56 (*it)->ToDebugInfoType(ss);
57
58 if (std::next(it) != typeList_.end()) {
59 ss << ", ";
60 }
61 }
62
63 ss << "]";
64 }
65
GetTypeAtIndex(const TupleSizeType index) const66 Type *ETSTupleType::GetTypeAtIndex(const TupleSizeType index) const
67 {
68 ES2PANDA_ASSERT(index < GetTupleSize());
69 return GetTupleTypesList().at(index);
70 }
71
CheckElementsIdentical(TypeRelation * relation,const ETSTupleType * other) const72 bool ETSTupleType::CheckElementsIdentical(TypeRelation *relation, const ETSTupleType *other) const
73 {
74 if (GetTupleSize() != other->GetTupleSize()) {
75 return false;
76 }
77
78 for (TupleSizeType idx = 0; idx < GetTupleSize(); ++idx) {
79 if (!relation->IsIdenticalTo(GetTypeAtIndex(idx), other->GetTypeAtIndex(idx))) {
80 return false;
81 }
82 }
83 return true;
84 }
85
Identical(TypeRelation * const relation,Type * const other)86 void ETSTupleType::Identical([[maybe_unused]] TypeRelation *const relation, Type *const other)
87 {
88 if (!other->IsETSTupleType()) {
89 return;
90 }
91
92 const auto *const otherTuple = other->AsETSTupleType();
93
94 if (HasTypeFlag(TypeFlag::READONLY) != other->HasTypeFlag(TypeFlag::READONLY)) {
95 relation->Result(false);
96 return;
97 }
98
99 if (!CheckElementsIdentical(relation, otherTuple)) {
100 relation->Result(false);
101 return;
102 }
103
104 relation->Result(true);
105 }
106
AssignmentSource(TypeRelation * const relation,Type * const target)107 bool ETSTupleType::AssignmentSource(TypeRelation *const relation, Type *const target)
108 {
109 if (!target->IsETSTupleType()) {
110 return false;
111 }
112
113 return relation->IsTrue();
114 }
115
AssignmentTarget(TypeRelation * const relation,Type * const source)116 void ETSTupleType::AssignmentTarget(TypeRelation *const relation, Type *const source)
117 {
118 if (!source->HasTypeFlag(TypeFlag::READONLY) && source->IsETSTupleType()) {
119 source->AsETSTupleType()->IsSubtypeOf(relation, this);
120 }
121 }
122
Substitute(TypeRelation * relation,const Substitution * substitution)123 Type *ETSTupleType::Substitute(TypeRelation *relation, const Substitution *substitution)
124 {
125 auto *const checker = relation->GetChecker()->AsETSChecker();
126 ArenaVector<Type *> newTypeList(checker->ProgramAllocator()->Adapter());
127
128 for (auto *const tupleTypeListElement : GetTupleTypesList()) {
129 newTypeList.emplace_back(tupleTypeListElement->Substitute(relation, substitution));
130 }
131
132 return checker->ProgramAllocator()->New<ETSTupleType>(checker, std::move(newTypeList));
133 }
134
IsSubtypeOf(TypeRelation * const relation,Type * target)135 void ETSTupleType::IsSubtypeOf(TypeRelation *const relation, Type *target)
136 {
137 if (target->IsETSObjectType() && target->AsETSObjectType()->IsGlobalETSObjectType()) {
138 relation->Result(true);
139 return;
140 }
141 if (target->IsETSTupleType()) {
142 if (!HasTypeFlag(TypeFlag::READONLY) && CheckElementsIdentical(relation, target->AsETSTupleType())) {
143 relation->Result(true);
144 }
145 }
146 }
147
Cast(TypeRelation * const relation,Type * const target)148 void ETSTupleType::Cast(TypeRelation *const relation, Type *const target)
149 {
150 if (!(target->IsETSTupleType() || target->IsETSArrayType())) {
151 conversion::Forbidden(relation);
152 return;
153 }
154
155 if (target->IsETSArrayType() && (!target->IsETSTupleType())) {
156 auto *const arrayTarget = target->AsETSArrayType();
157
158 if (!arrayTarget->ElementType()->IsETSObjectType()) {
159 conversion::Forbidden(relation);
160 return;
161 }
162
163 const SavedTypeRelationFlagsContext savedFlagsCtx(
164 relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
165
166 const bool elementsAssignable =
167 std::all_of(GetTupleTypesList().begin(), GetTupleTypesList().end(),
168 [&relation, &arrayTarget](auto *const tupleTypeAtIdx) {
169 return relation->IsAssignableTo(tupleTypeAtIdx, arrayTarget->ElementType());
170 });
171
172 relation->Result(elementsAssignable);
173 return;
174 }
175
176 const auto *const tupleTarget = target->AsETSTupleType();
177
178 if (tupleTarget->GetTupleSize() != GetTupleSize()) {
179 return;
180 }
181
182 for (TupleSizeType idx = 0; idx < GetTupleSize(); ++idx) {
183 const SavedTypeRelationFlagsContext savedFlagsCtx(
184 relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
185
186 if (!relation->IsAssignableTo(tupleTarget->GetTypeAtIndex(idx), GetTypeAtIndex(idx))) {
187 return;
188 }
189 }
190
191 relation->Result(true);
192 }
193
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)194 Type *ETSTupleType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation,
195 [[maybe_unused]] GlobalTypesHolder *globalTypes)
196 {
197 auto *const checker = relation->GetChecker()->AsETSChecker();
198 auto *const tupleType = allocator->New<ETSTupleType>(checker, GetTupleTypesList());
199 ES2PANDA_ASSERT(tupleType != nullptr);
200 tupleType->typeFlags_ = typeFlags_;
201 return tupleType;
202 }
203
CheckVarianceRecursively(TypeRelation * relation,VarianceFlag varianceFlag)204 void ETSTupleType::CheckVarianceRecursively(TypeRelation *relation, VarianceFlag varianceFlag)
205 {
206 for (auto const &ctype : typeList_) {
207 relation->CheckVarianceRecursively(ctype, relation->TransferVariant(varianceFlag, VarianceFlag::INVARIANT));
208 }
209 }
210
211 } // namespace ark::es2panda::checker
212