• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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