1 /*
2 * Copyright (c) 2021-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 "etsTypeAliasType.h"
17
18 #include "varbinder/variable.h"
19 #include "checker/ETSchecker.h"
20 #include "checker/ets/conversion.h"
21 #include "checker/types/typeRelation.h"
22 #include "checker/types/globalTypesHolder.h"
23
24 namespace ark::es2panda::checker {
25
ETSTypeAliasType(ETSChecker * checker,util::StringView name,const ir::AstNode * declNode,bool isRecursive)26 ETSTypeAliasType::ETSTypeAliasType(ETSChecker *checker, util::StringView name, const ir::AstNode *declNode,
27 bool isRecursive)
28 : Type(TypeFlag::ETS_TYPE_ALIAS),
29 name_(name),
30 declNode_(declNode),
31 isRecursive_(isRecursive),
32 instantiationMap_(checker->Allocator()->Adapter()),
33 typeArguments_(checker->Allocator()->Adapter())
34 {
35 }
36
ToString(std::stringstream & ss,bool precise) const37 void ETSTypeAliasType::ToString(std::stringstream &ss, bool precise) const
38 {
39 if (!isRecursive_) {
40 targetType_->ToString(ss, precise);
41 return;
42 }
43
44 if (precise) {
45 ToAssemblerType(ss);
46 } else {
47 ss << name_;
48 }
49
50 if (!typeArguments_.empty()) {
51 ss << compiler::Signatures::GENERIC_BEGIN;
52 for (auto arg = typeArguments_.cbegin(); arg != typeArguments_.cend(); ++arg) {
53 (*arg)->ToString(ss, precise);
54
55 if (next(arg) != typeArguments_.cend()) {
56 ss << lexer::TokenToString(lexer::TokenType::PUNCTUATOR_COMMA);
57 }
58 }
59 ss << compiler::Signatures::GENERIC_END;
60 }
61 }
62
ToAssemblerType(std::stringstream & ss) const63 void ETSTypeAliasType::ToAssemblerType(std::stringstream &ss) const
64 {
65 if (targetType_ == nullptr || recursionCount_) {
66 ss << "std.core.Object";
67 return;
68 }
69
70 recursionCount_ = true;
71 targetType_->ToAssemblerType(ss);
72 recursionCount_ = false;
73 }
74
ToAssemblerTypeWithRank(std::stringstream & ss) const75 void ETSTypeAliasType::ToAssemblerTypeWithRank(std::stringstream &ss) const
76 {
77 if (targetType_ == nullptr || recursionCount_) {
78 ss << "std.core.Object";
79 return;
80 }
81
82 recursionCount_ = true;
83 targetType_->ToAssemblerTypeWithRank(ss);
84 recursionCount_ = false;
85 }
86
ToDebugInfoType(std::stringstream & ss) const87 void ETSTypeAliasType::ToDebugInfoType(std::stringstream &ss) const
88 {
89 if (isRecursive_) {
90 ss << name_;
91 return;
92 }
93
94 targetType_->ToDebugInfoType(ss);
95 }
96
IsArgumentsIdentical(TypeRelation * relation,Type * other)97 bool ETSTypeAliasType::IsArgumentsIdentical(TypeRelation *relation, Type *other)
98 {
99 auto const otherTypeArguments = other->AsETSTypeAliasType()->typeArguments_;
100
101 auto const argsNumber = typeArguments_.size();
102 if (argsNumber != otherTypeArguments.size()) {
103 return false;
104 }
105
106 for (size_t idx = 0U; idx < argsNumber; ++idx) {
107 if (typeArguments_[idx]->IsWildcardType() || otherTypeArguments[idx]->IsWildcardType()) {
108 continue;
109 }
110 if (!relation->IsIdenticalTo(typeArguments_[idx], otherTypeArguments[idx])) {
111 return false;
112 }
113 }
114
115 return true;
116 }
117
Identical(TypeRelation * relation,Type * other)118 void ETSTypeAliasType::Identical(TypeRelation *relation, Type *other)
119 {
120 if (other->IsETSTypeAliasType() && other->AsETSTypeAliasType()->IsRecursive() && isRecursive_) {
121 if (other->AsETSTypeAliasType()->GetDeclNode() == this->declNode_) {
122 relation->Result(IsArgumentsIdentical(relation, other));
123 return;
124 }
125 }
126
127 if (targetType_ != nullptr) {
128 relation->IsIdenticalTo(other, targetType_);
129 }
130 }
131
AssignmentTarget(TypeRelation * relation,Type * source)132 void ETSTypeAliasType::AssignmentTarget(TypeRelation *relation, Type *source)
133 {
134 if (source->IsETSTypeAliasType()) {
135 relation->IsIdenticalTo(this, source);
136 }
137
138 if (!relation->IsTrue() && relation->IsAtTypeDepthLimit(GetBaseType()) && targetType_ != nullptr) {
139 relation->IncreaseTypeRecursionCount(GetBaseType());
140 relation->IsAssignableTo(source, targetType_);
141 relation->DecreaseTypeRecursionCount(GetBaseType());
142 }
143 }
144
AssignmentSource(TypeRelation * relation,Type * target)145 bool ETSTypeAliasType::AssignmentSource(TypeRelation *relation, Type *target)
146 {
147 if (target->IsETSTypeAliasType()) {
148 relation->IsIdenticalTo(target, this);
149 }
150
151 if (!relation->IsTrue() && relation->IsAtTypeDepthLimit(GetBaseType()) && targetType_ != nullptr) {
152 relation->IncreaseTypeRecursionCount(GetBaseType());
153 relation->IsAssignableTo(targetType_, target);
154 relation->DecreaseTypeRecursionCount(GetBaseType());
155 }
156
157 return relation->IsTrue();
158 }
159
Cast(TypeRelation * const relation,Type * const target)160 void ETSTypeAliasType::Cast(TypeRelation *const relation, Type *const target)
161 {
162 if (target->IsETSTypeAliasType()) {
163 relation->IsIdenticalTo(this, target);
164 }
165
166 if (!relation->IsTrue() && relation->IsAtTypeDepthLimit(GetBaseType())) {
167 relation->IncreaseTypeRecursionCount(GetBaseType());
168 targetType_->Cast(relation, target);
169 relation->DecreaseTypeRecursionCount(GetBaseType());
170 }
171 }
172
CastTarget(TypeRelation * relation,Type * source)173 void ETSTypeAliasType::CastTarget(TypeRelation *relation, Type *source)
174 {
175 if (source->IsETSTypeAliasType()) {
176 relation->IsIdenticalTo(this, source);
177 }
178
179 if (!relation->IsTrue() && relation->IsAtTypeDepthLimit(GetBaseType())) {
180 relation->IncreaseTypeRecursionCount(GetBaseType());
181 targetType_->CastTarget(relation, source);
182 relation->DecreaseTypeRecursionCount(GetBaseType());
183 }
184 }
185
IsSupertypeOf(TypeRelation * relation,Type * source)186 void ETSTypeAliasType::IsSupertypeOf(TypeRelation *relation, Type *source)
187 {
188 if (source->IsETSTypeAliasType()) {
189 relation->IsIdenticalTo(this, source);
190 }
191
192 if (!relation->IsTrue() && relation->IsAtTypeDepthLimit(GetBaseType()) && targetType_ != nullptr) {
193 relation->IncreaseTypeRecursionCount(GetBaseType());
194 relation->IsSupertypeOf(targetType_, source);
195 relation->DecreaseTypeRecursionCount(GetBaseType());
196 }
197 }
198
IsSubtypeOf(TypeRelation * relation,Type * target)199 void ETSTypeAliasType::IsSubtypeOf(TypeRelation *relation, Type *target)
200 {
201 if (target->IsETSTypeAliasType()) {
202 relation->IsIdenticalTo(this, target);
203 }
204
205 if (!relation->IsTrue() && relation->IsAtTypeDepthLimit(GetBaseType()) && targetType_ != nullptr) {
206 relation->IncreaseTypeRecursionCount(GetBaseType());
207 relation->IsSupertypeOf(target, targetType_);
208 relation->DecreaseTypeRecursionCount(GetBaseType());
209 }
210 }
211
Rank() const212 uint32_t ETSTypeAliasType::Rank() const
213 {
214 if (isRecursive_) {
215 return 0;
216 }
217
218 return targetType_->Rank();
219 }
220
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)221 Type *ETSTypeAliasType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
222 {
223 return targetType_->Instantiate(allocator, relation, globalTypes);
224 }
225
GetInstantiatedType(util::StringView hash)226 ETSTypeAliasType *ETSTypeAliasType::GetInstantiatedType(util::StringView hash)
227 {
228 auto &instantiationMap = base_ == nullptr ? instantiationMap_ : base_->instantiationMap_;
229
230 auto found = instantiationMap.find(hash);
231 if (found != instantiationMap.end()) {
232 return found->second;
233 }
234
235 return nullptr;
236 }
237
EmplaceInstantiatedType(util::StringView hash,ETSTypeAliasType * emplaceType)238 void ETSTypeAliasType::EmplaceInstantiatedType(util::StringView hash, ETSTypeAliasType *emplaceType)
239 {
240 auto &instantiationMap = base_ == nullptr ? instantiationMap_ : base_->instantiationMap_;
241
242 instantiationMap.try_emplace(hash, emplaceType);
243 }
244
SubstituteTypeArgs(TypeRelation * const relation,ArenaVector<Type * > & newTypeArgs,const Substitution * const substitution)245 bool ETSTypeAliasType::SubstituteTypeArgs(TypeRelation *const relation, ArenaVector<Type *> &newTypeArgs,
246 const Substitution *const substitution)
247 {
248 bool anyChange = false;
249 newTypeArgs.reserve(typeArguments_.size());
250
251 for (auto *const arg : typeArguments_) {
252 auto *const newArg = arg->Substitute(relation, substitution);
253 newTypeArgs.push_back(newArg);
254 anyChange = anyChange || (newArg != arg);
255 }
256
257 return anyChange;
258 }
259
ApplySubstitution(TypeRelation * relation)260 void ETSTypeAliasType::ApplySubstitution(TypeRelation *relation)
261 {
262 ASSERT(base_ == nullptr);
263
264 const util::StringView hash = relation->GetChecker()->AsETSChecker()->GetHashFromTypeArguments(typeArguments_);
265 EmplaceInstantiatedType(hash, this);
266
267 auto getTypes = [this]() {
268 std::vector<ETSTypeAliasType *> types;
269
270 for (auto [name, type] : instantiationMap_) {
271 if (type->targetType_ == nullptr) {
272 types.push_back(type);
273 }
274 }
275
276 return types;
277 };
278
279 std::vector<ETSTypeAliasType *> types;
280
281 while (!(types = getTypes(), types.empty())) {
282 for (auto type : types) {
283 type->SetTargetType(type->parent_->targetType_->Substitute(relation, type->substitution_));
284 }
285 }
286 }
287
SetTypeArguments(ArenaVector<Type * > typeArguments)288 void ETSTypeAliasType::SetTypeArguments(ArenaVector<Type *> typeArguments)
289 {
290 typeArguments_ = std::move(typeArguments);
291 }
292
Substitute(TypeRelation * relation,const Substitution * substitution)293 Type *ETSTypeAliasType::Substitute(TypeRelation *relation, const Substitution *substitution)
294 {
295 if (substitution == nullptr || substitution->empty()) {
296 return this;
297 }
298
299 auto *const checker = relation->GetChecker()->AsETSChecker();
300
301 ArenaVector<Type *> newTypeArgs {checker->Allocator()->Adapter()};
302
303 if (!SubstituteTypeArgs(relation, newTypeArgs, substitution)) {
304 return this;
305 }
306
307 const util::StringView hash = checker->GetHashFromTypeArguments(newTypeArgs);
308
309 ETSTypeAliasType *copiedType = GetInstantiatedType(hash);
310 if (copiedType != nullptr) {
311 return copiedType;
312 }
313
314 copiedType = checker->CreateETSTypeAliasType(name_, declNode_, isRecursive_);
315 copiedType->base_ = base_ == nullptr ? this : base_;
316 copiedType->parent_ = this;
317 copiedType->substitution_ = substitution;
318 copiedType->typeArguments_ = newTypeArgs;
319
320 EmplaceInstantiatedType(hash, copiedType);
321
322 if (targetType_ != nullptr) {
323 copiedType->SetTargetType(targetType_->Substitute(relation, substitution));
324 }
325
326 return copiedType;
327 }
328
329 } // namespace ark::es2panda::checker
330