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