• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "etsObjectType.h"
17 
18 #include "checker/ETSchecker.h"
19 #include "checker/ets/conversion.h"
20 #include "checker/types/ts/objectType.h"
21 #include "checker/types/typeFlag.h"
22 #include "checker/types/typeRelation.h"
23 #include "checker/types/globalTypesHolder.h"
24 #include "ir/base/scriptFunction.h"
25 #include "ir/expressions/identifier.h"
26 
27 namespace ark::es2panda::checker {
28 
Iterate(const PropertyTraverser & cb) const29 void ETSObjectType::Iterate(const PropertyTraverser &cb) const
30 {
31     for (const auto *prop : GetAllProperties()) {
32         cb(prop);
33     }
34 
35     if (superType_ != nullptr) {
36         superType_->Iterate(cb);
37     }
38 
39     for (const auto *interface : interfaces_) {
40         interface->Iterate(cb);
41     }
42 }
43 
SearchFieldsDecls(const util::StringView & name,PropertySearchFlags flags) const44 varbinder::LocalVariable *ETSObjectType::SearchFieldsDecls(const util::StringView &name,
45                                                            PropertySearchFlags flags) const
46 {
47     varbinder::LocalVariable *res {};
48     if ((flags & PropertySearchFlags::SEARCH_INSTANCE_FIELD) != 0) {
49         res = GetOwnProperty<PropertyType::INSTANCE_FIELD>(name);
50     }
51 
52     if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_FIELD) != 0)) {
53         res = GetOwnProperty<PropertyType::STATIC_FIELD>(name);
54     }
55 
56     if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_INSTANCE_DECL) != 0)) {
57         res = GetOwnProperty<PropertyType::INSTANCE_DECL>(name);
58     }
59 
60     if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_DECL) != 0)) {
61         res = GetOwnProperty<PropertyType::STATIC_DECL>(name);
62     }
63     return res;
64 }
65 
GetProperty(const util::StringView & name,PropertySearchFlags flags) const66 varbinder::LocalVariable *ETSObjectType::GetProperty(const util::StringView &name, PropertySearchFlags flags) const
67 {
68     varbinder::LocalVariable *res = SearchFieldsDecls(name, flags);
69     if (res == nullptr && (flags & PropertySearchFlags::SEARCH_METHOD) != 0) {
70         if ((flags & PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION) != 0) {
71             if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) != 0) {
72                 res = GetOwnProperty<PropertyType::INSTANCE_METHOD>(name);
73             }
74 
75             if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_METHOD) != 0)) {
76                 res = GetOwnProperty<PropertyType::STATIC_METHOD>(name);
77             }
78         } else {
79             res = CreateSyntheticVarFromEverySignature(name, flags);
80         }
81     }
82 
83     if (res == nullptr && (flags & PropertySearchFlags::SEARCH_IN_INTERFACES) != 0) {
84         for (auto *interface : interfaces_) {
85             res = interface->GetProperty(name, flags);
86             if (res != nullptr) {
87                 return res;
88             }
89         }
90     }
91 
92     if (res == nullptr && superType_ != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) {
93         res = superType_->GetProperty(name, flags);
94     }
95 
96     return res;
97 }
98 
IsPropertyInherited(const varbinder::Variable * var)99 bool ETSObjectType::IsPropertyInherited(const varbinder::Variable *var)
100 {
101     if (var->HasFlag(varbinder::VariableFlags::PRIVATE)) {
102         return GetProperty(var->Name(), PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL) == var;
103     }
104 
105     if (var->HasFlag(varbinder::VariableFlags::PROTECTED)) {
106         return (GetProperty(var->Name(), PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL) ==
107                 var) ||
108                this->IsPropertyOfAscendant(var);
109     }
110 
111     return true;
112 }
113 
IsPropertyOfAscendant(const varbinder::Variable * var) const114 bool ETSObjectType::IsPropertyOfAscendant(const varbinder::Variable *var) const
115 {
116     if (this->SuperType() == nullptr) {
117         return false;
118     }
119 
120     if (this->SuperType()->GetProperty(var->Name(),
121                                        PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL) == var) {
122         return true;
123     }
124 
125     return this->SuperType()->IsPropertyOfAscendant(var);
126 }
127 
IsSignatureInherited(Signature * signature)128 bool ETSObjectType::IsSignatureInherited(Signature *signature)
129 {
130     if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) {
131         return signature->Owner() == this;
132     }
133 
134     if (signature->HasSignatureFlag(SignatureFlags::PROTECTED)) {
135         return signature->Owner() == this || this->IsDescendantOf(signature->Owner());
136     }
137 
138     return true;
139 }
140 
IsDescendantOf(const ETSObjectType * ascendant) const141 bool ETSObjectType::IsDescendantOf(const ETSObjectType *ascendant) const
142 {
143     if (this->SuperType() == nullptr) {
144         return false;
145     }
146 
147     if (this->SuperType() == ascendant) {
148         return true;
149     }
150 
151     return this->SuperType()->IsDescendantOf(ascendant);
152 }
153 
CreateSyntheticVarFromEverySignature(const util::StringView & name,PropertySearchFlags flags) const154 varbinder::LocalVariable *ETSObjectType::CreateSyntheticVarFromEverySignature(const util::StringView &name,
155                                                                               PropertySearchFlags flags) const
156 {
157     varbinder::LocalVariable *res = allocator_->New<varbinder::LocalVariable>(varbinder::VariableFlags::SYNTHETIC |
158                                                                               varbinder::VariableFlags::METHOD);
159     ETSFunctionType *funcType = CreateETSFunctionType(name);
160 
161     varbinder::LocalVariable *functionalInterface = CollectSignaturesForSyntheticType(funcType, name, flags);
162 
163     if (functionalInterface != nullptr) {
164         return functionalInterface;
165     }
166 
167     if (funcType->CallSignatures().empty()) {
168         return nullptr;
169     }
170 
171     res->SetTsType(funcType);
172     funcType->SetVariable(res);
173     return res;
174 }
175 
CreateETSFunctionType(const util::StringView & name) const176 ETSFunctionType *ETSObjectType::CreateETSFunctionType(const util::StringView &name) const
177 {
178     return allocator_->New<ETSFunctionType>(name, allocator_);
179 }
180 
CollectSignaturesForSyntheticType(ETSFunctionType * funcType,const util::StringView & name,PropertySearchFlags flags) const181 varbinder::LocalVariable *ETSObjectType::CollectSignaturesForSyntheticType(ETSFunctionType *funcType,
182                                                                            const util::StringView &name,
183                                                                            PropertySearchFlags flags) const
184 {
185     auto const addSignature = [funcType, flags](varbinder::LocalVariable *found) -> void {
186         for (auto *it : found->TsType()->AsETSFunctionType()->CallSignatures()) {
187             if (((flags & PropertySearchFlags::IGNORE_ABSTRACT) != 0) &&
188                 it->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
189                 continue;
190             }
191             // Issue: #18720
192             // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
193             funcType->AddCallSignature(it);
194         }
195     };
196 
197     if ((flags & PropertySearchFlags::SEARCH_STATIC_METHOD) != 0) {
198         if (auto *found = GetOwnProperty<PropertyType::STATIC_METHOD>(name); found != nullptr) {
199             ASSERT(found->TsType()->IsETSFunctionType());
200             addSignature(found);
201         }
202     }
203 
204     if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) != 0) {
205         if (auto *found = GetOwnProperty<PropertyType::INSTANCE_METHOD>(name); found != nullptr) {
206             ASSERT(found->TsType()->IsETSFunctionType());
207             addSignature(found);
208         }
209     }
210 
211     if (superType_ != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) {
212         return superType_->CollectSignaturesForSyntheticType(funcType, name, flags);
213     }
214 
215     return nullptr;
216 }
217 
GetAllProperties() const218 std::vector<varbinder::LocalVariable *> ETSObjectType::GetAllProperties() const
219 {
220     std::vector<varbinder::LocalVariable *> allProperties;
221     for (const auto &[_, prop] : InstanceFields()) {
222         (void)_;
223         allProperties.push_back(prop);
224     }
225 
226     for (const auto &[_, prop] : StaticFields()) {
227         (void)_;
228         allProperties.push_back(prop);
229     }
230 
231     for (const auto &[_, prop] : InstanceMethods()) {
232         (void)_;
233         allProperties.push_back(prop);
234     }
235 
236     for (const auto &[_, prop] : StaticMethods()) {
237         (void)_;
238         allProperties.push_back(prop);
239     }
240 
241     for (const auto &[_, prop] : InstanceDecls()) {
242         (void)_;
243         allProperties.push_back(prop);
244     }
245 
246     for (const auto &[_, prop] : StaticDecls()) {
247         (void)_;
248         allProperties.push_back(prop);
249     }
250 
251     return allProperties;
252 }
253 
Methods() const254 std::vector<varbinder::LocalVariable *> ETSObjectType::Methods() const
255 {
256     std::vector<varbinder::LocalVariable *> methods;
257     for (const auto &[_, prop] : InstanceMethods()) {
258         (void)_;
259         methods.push_back(prop);
260     }
261 
262     for (const auto &[_, prop] : StaticMethods()) {
263         (void)_;
264         methods.push_back(prop);
265     }
266 
267     return methods;
268 }
269 
Fields() const270 std::vector<varbinder::LocalVariable *> ETSObjectType::Fields() const
271 {
272     std::vector<varbinder::LocalVariable *> fields;
273     for (const auto &[_, prop] : InstanceFields()) {
274         (void)_;
275         fields.push_back(prop);
276     }
277 
278     for (const auto &[_, prop] : StaticFields()) {
279         (void)_;
280         fields.push_back(prop);
281     }
282 
283     return fields;
284 }
285 
ForeignProperties() const286 std::vector<const varbinder::LocalVariable *> ETSObjectType::ForeignProperties() const
287 {
288     std::vector<const varbinder::LocalVariable *> foreignProps;
289     std::unordered_set<util::StringView> ownProps;
290 
291     EnsurePropertiesInstantiated();
292     ownProps.reserve(properties_.size());
293 
294     for (const auto *prop : GetAllProperties()) {
295         ownProps.insert(prop->Name());
296     }
297 
298     auto allProps = CollectAllProperties();
299     for (const auto &[name, var] : allProps) {
300         if (ownProps.find(name) == ownProps.end()) {
301             foreignProps.push_back(var);
302         }
303     }
304 
305     return foreignProps;
306 }
307 
CollectAllProperties() const308 ArenaMap<util::StringView, const varbinder::LocalVariable *> ETSObjectType::CollectAllProperties() const
309 {
310     ArenaMap<util::StringView, const varbinder::LocalVariable *> propMap(allocator_->Adapter());
311     EnsurePropertiesInstantiated();
312     Iterate([&propMap](const varbinder::LocalVariable *var) { propMap.emplace(var->Name(), var); });
313 
314     return propMap;
315 }
316 
ToString(std::stringstream & ss,bool precise) const317 void ETSObjectType::ToString(std::stringstream &ss, bool precise) const
318 {
319     if (HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
320         GetFunctionalInterfaceInvokeType()->ToString(ss, precise);
321         return;
322     }
323 
324     if (IsPartial()) {
325         ss << "Partial" << compiler::Signatures::GENERIC_BEGIN;
326         baseType_->ToString(ss, precise);
327         ss << compiler::Signatures::GENERIC_END;
328         return;
329     }
330 
331     const bool isReadonlyType = HasTypeFlag(TypeFlag::READONLY);
332     if (isReadonlyType) {
333         ss << "Readonly" << compiler::Signatures::GENERIC_BEGIN;
334     }
335     const bool isRequiredType = HasObjectFlag(ETSObjectFlags::REQUIRED);
336     if (isRequiredType) {
337         ss << "Required" << compiler::Signatures::GENERIC_BEGIN;
338     }
339 
340     if (precise) {
341         ss << assemblerName_;  // NOTE(gogabr): need full qualified name
342     } else {
343         ss << name_;
344     }
345 
346     if (!typeArguments_.empty()) {
347         ss << compiler::Signatures::GENERIC_BEGIN;
348         for (auto arg = typeArguments_.cbegin(); arg != typeArguments_.cend(); ++arg) {
349             (*arg)->ToString(ss, precise);
350 
351             if (next(arg) != typeArguments_.cend()) {
352                 ss << lexer::TokenToString(lexer::TokenType::PUNCTUATOR_COMMA);
353             }
354         }
355         ss << compiler::Signatures::GENERIC_END;
356     }
357 
358     if (isRequiredType) {
359         ss << compiler::Signatures::GENERIC_END;
360     }
361     if (isReadonlyType) {
362         ss << compiler::Signatures::GENERIC_END;
363     }
364 }
365 
SubstitutePartialTypes(TypeRelation * relation,Type * other)366 void ETSObjectType::SubstitutePartialTypes(TypeRelation *relation, Type *other)
367 {
368     ASSERT(IsPartial());
369 
370     if ((baseType_->IsGeneric() || baseType_->IsETSTypeParameter()) && effectiveSubstitution_ != nullptr) {
371         if (auto *newBaseType = baseType_->Substitute(relation, effectiveSubstitution_);
372             newBaseType->IsETSObjectType() && !relation->IsIdenticalTo(newBaseType, baseType_)) {
373             baseType_ = newBaseType->AsETSObjectType();
374         }
375     }
376 
377     if (other->IsETSObjectType() && other->AsETSObjectType()->IsPartial()) {
378         auto *otherPartial = other->AsETSObjectType();
379         if ((otherPartial->baseType_->IsGeneric() || otherPartial->baseType_->IsETSTypeParameter()) &&
380             otherPartial->effectiveSubstitution_ != nullptr) {
381             if (auto *newBaseType = otherPartial->baseType_->Substitute(relation, otherPartial->effectiveSubstitution_);
382                 newBaseType->IsETSObjectType() && !relation->IsIdenticalTo(newBaseType, otherPartial->baseType_)) {
383                 otherPartial->baseType_ = newBaseType->AsETSObjectType();
384             }
385         }
386     }
387 }
388 
IdenticalUptoTypeArguments(TypeRelation * relation,Type * other)389 void ETSObjectType::IdenticalUptoTypeArguments(TypeRelation *relation, Type *other)
390 {
391     relation->Result(false);
392 
393     if (IsPartial()) {
394         SubstitutePartialTypes(relation, other);
395     }
396 
397     if (!other->IsETSObjectType() || !CheckIdenticalFlags(other->AsETSObjectType())) {
398         return;
399     }
400 
401     // NOTE: (DZ) only both Partial types can be compatible.
402     if (static_cast<bool>(static_cast<std::byte>(IsPartial()) ^
403                           static_cast<std::byte>(other->AsETSObjectType()->IsPartial()))) {
404         return;
405     }
406 
407     auto *thisBase = GetOriginalBaseType();
408     auto *otherBase = other->AsETSObjectType()->GetOriginalBaseType();
409     if (thisBase->Variable() != otherBase->Variable()) {
410         return;
411     }
412 
413     if ((relation->IgnoreTypeParameters() && !HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) || (this == other)) {
414         relation->Result(true);
415         return;
416     }
417 
418     auto const sourceTypeArguments = other->AsETSObjectType()->TypeArguments();
419     if (typeArguments_.empty() != sourceTypeArguments.empty()) {
420         return;
421     }
422 
423     relation->Result(true);
424 }
425 
Identical(TypeRelation * relation,Type * other)426 void ETSObjectType::Identical(TypeRelation *relation, Type *other)
427 {
428     IdenticalUptoTypeArguments(relation, other);
429 
430     if (!relation->IsTrue() || !HasTypeFlag(TypeFlag::GENERIC) || !other->IsETSObjectType()) {
431         return;
432     }
433 
434     auto const otherTypeArguments = other->AsETSObjectType()->TypeArguments();
435 
436     auto const argsNumber = typeArguments_.size();
437     if (argsNumber != otherTypeArguments.size()) {
438         relation->Result(false);
439         return;
440     }
441 
442     for (size_t idx = 0U; idx < argsNumber; ++idx) {
443         if (typeArguments_[idx]->IsWildcardType() || otherTypeArguments[idx]->IsWildcardType()) {
444             continue;
445         }
446         if (!relation->IsIdenticalTo(typeArguments_[idx], otherTypeArguments[idx])) {
447             return;
448         }
449     }
450 
451     relation->Result(true);
452 }
453 
CheckIdenticalFlags(ETSObjectType * other) const454 bool ETSObjectType::CheckIdenticalFlags(ETSObjectType *other) const
455 {
456     constexpr auto FLAGS_TO_REMOVE = ETSObjectFlags::INCOMPLETE_INSTANTIATION |
457                                      ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS |
458                                      ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY;
459 
460     auto cleanedTargetFlags = other->ObjectFlags();
461     cleanedTargetFlags &= ~FLAGS_TO_REMOVE;
462 
463     auto cleanedSelfFlags = ObjectFlags();
464     cleanedSelfFlags &= ~FLAGS_TO_REMOVE;
465 
466     return cleanedSelfFlags == cleanedTargetFlags;
467 }
468 
AssignmentSource(TypeRelation * const relation,Type * const target)469 bool ETSObjectType::AssignmentSource(TypeRelation *const relation, [[maybe_unused]] Type *const target)
470 {
471     return relation->Result(false);
472 }
473 
AssignmentTarget(TypeRelation * const relation,Type * source)474 void ETSObjectType::AssignmentTarget(TypeRelation *const relation, Type *source)
475 {
476     if (source->HasTypeFlag(TypeFlag::READONLY)) {
477         relation->Result(false);
478         return;
479     }
480 
481     if (HasObjectFlag(ETSObjectFlags::FUNCTIONAL) && source->IsETSFunctionType()) {
482         EnsurePropertiesInstantiated();
483         auto found = properties_[static_cast<size_t>(PropertyType::INSTANCE_METHOD)].find(
484             FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME);
485         ASSERT(found != properties_[static_cast<size_t>(PropertyType::INSTANCE_METHOD)].end());
486         source = source->AsETSFunctionType()->BoxPrimitives(relation->GetChecker()->AsETSChecker());
487         relation->IsAssignableTo(source, found->second->TsType());
488         return;
489     }
490 
491     relation->IsSupertypeOf(this, source);
492 }
493 
CastWideningNarrowing(TypeRelation * const relation,Type * const target,TypeFlag unboxFlags,TypeFlag wideningFlags,TypeFlag narrowingFlags)494 bool ETSObjectType::CastWideningNarrowing(TypeRelation *const relation, Type *const target, TypeFlag unboxFlags,
495                                           TypeFlag wideningFlags, TypeFlag narrowingFlags)
496 {
497     if (target->HasTypeFlag(unboxFlags)) {
498         conversion::Unboxing(relation, this);
499         return true;
500     }
501     if (target->HasTypeFlag(wideningFlags)) {
502         conversion::UnboxingWideningPrimitive(relation, this, target);
503         return true;
504     }
505     if (target->HasTypeFlag(narrowingFlags)) {
506         conversion::UnboxingNarrowingPrimitive(relation, this, target);
507         return true;
508     }
509     return false;
510 }
511 
TryCastByte(TypeRelation * const relation,Type * const target)512 bool ETSObjectType::TryCastByte(TypeRelation *const relation, Type *const target)
513 {
514     if (target->HasTypeFlag(TypeFlag::BYTE)) {
515         conversion::Unboxing(relation, this);
516         return true;
517     }
518     if (target->HasTypeFlag(TypeFlag::SHORT | TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE)) {
519         conversion::UnboxingWideningPrimitive(relation, this, target);
520         return true;
521     }
522     if (target->HasTypeFlag(TypeFlag::CHAR)) {
523         conversion::UnboxingWideningNarrowingPrimitive(relation, this, target);
524         return true;
525     }
526     return false;
527 }
528 
TryCastIntegral(TypeRelation * const relation,Type * const target)529 bool ETSObjectType::TryCastIntegral(TypeRelation *const relation, Type *const target)
530 {
531     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_BYTE) && TryCastByte(relation, target)) {
532         return true;
533     }
534     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_SHORT) &&
535         CastWideningNarrowing(relation, target, TypeFlag::SHORT,
536                               TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE,
537                               TypeFlag::BYTE | TypeFlag::CHAR)) {
538         return true;
539     }
540     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_CHAR) &&
541         CastWideningNarrowing(relation, target, TypeFlag::CHAR,
542                               TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE,
543                               TypeFlag::BYTE | TypeFlag::SHORT)) {
544         return true;
545     }
546     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_INT) &&
547         CastWideningNarrowing(relation, target, TypeFlag::INT, TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE,
548                               TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR)) {
549         return true;
550     }
551     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_LONG) &&
552         CastWideningNarrowing(relation, target, TypeFlag::LONG, TypeFlag::FLOAT | TypeFlag::DOUBLE,
553                               TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT)) {
554         return true;
555     }
556     return false;
557 }
558 
TryCastFloating(TypeRelation * const relation,Type * const target)559 bool ETSObjectType::TryCastFloating(TypeRelation *const relation, Type *const target)
560 {
561     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_FLOAT) &&
562         CastWideningNarrowing(relation, target, TypeFlag::FLOAT, TypeFlag::DOUBLE,
563                               TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT | TypeFlag::LONG)) {
564         return true;
565     }
566     if (auto narrowingFlags =
567             TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT;
568         this->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE) &&
569         CastWideningNarrowing(relation, target, TypeFlag::DOUBLE, TypeFlag::NONE, narrowingFlags)) {
570         return true;
571     }
572     return false;
573 }
574 
TryCastUnboxable(TypeRelation * const relation,Type * const target)575 bool ETSObjectType::TryCastUnboxable(TypeRelation *const relation, Type *const target)
576 {
577     if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
578         if (!target->IsETSUnboxableObject()) {
579             conversion::WideningReference(relation, this, target->AsETSObjectType());
580             return true;
581         }
582         auto unboxedTarget = relation->GetChecker()->AsETSChecker()->MaybeUnboxInRelation(target);
583         CastNumericObject(relation, unboxedTarget);
584         if (relation->IsTrue()) {
585             conversion::Boxing(relation, unboxedTarget);
586             return true;
587         }
588         conversion::WideningReference(relation, this, target->AsETSObjectType());
589         return true;
590     }
591     conversion::Forbidden(relation);
592     return true;
593 }
594 
CastNumericObject(TypeRelation * const relation,Type * const target)595 bool ETSObjectType::CastNumericObject(TypeRelation *const relation, Type *const target)
596 {
597     if (!target->IsETSPrimitiveType()) {
598         return false;
599     }
600     if (relation->IsIdenticalTo(this, target)) {
601         return true;
602     }
603     if (TryCastIntegral(relation, target)) {
604         return true;
605     }
606     if (TryCastFloating(relation, target)) {
607         return true;
608     }
609     if (this->HasObjectFlag(ETSObjectFlags::BOXED_ENUM) && target->HasTypeFlag(TypeFlag::ETS_ENUM)) {
610         conversion::Unboxing(relation, this);
611         return true;
612     }
613     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_BOOLEAN) && target->HasTypeFlag(TypeFlag::ETS_BOOLEAN)) {
614         conversion::Unboxing(relation, this);
615         return true;
616     }
617     if (this->IsETSUnboxableObject()) {
618         return TryCastUnboxable(relation, target);
619     }
620     if (target->IsETSPrimitiveType()) {
621         conversion::NarrowingReferenceUnboxing(relation, this, target);
622         return true;
623     }
624     return false;
625 }
626 
Cast(TypeRelation * const relation,Type * const target)627 void ETSObjectType::Cast(TypeRelation *const relation, Type *const target)
628 {
629     conversion::Identity(relation, this, target);
630     if (relation->IsTrue()) {
631         return;
632     }
633 
634     if (CastNumericObject(relation, target)) {
635         return;
636     }
637 
638     if (target->HasTypeFlag(TypeFlag::ETS_ARRAY)) {
639         conversion::NarrowingReference(relation, this, target->AsETSArrayType());
640         return;
641     }
642 
643     if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
644         conversion::WideningReference(relation, this, target->AsETSObjectType());
645         if (relation->IsTrue()) {
646             return;
647         }
648 
649         conversion::NarrowingReference(relation, this, target->AsETSObjectType());
650         if (relation->IsTrue()) {
651             return;
652         }
653     }
654 
655     //  #16485: Probably temporary solution for generic bridges realization. Allows casting of generic classes
656     //          in the form C<T> as C<U> (where U extends T) or C<T> as D (where D extends C<U>)
657     if ((relation->GetChecker()->Context().Status() & CheckerStatus::IN_BRIDGE_TEST) != 0U) {
658         SavedTypeRelationFlagsContext const savedFlags(relation, relation->GetTypeRelationFlags() |
659                                                                      TypeRelationFlag::IGNORE_TYPE_PARAMETERS);
660         relation->IsSupertypeOf(this, target);
661         return;
662     }
663 
664     conversion::Forbidden(relation);
665 }
666 
DefaultObjectTypeChecks(const ETSChecker * const etsChecker,TypeRelation * const relation,Type * const source)667 bool ETSObjectType::DefaultObjectTypeChecks(const ETSChecker *const etsChecker, TypeRelation *const relation,
668                                             Type *const source)
669 {
670     relation->Result(false);
671 
672     // 3.8.3 Subtyping among Array Types
673     auto const *const base = GetConstOriginalBaseType();
674     if (base == etsChecker->GlobalETSObjectType() && source->IsETSArrayType()) {
675         relation->Result(true);
676         return true;
677     }
678 
679     if (!source->IsETSObjectType() ||
680         !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE)) {
681         return true;
682     }
683 
684     // All classes and interfaces are subtypes of Object
685     if (base == etsChecker->GlobalETSObjectType()) {
686         relation->Result(true);
687         return true;
688     }
689 
690     IdenticalUptoTypeArguments(relation, source);
691     if (relation->IsTrue() && HasTypeFlag(TypeFlag::GENERIC) && !relation->IgnoreTypeParameters()) {
692         IsGenericSupertypeOf(relation, source);
693     }
694     return relation->IsTrue();
695 }
696 
IsSupertypeOf(TypeRelation * relation,Type * source)697 void ETSObjectType::IsSupertypeOf(TypeRelation *relation, Type *source)
698 {
699     relation->Result(false);
700     auto *const etsChecker = relation->GetChecker()->AsETSChecker();
701 
702     if (IsPartial()) {
703         if (!source->IsETSObjectType() || !source->AsETSObjectType()->IsPartial()) {
704             return;
705         }
706         relation->IsSupertypeOf(GetBaseType(), source->AsETSObjectType()->GetBaseType());
707         return;
708     }
709 
710     if (DefaultObjectTypeChecks(etsChecker, relation, source)) {
711         return;
712     }
713 
714     //  #16485: special case for generic bridges processing.
715     //          We need only to check if the type is immediate supertype of processing class.
716     auto const &checkerContext = relation->GetChecker()->Context();
717     if ((checkerContext.Status() & CheckerStatus::IN_BRIDGE_TEST) != 0U && relation->IsBridgeCheck()) {
718         if (source->Variable() == checkerContext.ContainingClass()->SuperType()->Variable()) {
719             return;
720         }
721     }
722 
723     ETSObjectType *sourceObj = source->AsETSObjectType();
724     if (auto *sourceSuper = sourceObj->SuperType(); sourceSuper != nullptr) {
725         if (relation->IsSupertypeOf(this, sourceSuper)) {
726             return;
727         }
728     }
729 
730     if (HasObjectFlag(ETSObjectFlags::INTERFACE)) {
731         for (auto *itf : sourceObj->Interfaces()) {
732             if (relation->IsSupertypeOf(this, itf)) {
733                 return;
734             }
735         }
736     }
737 }
738 
IsGenericSupertypeOf(TypeRelation * relation,Type * source)739 void ETSObjectType::IsGenericSupertypeOf(TypeRelation *relation, Type *source)
740 {
741     ASSERT(HasTypeFlag(TypeFlag::GENERIC));
742 
743     auto *sourceType = source->AsETSObjectType();
744     auto const &sourceTypeArguments = sourceType->TypeArguments();
745     auto const typeArgumentsNumber = typeArguments_.size();
746     if (typeArgumentsNumber > sourceTypeArguments.size()) {
747         relation->Result(false);
748         return;
749     }
750 
751     ASSERT(declNode_ == sourceType->GetDeclNode());
752 
753     auto *typeParamsDecl = GetTypeParams();
754     ASSERT(typeParamsDecl != nullptr || typeArguments_.empty());
755 
756     if (typeParamsDecl == nullptr) {
757         return;
758     }
759 
760     auto &typeParams = typeParamsDecl->Params();
761     ASSERT(typeParams.size() == typeArgumentsNumber);
762 
763     for (size_t idx = 0U; idx < typeArgumentsNumber; ++idx) {
764         auto *typeArg = typeArguments_[idx];
765         auto *sourceTypeArg = sourceTypeArguments[idx];
766         auto *typeParam = typeParams[idx];
767 
768         relation->Result(false);
769         if (typeArg->IsWildcardType() || sourceTypeArg->IsWildcardType()) {
770             continue;
771         }
772         if (typeParam->IsOut()) {
773             relation->IsSupertypeOf(typeArg, sourceTypeArg);
774         } else if (typeParam->IsIn()) {
775             relation->IsSupertypeOf(sourceTypeArg, typeArg);
776         } else {
777             relation->IsIdenticalTo(typeArg, sourceTypeArg);
778         }
779 
780         if (!relation->IsTrue()) {
781             return;
782         }
783     }
784 
785     relation->Result(true);
786 }
787 
AsSuper(Checker * checker,varbinder::Variable * sourceVar)788 Type *ETSObjectType::AsSuper(Checker *checker, varbinder::Variable *sourceVar)
789 {
790     if (sourceVar == nullptr) {
791         return nullptr;
792     }
793 
794     if (variable_ == sourceVar) {
795         return this;
796     }
797 
798     if (HasObjectFlag(ETSObjectFlags::INTERFACE)) {
799         Type *res = nullptr;
800         for (auto *const it : checker->AsETSChecker()->GetInterfaces(this)) {
801             res = it->AsSuper(checker, sourceVar);
802             if (res != nullptr) {
803                 return res;
804             }
805         }
806         return checker->GetGlobalTypesHolder()->GlobalETSObjectType()->AsSuper(checker, sourceVar);
807     }
808 
809     Type *const superType = checker->AsETSChecker()->GetSuperType(this);
810 
811     if (superType == nullptr) {
812         return nullptr;
813     }
814 
815     if (!superType->IsETSObjectType()) {
816         return nullptr;
817     }
818 
819     if (ETSObjectType *const superObj = superType->AsETSObjectType(); superObj->HasObjectFlag(ETSObjectFlags::CLASS)) {
820         Type *const res = superObj->AsSuper(checker, sourceVar);
821         if (res != nullptr) {
822             return res;
823         }
824     }
825 
826     if (sourceVar->TsType()->IsETSObjectType() &&
827         sourceVar->TsType()->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
828         for (auto *const it : checker->AsETSChecker()->GetInterfaces(this)) {
829             Type *const res = it->AsSuper(checker, sourceVar);
830             if (res != nullptr) {
831                 return res;
832             }
833         }
834     }
835 
836     return nullptr;
837 }
838 
CopyProperty(varbinder::LocalVariable * prop,ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)839 varbinder::LocalVariable *ETSObjectType::CopyProperty(varbinder::LocalVariable *prop, ArenaAllocator *allocator,
840                                                       TypeRelation *relation, GlobalTypesHolder *globalTypes)
841 {
842     auto *const copiedProp = prop->Copy(allocator, prop->Declaration());
843     auto *const copiedPropType = ETSChecker::TryToInstantiate(
844         relation->GetChecker()->AsETSChecker()->GetTypeOfVariable(prop), allocator, relation, globalTypes);
845     // NOTE: don't change type variable if it differs from copying one!
846     if (copiedPropType->Variable() == prop) {
847         copiedPropType->SetVariable(copiedProp);
848     }
849     copiedProp->SetTsType(copiedPropType);
850     return copiedProp;
851 }
852 
Instantiate(ArenaAllocator * const allocator,TypeRelation * const relation,GlobalTypesHolder * const globalTypes)853 Type *ETSObjectType::Instantiate(ArenaAllocator *const allocator, TypeRelation *const relation,
854                                  GlobalTypesHolder *const globalTypes)
855 {
856     auto *const checker = relation->GetChecker()->AsETSChecker();
857     std::lock_guard guard {*checker->Mutex()};
858     auto *const base = GetOriginalBaseType();
859 
860     if (!relation->IsAtTypeDepthLimit(base)) {
861         return this;
862     }
863     relation->IncreaseTypeRecursionCount(base);
864 
865     auto *const copiedType = checker->CreateNewETSObjectType(name_, declNode_, flags_);
866     copiedType->typeFlags_ = typeFlags_;
867     copiedType->RemoveObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS |
868                                  ETSObjectFlags::INCOMPLETE_INSTANTIATION | ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
869     copiedType->SetAssemblerName(assemblerName_);
870     copiedType->SetVariable(variable_);
871     copiedType->SetSuperType(superType_);
872 
873     for (auto *const it : interfaces_) {
874         copiedType->AddInterface(it);
875     }
876 
877     ArenaVector<Type *> typeArgs(allocator->Adapter());
878     for (auto *const typeArgument : TypeArguments()) {
879         typeArgs.emplace_back(typeArgument->Instantiate(allocator, relation, globalTypes));
880     }
881     copiedType->SetTypeArguments(std::move(typeArgs));
882     copiedType->SetBaseType(this);
883     copiedType->propertiesInstantiated_ = false;
884     copiedType->relation_ = relation;
885     copiedType->effectiveSubstitution_ = nullptr;
886 
887     relation->DecreaseTypeRecursionCount(base);
888 
889     return copiedType;
890 }
891 
SubstituteVariableType(TypeRelation * relation,const Substitution * substitution,Type * const varType)892 static Type *SubstituteVariableType(TypeRelation *relation, const Substitution *substitution, Type *const varType)
893 {
894     auto *substitutedType = varType->Substitute(relation, substitution);
895 
896     if (varType->HasTypeFlag(TypeFlag::ETS_REQUIRED_TYPE_PARAMETER)) {
897         substitutedType = relation->GetChecker()->AsETSChecker()->HandleRequiredType(substitutedType);
898     }
899 
900     return substitutedType;
901 }
902 
CopyPropertyWithTypeArguments(varbinder::LocalVariable * prop,TypeRelation * relation,const Substitution * substitution)903 static varbinder::LocalVariable *CopyPropertyWithTypeArguments(varbinder::LocalVariable *prop, TypeRelation *relation,
904                                                                const Substitution *substitution)
905 {
906     auto *const checker = relation->GetChecker()->AsETSChecker();
907     auto *const varType = ETSChecker::IsVariableGetterSetter(prop) ? prop->TsType() : checker->GetTypeOfVariable(prop);
908     auto *const copiedPropType = SubstituteVariableType(relation, substitution, varType);
909     auto *const copiedProp = prop->Copy(checker->Allocator(), prop->Declaration());
910     copiedPropType->SetVariable(copiedProp);
911     copiedProp->SetTsType(copiedPropType);
912     return copiedProp;
913 }
914 
GetConstOriginalBaseType() const915 ETSObjectType const *ETSObjectType::GetConstOriginalBaseType() const noexcept
916 {
917     if (auto *baseIter = GetBaseType(); baseIter != nullptr) {
918         auto *baseIterNext = baseIter->GetBaseType();
919         while (baseIterNext != nullptr && baseIterNext != baseIter) {
920             baseIter = baseIterNext;
921             baseIterNext = baseIter->GetBaseType();
922         }
923         return baseIter;
924     }
925     return this;
926 }
927 
SubstituteTypeArgs(TypeRelation * const relation,ArenaVector<Type * > & newTypeArgs,const Substitution * const substitution)928 bool ETSObjectType::SubstituteTypeArgs(TypeRelation *const relation, ArenaVector<Type *> &newTypeArgs,
929                                        const Substitution *const substitution)
930 {
931     bool anyChange = false;
932     newTypeArgs.reserve(typeArguments_.size());
933 
934     for (auto *const arg : typeArguments_) {
935         auto *const newArg = arg->Substitute(relation, substitution);
936         newTypeArgs.push_back(newArg);
937         anyChange = anyChange || (newArg != arg);
938     }
939 
940     return anyChange;
941 }
942 
ComputeEffectiveSubstitution(TypeRelation * const relation,const ArenaVector<Type * > & baseTypeParams,ArenaVector<Type * > & newTypeArgs)943 static Substitution *ComputeEffectiveSubstitution(TypeRelation *const relation,
944                                                   const ArenaVector<Type *> &baseTypeParams,
945                                                   ArenaVector<Type *> &newTypeArgs)
946 {
947     ASSERT(baseTypeParams.size() == newTypeArgs.size());
948     auto *const checker = relation->GetChecker()->AsETSChecker();
949     auto *effectiveSubstitution = checker->NewSubstitution();
950 
951     for (size_t ix = 0; ix < baseTypeParams.size(); ix++) {
952         ETSChecker::EmplaceSubstituted(effectiveSubstitution, baseTypeParams[ix]->AsETSTypeParameter(),
953                                        newTypeArgs[ix]);
954     }
955 
956     return effectiveSubstitution;
957 }
958 
SetCopiedTypeProperties(TypeRelation * const relation,ETSObjectType * const copiedType,ArenaVector<Type * > && newTypeArgs,ETSObjectType * base)959 void ETSObjectType::SetCopiedTypeProperties(TypeRelation *const relation, ETSObjectType *const copiedType,
960                                             ArenaVector<Type *> &&newTypeArgs, ETSObjectType *base)
961 {
962     copiedType->typeFlags_ = typeFlags_;
963     copiedType->RemoveObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS |
964                                  ETSObjectFlags::INCOMPLETE_INSTANTIATION | ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
965     copiedType->SetVariable(variable_);
966     copiedType->SetBaseType(base);
967 
968     auto const &baseTypeParams = base->TypeArguments();
969     copiedType->effectiveSubstitution_ = ComputeEffectiveSubstitution(relation, baseTypeParams, newTypeArgs);
970 
971     copiedType->SetTypeArguments(std::move(newTypeArgs));
972     copiedType->relation_ = relation;
973 }
974 
UpdateTypeProperty(checker::ETSChecker * checker,varbinder::LocalVariable * const prop,PropertyType fieldType,PropertyProcesser const & func)975 void ETSObjectType::UpdateTypeProperty(checker::ETSChecker *checker, varbinder::LocalVariable *const prop,
976                                        PropertyType fieldType, PropertyProcesser const &func)
977 {
978     auto *const propType = prop->Declaration()->Node()->Check(checker);
979 
980     auto *const propCopy = func(prop, propType);
981     if (fieldType == PropertyType::INSTANCE_FIELD) {
982         RemoveProperty<PropertyType::INSTANCE_FIELD>(prop);
983         AddProperty<PropertyType::INSTANCE_FIELD>(propCopy);
984     } else {
985         RemoveProperty<PropertyType::STATIC_FIELD>(prop);
986         AddProperty<PropertyType::STATIC_FIELD>(propCopy);
987     }
988 }
989 
UpdateTypeProperties(checker::ETSChecker * checker,PropertyProcesser const & func)990 void ETSObjectType::UpdateTypeProperties(checker::ETSChecker *checker, PropertyProcesser const &func)
991 {
992     AddTypeFlag(TypeFlag::READONLY);
993     for (auto const &prop : InstanceFields()) {
994         UpdateTypeProperty(checker, prop.second, PropertyType::INSTANCE_FIELD, func);
995     }
996 
997     for (auto const &prop : StaticFields()) {
998         UpdateTypeProperty(checker, prop.second, PropertyType::STATIC_FIELD, func);
999     }
1000 
1001     if (SuperType() != nullptr) {
1002         auto *const superProp = SuperType()->Clone(checker)->AsETSObjectType();
1003         superProp->UpdateTypeProperties(checker, func);
1004         SetSuperType(superProp);
1005     }
1006 }
1007 
Substitute(TypeRelation * relation,const Substitution * substitution,bool cache)1008 ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitution *substitution, bool cache)
1009 {
1010     if (substitution == nullptr || substitution->empty()) {
1011         return this;
1012     }
1013 
1014     auto *const checker = relation->GetChecker()->AsETSChecker();
1015     auto *base = GetOriginalBaseType();
1016 
1017     ArenaVector<Type *> newTypeArgs {checker->Allocator()->Adapter()};
1018     const bool anyChange = SubstituteTypeArgs(relation, newTypeArgs, substitution);
1019     // Lambda types can capture type params in their bodies, normal classes cannot.
1020     // NOTE: gogabr. determine precise conditions where we do not need to copy.
1021     // Perhaps keep track of captured type parameters for each type.
1022     if (!anyChange && !HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
1023         return this;
1024     }
1025 
1026     const util::StringView hash = checker->GetHashFromSubstitution(substitution);
1027     if (cache) {
1028         if (auto *inst = GetInstantiatedType(hash); inst != nullptr) {
1029             return inst;
1030         }
1031     }
1032 
1033     if (!relation->IsAtTypeDepthLimit(base)) {
1034         return this;
1035     }
1036     relation->IncreaseTypeRecursionCount(base);
1037 
1038     auto *const copiedType = checker->CreateNewETSObjectType(name_, declNode_, flags_);
1039     SetCopiedTypeProperties(relation, copiedType, std::move(newTypeArgs), base);
1040 
1041     if (cache) {
1042         GetInstantiationMap().try_emplace(hash, copiedType);
1043     }
1044 
1045     if (superType_ != nullptr) {
1046         copiedType->SetSuperType(superType_->Substitute(relation, substitution)->AsETSObjectType());
1047     }
1048     for (auto *itf : interfaces_) {
1049         auto *newItf = itf->Substitute(relation, substitution)->AsETSObjectType();
1050         copiedType->AddInterface(newItf);
1051     }
1052 
1053     relation->DecreaseTypeRecursionCount(base);
1054 
1055     return copiedType;
1056 }
1057 
Substitute(TypeRelation * relation,const Substitution * substitution)1058 ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitution *substitution)
1059 {
1060     return Substitute(relation, substitution, true);
1061 }
1062 
SubstituteArguments(TypeRelation * relation,ArenaVector<Type * > const & arguments)1063 ETSObjectType *ETSObjectType::SubstituteArguments(TypeRelation *relation, ArenaVector<Type *> const &arguments)
1064 {
1065     if (arguments.empty()) {
1066         return this;
1067     }
1068 
1069     auto *checker = relation->GetChecker()->AsETSChecker();
1070     auto *substitution = checker->NewSubstitution();
1071 
1072     ASSERT(baseType_ == nullptr);
1073     ASSERT(typeArguments_.size() == arguments.size());
1074 
1075     for (size_t ix = 0; ix < typeArguments_.size(); ix++) {
1076         substitution->emplace(typeArguments_[ix]->AsETSTypeParameter(), checker->MaybeBoxType(arguments[ix]));
1077     }
1078 
1079     return Substitute(relation, substitution);
1080 }
1081 
InstantiateProperties() const1082 void ETSObjectType::InstantiateProperties() const
1083 {
1084     ASSERT(relation_ != nullptr);
1085     auto *checker = relation_->GetChecker()->AsETSChecker();
1086 
1087     if (baseType_ == nullptr || baseType_ == this) {
1088         checker->ResolveDeclaredMembersOfObject(this);
1089         return;
1090     }
1091 
1092     ASSERT(!propertiesInstantiated_);
1093     declNode_->Check(checker);
1094 
1095     for (auto *const it : baseType_->ConstructSignatures()) {
1096         auto *newSig = it->Substitute(relation_, effectiveSubstitution_);
1097         constructSignatures_.push_back(newSig);
1098     }
1099 
1100     for (auto const &[_, prop] : baseType_->InstanceFields()) {
1101         (void)_;
1102         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1103         properties_[static_cast<size_t>(PropertyType::INSTANCE_FIELD)].emplace(prop->Name(), copiedProp);
1104     }
1105 
1106     for (auto const &[_, prop] : baseType_->StaticFields()) {
1107         (void)_;
1108         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1109         properties_[static_cast<size_t>(PropertyType::STATIC_FIELD)].emplace(prop->Name(), copiedProp);
1110     }
1111 
1112     for (auto const &[_, prop] : baseType_->InstanceMethods()) {
1113         (void)_;
1114         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1115         properties_[static_cast<size_t>(PropertyType::INSTANCE_METHOD)].emplace(prop->Name(), copiedProp);
1116     }
1117 
1118     for (auto const &[_, prop] : baseType_->StaticMethods()) {
1119         (void)_;
1120         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1121         properties_[static_cast<size_t>(PropertyType::STATIC_METHOD)].emplace(prop->Name(), copiedProp);
1122     }
1123 
1124     for (auto const &[_, prop] : baseType_->InstanceDecls()) {
1125         (void)_;
1126         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1127         properties_[static_cast<size_t>(PropertyType::INSTANCE_DECL)].emplace(prop->Name(), copiedProp);
1128     }
1129 
1130     for (auto const &[_, prop] : baseType_->StaticDecls()) {
1131         (void)_;
1132         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1133         properties_[static_cast<size_t>(PropertyType::STATIC_DECL)].emplace(prop->Name(), copiedProp);
1134     }
1135 }
1136 
DebugInfoTypeFromName(std::stringstream & ss,util::StringView asmName)1137 void ETSObjectType::DebugInfoTypeFromName(std::stringstream &ss, util::StringView asmName)
1138 {
1139     ss << compiler::Signatures::CLASS_REF_BEGIN;
1140     auto copied = asmName.Mutf8();
1141     std::replace(copied.begin(), copied.end(), *compiler::Signatures::METHOD_SEPARATOR.begin(),
1142                  *compiler::Signatures::NAMESPACE_SEPARATOR.begin());
1143     ss << copied;
1144     ss << compiler::Signatures::MANGLE_SEPARATOR;
1145 }
1146 
GetPrecedence(checker::ETSChecker * checker,ETSObjectType const * type)1147 std::uint32_t ETSObjectType::GetPrecedence(checker::ETSChecker *checker, ETSObjectType const *type) noexcept
1148 {
1149     ASSERT(type != nullptr);
1150     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_BYTE)) {
1151         return 1U;
1152     }
1153     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_CHAR)) {
1154         return 2U;
1155     }
1156     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_SHORT)) {
1157         return 3U;
1158     }
1159     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_INT)) {
1160         return 4U;
1161     }
1162     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_LONG)) {
1163         return 5U;
1164     }
1165     if (checker->Relation()->IsIdenticalTo(const_cast<ETSObjectType *>(type),
1166                                            checker->GetGlobalTypesHolder()->GlobalIntegralBuiltinType())) {
1167         return 5U;
1168     }
1169     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_FLOAT)) {
1170         return 6U;
1171     }
1172     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE)) {
1173         return 7U;
1174     }
1175     if (checker->Relation()->IsIdenticalTo(const_cast<ETSObjectType *>(type),
1176                                            checker->GetGlobalTypesHolder()->GlobalFloatingBuiltinType())) {
1177         return 7U;
1178     }
1179     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_BIGINT)) {
1180         return 8U;
1181     }
1182     return 0U;
1183 }
AddReExports(ETSObjectType * reExport)1184 void ETSObjectType::AddReExports(ETSObjectType *reExport)
1185 {
1186     if (std::find(reExports_.begin(), reExports_.end(), reExport) == reExports_.end()) {
1187         reExports_.push_back(reExport);
1188     }
1189 }
1190 
AddReExportAlias(util::StringView const & value,util::StringView const & key)1191 void ETSObjectType::AddReExportAlias(util::StringView const &value, util::StringView const &key)
1192 {
1193     reExportAlias_.insert({key, value});
1194 }
1195 
GetReExportAliasValue(util::StringView const & key) const1196 util::StringView ETSObjectType::GetReExportAliasValue(util::StringView const &key) const
1197 {
1198     auto ret = reExportAlias_.find(key);
1199     if (reExportAlias_.end() == ret) {
1200         return key;
1201     }
1202     return ret->second;
1203 }
1204 
IsReExportHaveAliasValue(util::StringView const & key) const1205 bool ETSObjectType::IsReExportHaveAliasValue(util::StringView const &key) const
1206 {
1207     return std::any_of(reExportAlias_.begin(), reExportAlias_.end(),
1208                        [&](const auto &val) { return val.second == key; });
1209 }
1210 
ReExports() const1211 const ArenaVector<ETSObjectType *> &ETSObjectType::ReExports() const
1212 {
1213     return reExports_;
1214 }
1215 
ToAssemblerType(std::stringstream & ss) const1216 void ETSObjectType::ToAssemblerType([[maybe_unused]] std::stringstream &ss) const
1217 {
1218     ss << assemblerName_;
1219 }
1220 
ToDebugInfoType(std::stringstream & ss) const1221 void ETSObjectType::ToDebugInfoType(std::stringstream &ss) const
1222 {
1223     DebugInfoTypeFromName(ss, assemblerName_);
1224 }
1225 
ToDebugInfoSignatureType(std::stringstream & ss) const1226 void ETSObjectType::ToDebugInfoSignatureType(std::stringstream &ss) const
1227 {
1228     ss << compiler::Signatures::GENERIC_BEGIN;
1229     ss << assemblerName_;
1230     ss << compiler::Signatures::GENERIC_END;
1231 }
1232 
GetTypeParams() const1233 ir::TSTypeParameterDeclaration *ETSObjectType::GetTypeParams() const
1234 {
1235     if (HasObjectFlag(ETSObjectFlags::ENUM) || !HasTypeFlag(TypeFlag::GENERIC)) {
1236         return nullptr;
1237     }
1238 
1239     if (HasObjectFlag(ETSObjectFlags::CLASS)) {
1240         ASSERT(declNode_->IsClassDefinition() && declNode_->AsClassDefinition()->TypeParams());
1241         return declNode_->AsClassDefinition()->TypeParams();
1242     }
1243 
1244     ASSERT(declNode_->IsTSInterfaceDeclaration() && declNode_->AsTSInterfaceDeclaration()->TypeParams());
1245     return declNode_->AsTSInterfaceDeclaration()->TypeParams();
1246 }
1247 
1248 }  // namespace ark::es2panda::checker
1249