• 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     if (funcType == nullptr) {
186         return nullptr;
187     }
188 
189     auto const addSignature = [funcType, flags](varbinder::LocalVariable *found) -> void {
190         for (auto *it : found->TsType()->AsETSFunctionType()->CallSignatures()) {
191             if (((flags & PropertySearchFlags::IGNORE_ABSTRACT) != 0) &&
192                 it->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
193                 continue;
194             }
195 
196             funcType->AddCallSignature(it);
197         }
198     };
199 
200     if ((flags & PropertySearchFlags::SEARCH_STATIC_METHOD) != 0) {
201         if (auto *found = GetOwnProperty<PropertyType::STATIC_METHOD>(name); found != nullptr) {
202             ASSERT(found->TsType()->IsETSFunctionType());
203             addSignature(found);
204         }
205     }
206 
207     if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) != 0) {
208         if (auto *found = GetOwnProperty<PropertyType::INSTANCE_METHOD>(name); found != nullptr) {
209             ASSERT(found->TsType()->IsETSFunctionType());
210             addSignature(found);
211         }
212     }
213 
214     if (superType_ != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) {
215         return superType_->CollectSignaturesForSyntheticType(funcType, name, flags);
216     }
217 
218     return nullptr;
219 }
220 
GetAllProperties() const221 std::vector<varbinder::LocalVariable *> ETSObjectType::GetAllProperties() const
222 {
223     std::vector<varbinder::LocalVariable *> allProperties;
224     for (const auto &[_, prop] : InstanceFields()) {
225         (void)_;
226         allProperties.push_back(prop);
227     }
228 
229     for (const auto &[_, prop] : StaticFields()) {
230         (void)_;
231         allProperties.push_back(prop);
232     }
233 
234     for (const auto &[_, prop] : InstanceMethods()) {
235         (void)_;
236         allProperties.push_back(prop);
237     }
238 
239     for (const auto &[_, prop] : StaticMethods()) {
240         (void)_;
241         allProperties.push_back(prop);
242     }
243 
244     for (const auto &[_, prop] : InstanceDecls()) {
245         (void)_;
246         allProperties.push_back(prop);
247     }
248 
249     for (const auto &[_, prop] : StaticDecls()) {
250         (void)_;
251         allProperties.push_back(prop);
252     }
253 
254     return allProperties;
255 }
256 
Methods() const257 std::vector<varbinder::LocalVariable *> ETSObjectType::Methods() const
258 {
259     std::vector<varbinder::LocalVariable *> methods;
260     for (const auto &[_, prop] : InstanceMethods()) {
261         (void)_;
262         methods.push_back(prop);
263     }
264 
265     for (const auto &[_, prop] : StaticMethods()) {
266         (void)_;
267         methods.push_back(prop);
268     }
269 
270     return methods;
271 }
272 
Fields() const273 std::vector<varbinder::LocalVariable *> ETSObjectType::Fields() const
274 {
275     std::vector<varbinder::LocalVariable *> fields;
276     for (const auto &[_, prop] : InstanceFields()) {
277         (void)_;
278         fields.push_back(prop);
279     }
280 
281     for (const auto &[_, prop] : StaticFields()) {
282         (void)_;
283         fields.push_back(prop);
284     }
285 
286     return fields;
287 }
288 
ForeignProperties() const289 std::vector<const varbinder::LocalVariable *> ETSObjectType::ForeignProperties() const
290 {
291     std::vector<const varbinder::LocalVariable *> foreignProps;
292     std::unordered_set<util::StringView> ownProps;
293 
294     EnsurePropertiesInstantiated();
295     ownProps.reserve(properties_.size());
296 
297     for (const auto *prop : GetAllProperties()) {
298         ownProps.insert(prop->Name());
299     }
300 
301     auto allProps = CollectAllProperties();
302     for (const auto &[name, var] : allProps) {
303         if (ownProps.find(name) == ownProps.end()) {
304             foreignProps.push_back(var);
305         }
306     }
307 
308     return foreignProps;
309 }
310 
CollectAllProperties() const311 ArenaMap<util::StringView, const varbinder::LocalVariable *> ETSObjectType::CollectAllProperties() const
312 {
313     ArenaMap<util::StringView, const varbinder::LocalVariable *> propMap(allocator_->Adapter());
314     EnsurePropertiesInstantiated();
315     Iterate([&propMap](const varbinder::LocalVariable *var) { propMap.emplace(var->Name(), var); });
316 
317     return propMap;
318 }
319 
ToString(std::stringstream & ss,bool precise) const320 void ETSObjectType::ToString(std::stringstream &ss, bool precise) const
321 {
322     if (HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
323         GetFunctionalInterfaceInvokeType()->ToString(ss, precise);
324         return;
325     }
326 
327     const bool isRequiredType = HasObjectFlag(ETSObjectFlags::REQUIRED);
328     if (isRequiredType) {
329         ss << "Required" << compiler::Signatures::GENERIC_BEGIN;
330     }
331 
332     if (precise) {
333         ss << assemblerName_;  // NOTE(gogabr): need full qualified name
334     } else {
335         ss << name_;
336     }
337 
338     if (!typeArguments_.empty()) {
339         ss << compiler::Signatures::GENERIC_BEGIN;
340         for (auto arg = typeArguments_.cbegin(); arg != typeArguments_.cend(); ++arg) {
341             (*arg)->ToString(ss, precise);
342 
343             if (next(arg) != typeArguments_.cend()) {
344                 ss << lexer::TokenToString(lexer::TokenType::PUNCTUATOR_COMMA);
345             }
346         }
347         ss << compiler::Signatures::GENERIC_END;
348     }
349 
350     if (isRequiredType) {
351         ss << compiler::Signatures::GENERIC_END;
352     }
353 }
354 
IdenticalUptoTypeArguments(TypeRelation * relation,Type * other)355 void ETSObjectType::IdenticalUptoTypeArguments(TypeRelation *relation, Type *other)
356 {
357     relation->Result(false);
358     if (!other->IsETSObjectType() || !CheckIdenticalFlags(other->AsETSObjectType())) {
359         return;
360     }
361 
362     auto *thisBase = GetOriginalBaseType();
363     auto *otherBase = other->AsETSObjectType()->GetOriginalBaseType();
364     if (thisBase->Variable() != otherBase->Variable()) {
365         return;
366     }
367 
368     if ((relation->IgnoreTypeParameters() && !HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) || (this == other)) {
369         relation->Result(true);
370         return;
371     }
372 
373     auto const sourceTypeArguments = other->AsETSObjectType()->TypeArguments();
374     if (typeArguments_.empty() != sourceTypeArguments.empty()) {
375         return;
376     }
377 
378     relation->Result(true);
379 }
380 
Identical(TypeRelation * relation,Type * other)381 void ETSObjectType::Identical(TypeRelation *relation, Type *other)
382 {
383     IdenticalUptoTypeArguments(relation, other);
384 
385     if (!relation->IsTrue() || !HasTypeFlag(TypeFlag::GENERIC)) {
386         return;
387     }
388 
389     auto const otherTypeArguments = other->AsETSObjectType()->TypeArguments();
390 
391     auto const argsNumber = typeArguments_.size();
392     if (argsNumber != otherTypeArguments.size()) {
393         relation->Result(false);
394         return;
395     }
396 
397     for (size_t idx = 0U; idx < argsNumber; ++idx) {
398         if (typeArguments_[idx]->IsWildcardType() || otherTypeArguments[idx]->IsWildcardType()) {
399             continue;
400         }
401         if (!relation->IsIdenticalTo(typeArguments_[idx], otherTypeArguments[idx])) {
402             return;
403         }
404     }
405 
406     relation->Result(true);
407 }
408 
CheckIdenticalFlags(ETSObjectType * other) const409 bool ETSObjectType::CheckIdenticalFlags(ETSObjectType *other) const
410 {
411     constexpr auto FLAGS_TO_REMOVE = ETSObjectFlags::INCOMPLETE_INSTANTIATION |
412                                      ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS |
413                                      ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY | ETSObjectFlags::READONLY;
414     // note(lujiahui): we support assigning T to Readonly<T>, but do not support assigning Readonly<T> to T
415     // more details in spec
416     if (!HasObjectFlag(ETSObjectFlags::READONLY) && other->HasObjectFlag(ETSObjectFlags::READONLY)) {
417         return false;
418     }
419     auto cleanedTargetFlags = other->ObjectFlags();
420     cleanedTargetFlags &= ~FLAGS_TO_REMOVE;
421 
422     auto cleanedSelfFlags = ObjectFlags();
423     cleanedSelfFlags &= ~FLAGS_TO_REMOVE;
424 
425     return cleanedSelfFlags == cleanedTargetFlags;
426 }
427 
AssignmentSource(TypeRelation * const relation,Type * const target)428 bool ETSObjectType::AssignmentSource(TypeRelation *const relation, [[maybe_unused]] Type *const target)
429 {
430     return relation->Result(false);
431 }
432 
AssignmentTarget(TypeRelation * const relation,Type * source)433 void ETSObjectType::AssignmentTarget(TypeRelation *const relation, Type *source)
434 {
435     if (source->IsETSObjectType() && source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::READONLY)) {
436         relation->Result(false);
437         return;
438     }
439 
440     if (HasObjectFlag(ETSObjectFlags::FUNCTIONAL) && source->IsETSFunctionType()) {
441         EnsurePropertiesInstantiated();
442         auto found = properties_[static_cast<size_t>(PropertyType::INSTANCE_METHOD)].find(
443             FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME);
444         ASSERT(found != properties_[static_cast<size_t>(PropertyType::INSTANCE_METHOD)].end());
445         source = source->AsETSFunctionType()->BoxPrimitives(relation->GetChecker()->AsETSChecker());
446         relation->IsAssignableTo(source, found->second->TsType());
447         return;
448     }
449 
450     relation->IsSupertypeOf(this, source);
451 }
452 
CastWideningNarrowing(TypeRelation * const relation,Type * const target,TypeFlag unboxFlags,TypeFlag wideningFlags,TypeFlag narrowingFlags)453 bool ETSObjectType::CastWideningNarrowing(TypeRelation *const relation, Type *const target, TypeFlag unboxFlags,
454                                           TypeFlag wideningFlags, TypeFlag narrowingFlags)
455 {
456     if (target->HasTypeFlag(unboxFlags)) {
457         conversion::Unboxing(relation, this);
458         return true;
459     }
460     if (target->HasTypeFlag(wideningFlags)) {
461         conversion::UnboxingWideningPrimitive(relation, this, target);
462         return true;
463     }
464     if (target->HasTypeFlag(narrowingFlags)) {
465         conversion::UnboxingNarrowingPrimitive(relation, this, target);
466         return true;
467     }
468     return false;
469 }
470 
TryCastByte(TypeRelation * const relation,Type * const target)471 bool ETSObjectType::TryCastByte(TypeRelation *const relation, Type *const target)
472 {
473     if (target->HasTypeFlag(TypeFlag::BYTE)) {
474         conversion::Unboxing(relation, this);
475         return true;
476     }
477     if (target->HasTypeFlag(TypeFlag::SHORT | TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE)) {
478         conversion::UnboxingWideningPrimitive(relation, this, target);
479         return true;
480     }
481     if (target->HasTypeFlag(TypeFlag::CHAR)) {
482         conversion::UnboxingWideningNarrowingPrimitive(relation, this, target);
483         return true;
484     }
485     return false;
486 }
487 
TryCastIntegral(TypeRelation * const relation,Type * const target)488 bool ETSObjectType::TryCastIntegral(TypeRelation *const relation, Type *const target)
489 {
490     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_BYTE) && TryCastByte(relation, target)) {
491         return true;
492     }
493     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_SHORT) &&
494         CastWideningNarrowing(relation, target, TypeFlag::SHORT,
495                               TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE,
496                               TypeFlag::BYTE | TypeFlag::CHAR)) {
497         return true;
498     }
499     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_CHAR) &&
500         CastWideningNarrowing(relation, target, TypeFlag::CHAR,
501                               TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE,
502                               TypeFlag::BYTE | TypeFlag::SHORT)) {
503         return true;
504     }
505     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_INT) &&
506         CastWideningNarrowing(relation, target, TypeFlag::INT, TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE,
507                               TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR)) {
508         return true;
509     }
510     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_LONG) &&
511         CastWideningNarrowing(relation, target, TypeFlag::LONG, TypeFlag::FLOAT | TypeFlag::DOUBLE,
512                               TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT)) {
513         return true;
514     }
515     return false;
516 }
517 
TryCastFloating(TypeRelation * const relation,Type * const target)518 bool ETSObjectType::TryCastFloating(TypeRelation *const relation, Type *const target)
519 {
520     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_FLOAT) &&
521         CastWideningNarrowing(relation, target, TypeFlag::FLOAT, TypeFlag::DOUBLE,
522                               TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT | TypeFlag::LONG)) {
523         return true;
524     }
525     if (auto narrowingFlags =
526             TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT;
527         this->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE) &&
528         CastWideningNarrowing(relation, target, TypeFlag::DOUBLE, TypeFlag::NONE, narrowingFlags)) {
529         return true;
530     }
531     return false;
532 }
533 
TryCastUnboxable(TypeRelation * const relation,Type * const target)534 bool ETSObjectType::TryCastUnboxable(TypeRelation *const relation, Type *const target)
535 {
536     if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
537         if (!target->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) {
538             conversion::WideningReference(relation, this, target->AsETSObjectType());
539             return true;
540         }
541         auto unboxedTarget = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target);
542         CastNumericObject(relation, unboxedTarget);
543         if (relation->IsTrue()) {
544             conversion::Boxing(relation, unboxedTarget);
545             return true;
546         }
547         conversion::WideningReference(relation, this, target->AsETSObjectType());
548         return true;
549     }
550     conversion::Forbidden(relation);
551     return true;
552 }
553 
CastNumericObject(TypeRelation * const relation,Type * const target)554 bool ETSObjectType::CastNumericObject(TypeRelation *const relation, Type *const target)
555 {
556     if (!target->HasTypeFlag(TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT | TypeFlag::LONG |
557                              TypeFlag::FLOAT | TypeFlag::DOUBLE | TypeFlag::ETS_BOOLEAN)) {
558         return false;
559     }
560     if (relation->IsIdenticalTo(this, target)) {
561         return true;
562     }
563     if (TryCastIntegral(relation, target)) {
564         return true;
565     }
566     if (TryCastFloating(relation, target)) {
567         return true;
568     }
569     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_BOOLEAN) && target->HasTypeFlag(TypeFlag::ETS_BOOLEAN)) {
570         conversion::Unboxing(relation, this);
571         return true;
572     }
573     if (this->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) {
574         return TryCastUnboxable(relation, target);
575     }
576     if (target->HasTypeFlag(TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT | TypeFlag::LONG |
577                             TypeFlag::FLOAT | TypeFlag::DOUBLE | TypeFlag::ETS_BOOLEAN)) {
578         conversion::NarrowingReferenceUnboxing(relation, this, target);
579         return true;
580     }
581     return false;
582 }
583 
Cast(TypeRelation * const relation,Type * const target)584 void ETSObjectType::Cast(TypeRelation *const relation, Type *const target)
585 {
586     conversion::Identity(relation, this, target);
587     if (relation->IsTrue()) {
588         return;
589     }
590 
591     if (CastNumericObject(relation, target)) {
592         return;
593     }
594 
595     if (target->HasTypeFlag(TypeFlag::ETS_ARRAY)) {
596         conversion::NarrowingReference(relation, this, target->AsETSArrayType());
597         return;
598     }
599 
600     if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
601         conversion::WideningReference(relation, this, target->AsETSObjectType());
602         if (relation->IsTrue()) {
603             return;
604         }
605 
606         conversion::NarrowingReference(relation, this, target->AsETSObjectType());
607         if (relation->IsTrue()) {
608             return;
609         }
610     }
611 
612     if (target->IsETSEnumType()) {
613         relation->GetNode()->AddBoxingUnboxingFlags(ir::BoxingUnboxingFlags::UNBOX_TO_ENUM);
614         relation->Result(true);
615         return;
616     }
617     conversion::Forbidden(relation);
618 }
619 
DefaultObjectTypeChecks(const ETSChecker * const etsChecker,TypeRelation * const relation,Type * const source)620 bool ETSObjectType::DefaultObjectTypeChecks(const ETSChecker *const etsChecker, TypeRelation *const relation,
621                                             Type *const source)
622 {
623     relation->Result(false);
624 
625     // 3.8.3 Subtyping among Array Types
626     auto const *const base = GetConstOriginalBaseType();
627     if (base == etsChecker->GlobalETSObjectType() && source->IsETSArrayType()) {
628         relation->Result(true);
629         return true;
630     }
631 
632     if (!source->IsETSObjectType() ||
633         !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE)) {
634         return true;
635     }
636 
637     // All classes and interfaces are subtypes of Object
638     if (base == etsChecker->GlobalETSObjectType()) {
639         relation->Result(true);
640         return true;
641     }
642 
643     IdenticalUptoTypeArguments(relation, source);
644     if (relation->IsTrue() && HasTypeFlag(TypeFlag::GENERIC)) {
645         IsGenericSupertypeOf(relation, source);
646     }
647     return relation->IsTrue();
648 }
649 
IsSupertypeOf(TypeRelation * relation,Type * source)650 void ETSObjectType::IsSupertypeOf(TypeRelation *relation, Type *source)
651 {
652     relation->Result(false);
653     auto *const etsChecker = relation->GetChecker()->AsETSChecker();
654 
655     if (DefaultObjectTypeChecks(etsChecker, relation, source)) {
656         return;
657     }
658 
659     ETSObjectType *sourceObj = source->AsETSObjectType();
660     if (auto *sourceSuper = sourceObj->SuperType(); sourceSuper != nullptr) {
661         if (relation->IsSupertypeOf(this, sourceSuper)) {
662             return;
663         }
664     }
665 
666     if (HasObjectFlag(ETSObjectFlags::INTERFACE)) {
667         for (auto *itf : sourceObj->Interfaces()) {
668             if (relation->IsSupertypeOf(this, itf)) {
669                 return;
670             }
671         }
672     }
673 }
674 
IsGenericSupertypeOf(TypeRelation * relation,Type * source)675 void ETSObjectType::IsGenericSupertypeOf(TypeRelation *relation, Type *source)
676 {
677     ASSERT(HasTypeFlag(TypeFlag::GENERIC));
678 
679     auto *sourceType = source->AsETSObjectType();
680     auto const &sourceTypeArguments = sourceType->TypeArguments();
681     auto const typeArgumentsNumber = typeArguments_.size();
682     if (typeArgumentsNumber > sourceTypeArguments.size()) {
683         relation->Result(false);
684         return;
685     }
686 
687     ASSERT(declNode_ == sourceType->GetDeclNode());
688 
689     auto *typeParamsDecl = GetTypeParams();
690     ASSERT(typeParamsDecl != nullptr || typeArguments_.empty());
691 
692     if (typeParamsDecl == nullptr) {
693         return;
694     }
695 
696     auto &typeParams = typeParamsDecl->Params();
697     ASSERT(typeParams.size() == typeArgumentsNumber);
698 
699     for (size_t idx = 0U; idx < typeArgumentsNumber; ++idx) {
700         auto *typeArg = typeArguments_[idx];
701         auto *sourceTypeArg = sourceTypeArguments[idx];
702         auto *typeParam = typeParams[idx];
703 
704         relation->Result(false);
705         if (typeArg->IsWildcardType() || sourceTypeArg->IsWildcardType()) {
706             continue;
707         }
708         if (typeParam->IsOut()) {
709             relation->IsSupertypeOf(typeArg, sourceTypeArg);
710         } else if (typeParam->IsIn()) {
711             relation->IsSupertypeOf(sourceTypeArg, typeArg);
712         } else {
713             relation->IsIdenticalTo(typeArg, sourceTypeArg);
714         }
715 
716         if (!relation->IsTrue()) {
717             return;
718         }
719     }
720 
721     relation->Result(true);
722 }
723 
AsSuper(Checker * checker,varbinder::Variable * sourceVar)724 Type *ETSObjectType::AsSuper(Checker *checker, varbinder::Variable *sourceVar)
725 {
726     if (sourceVar == nullptr) {
727         return nullptr;
728     }
729 
730     if (variable_ == sourceVar) {
731         return this;
732     }
733 
734     if (HasObjectFlag(ETSObjectFlags::INTERFACE)) {
735         Type *res = nullptr;
736         for (auto *const it : checker->AsETSChecker()->GetInterfaces(this)) {
737             res = it->AsSuper(checker, sourceVar);
738             if (res != nullptr) {
739                 return res;
740             }
741         }
742         return checker->GetGlobalTypesHolder()->GlobalETSObjectType()->AsSuper(checker, sourceVar);
743     }
744 
745     Type *const superType = checker->AsETSChecker()->GetSuperType(this);
746 
747     if (superType == nullptr) {
748         return nullptr;
749     }
750 
751     if (!superType->IsETSObjectType()) {
752         return nullptr;
753     }
754 
755     if (ETSObjectType *const superObj = superType->AsETSObjectType(); superObj->HasObjectFlag(ETSObjectFlags::CLASS)) {
756         Type *const res = superObj->AsSuper(checker, sourceVar);
757         if (res != nullptr) {
758             return res;
759         }
760     }
761 
762     if (sourceVar->TsType()->IsETSObjectType() &&
763         sourceVar->TsType()->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
764         for (auto *const it : checker->AsETSChecker()->GetInterfaces(this)) {
765             Type *const res = it->AsSuper(checker, sourceVar);
766             if (res != nullptr) {
767                 return res;
768             }
769         }
770     }
771 
772     return nullptr;
773 }
774 
CopyProperty(varbinder::LocalVariable * prop,ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)775 varbinder::LocalVariable *ETSObjectType::CopyProperty(varbinder::LocalVariable *prop, ArenaAllocator *allocator,
776                                                       TypeRelation *relation, GlobalTypesHolder *globalTypes)
777 {
778     auto *const copiedProp = prop->Copy(allocator, prop->Declaration());
779     auto *const copiedPropType = ETSChecker::TryToInstantiate(
780         relation->GetChecker()->AsETSChecker()->GetTypeOfVariable(prop), allocator, relation, globalTypes);
781     // NOTE: don't change type variable if it differs from copying one!
782     if (copiedPropType->Variable() == prop) {
783         copiedPropType->SetVariable(copiedProp);
784     }
785     copiedProp->SetTsType(copiedPropType);
786     return copiedProp;
787 }
788 
Instantiate(ArenaAllocator * const allocator,TypeRelation * const relation,GlobalTypesHolder * const globalTypes)789 Type *ETSObjectType::Instantiate(ArenaAllocator *const allocator, TypeRelation *const relation,
790                                  GlobalTypesHolder *const globalTypes)
791 {
792     auto *const checker = relation->GetChecker()->AsETSChecker();
793     std::lock_guard guard {*checker->Mutex()};
794     auto *const base = GetOriginalBaseType();
795 
796     if (!relation->TypeInstantiationPossible(base)) {
797         return this;
798     }
799     relation->IncreaseTypeRecursionCount(base);
800 
801     auto *const copiedType = checker->CreateNewETSObjectType(name_, declNode_, flags_);
802     copiedType->typeFlags_ = typeFlags_;
803     copiedType->RemoveObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS |
804                                  ETSObjectFlags::INCOMPLETE_INSTANTIATION | ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
805     copiedType->SetAssemblerName(assemblerName_);
806     copiedType->SetVariable(variable_);
807     copiedType->SetSuperType(superType_);
808 
809     for (auto *const it : interfaces_) {
810         copiedType->AddInterface(it);
811     }
812 
813     for (auto *const typeArgument : TypeArguments()) {
814         copiedType->TypeArguments().emplace_back(typeArgument->Instantiate(allocator, relation, globalTypes));
815     }
816     copiedType->SetBaseType(this);
817     copiedType->propertiesInstantiated_ = false;
818     copiedType->relation_ = relation;
819     copiedType->effectiveSubstitution_ = nullptr;
820 
821     relation->DecreaseTypeRecursionCount(base);
822 
823     return copiedType;
824 }
825 
SubstituteVariableType(TypeRelation * relation,const Substitution * substitution,Type * const varType)826 static Type *SubstituteVariableType(TypeRelation *relation, const Substitution *substitution, Type *const varType)
827 {
828     auto *substitutedType = varType->Substitute(relation, substitution);
829 
830     if (varType->HasTypeFlag(TypeFlag::ETS_REQUIRED_TYPE_PARAMETER)) {
831         substitutedType = relation->GetChecker()->AsETSChecker()->HandleRequiredType(substitutedType);
832     }
833 
834     return substitutedType;
835 }
836 
CopyPropertyWithTypeArguments(varbinder::LocalVariable * prop,TypeRelation * relation,const Substitution * substitution)837 static varbinder::LocalVariable *CopyPropertyWithTypeArguments(varbinder::LocalVariable *prop, TypeRelation *relation,
838                                                                const Substitution *substitution)
839 {
840     auto *const checker = relation->GetChecker()->AsETSChecker();
841     auto *const varType = ETSChecker::IsVariableGetterSetter(prop) ? prop->TsType() : checker->GetTypeOfVariable(prop);
842     auto *const copiedPropType = SubstituteVariableType(relation, substitution, varType);
843     auto *const copiedProp = prop->Copy(checker->Allocator(), prop->Declaration());
844     copiedPropType->SetVariable(copiedProp);
845     copiedProp->SetTsType(copiedPropType);
846     return copiedProp;
847 }
848 
GetConstOriginalBaseType() const849 ETSObjectType const *ETSObjectType::GetConstOriginalBaseType() const noexcept
850 {
851     if (auto *baseIter = GetBaseType(); baseIter != nullptr) {
852         auto *baseIterNext = baseIter->GetBaseType();
853         while (baseIterNext != nullptr && baseIterNext != baseIter) {
854             baseIter = baseIterNext;
855             baseIterNext = baseIter->GetBaseType();
856         }
857         return baseIter;
858     }
859     return this;
860 }
861 
SubstituteTypeArgs(TypeRelation * const relation,ArenaVector<Type * > & newTypeArgs,const Substitution * const substitution)862 bool ETSObjectType::SubstituteTypeArgs(TypeRelation *const relation, ArenaVector<Type *> &newTypeArgs,
863                                        const Substitution *const substitution)
864 {
865     bool anyChange = false;
866     newTypeArgs.reserve(typeArguments_.size());
867 
868     for (auto *const arg : typeArguments_) {
869         auto *const newArg = arg->Substitute(relation, substitution);
870         newTypeArgs.push_back(newArg);
871         anyChange = anyChange || (newArg != arg);
872     }
873 
874     return anyChange;
875 }
876 
ComputeEffectiveSubstitution(TypeRelation * const relation,const ArenaVector<Type * > & baseTypeParams,ArenaVector<Type * > & newTypeArgs)877 static Substitution *ComputeEffectiveSubstitution(TypeRelation *const relation,
878                                                   const ArenaVector<Type *> &baseTypeParams,
879                                                   ArenaVector<Type *> &newTypeArgs)
880 {
881     ASSERT(baseTypeParams.size() == newTypeArgs.size());
882     auto *const checker = relation->GetChecker()->AsETSChecker();
883     auto *effectiveSubstitution = checker->NewSubstitution();
884 
885     for (size_t ix = 0; ix < baseTypeParams.size(); ix++) {
886         ETSChecker::EmplaceSubstituted(effectiveSubstitution, baseTypeParams[ix]->AsETSTypeParameter(),
887                                        newTypeArgs[ix]);
888     }
889 
890     return effectiveSubstitution;
891 }
892 
SetCopiedTypeProperties(TypeRelation * const relation,ETSObjectType * const copiedType,ArenaVector<Type * > && newTypeArgs,ETSObjectType * base)893 void ETSObjectType::SetCopiedTypeProperties(TypeRelation *const relation, ETSObjectType *const copiedType,
894                                             ArenaVector<Type *> &&newTypeArgs, ETSObjectType *base)
895 {
896     copiedType->typeFlags_ = typeFlags_;
897     copiedType->RemoveObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS |
898                                  ETSObjectFlags::INCOMPLETE_INSTANTIATION | ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
899     copiedType->SetVariable(variable_);
900     copiedType->SetBaseType(base);
901 
902     auto const &baseTypeParams = base->TypeArguments();
903     copiedType->effectiveSubstitution_ = ComputeEffectiveSubstitution(relation, baseTypeParams, newTypeArgs);
904 
905     copiedType->SetTypeArguments(std::move(newTypeArgs));
906     copiedType->relation_ = relation;
907 }
908 
UpdateTypeProperty(checker::ETSChecker * checker,varbinder::LocalVariable * const prop,PropertyType fieldType,PropertyProcesser const & func)909 void ETSObjectType::UpdateTypeProperty(checker::ETSChecker *checker, varbinder::LocalVariable *const prop,
910                                        PropertyType fieldType, PropertyProcesser const &func)
911 {
912     auto *const propType = prop->Declaration()->Node()->Check(checker);
913 
914     if (propType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
915         checker->ThrowTypeError("Base type of a Utility type can only contain fields with reference type.",
916                                 prop->Declaration()->Node()->Start());
917     }
918 
919     auto *const propCopy = func(prop, propType);
920     if (fieldType == PropertyType::INSTANCE_FIELD) {
921         RemoveProperty<PropertyType::INSTANCE_FIELD>(prop);
922         AddProperty<PropertyType::INSTANCE_FIELD>(propCopy);
923     } else {
924         RemoveProperty<PropertyType::STATIC_FIELD>(prop);
925         AddProperty<PropertyType::STATIC_FIELD>(propCopy);
926     }
927 }
928 
UpdateTypeProperties(checker::ETSChecker * checker,PropertyProcesser const & func)929 void ETSObjectType::UpdateTypeProperties(checker::ETSChecker *checker, PropertyProcesser const &func)
930 {
931     AddObjectFlag(ETSObjectFlags::READONLY);
932     for (auto const &prop : InstanceFields()) {
933         UpdateTypeProperty(checker, prop.second, PropertyType::INSTANCE_FIELD, func);
934     }
935 
936     for (auto const &prop : StaticFields()) {
937         UpdateTypeProperty(checker, prop.second, PropertyType::STATIC_FIELD, func);
938     }
939 
940     if (SuperType() != nullptr) {
941         auto *const superProp = SuperType()->Clone(checker)->AsETSObjectType();
942         superProp->UpdateTypeProperties(checker, func);
943         SetSuperType(superProp);
944     }
945 }
946 
Substitute(TypeRelation * relation,const Substitution * substitution,bool cache)947 ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitution *substitution, bool cache)
948 {
949     if (substitution == nullptr || substitution->empty()) {
950         return this;
951     }
952 
953     auto *const checker = relation->GetChecker()->AsETSChecker();
954     auto *base = GetOriginalBaseType();
955 
956     ArenaVector<Type *> newTypeArgs {checker->Allocator()->Adapter()};
957     const bool anyChange = SubstituteTypeArgs(relation, newTypeArgs, substitution);
958     // Lambda types can capture type params in their bodies, normal classes cannot.
959     // NOTE: gogabr. determine precise conditions where we do not need to copy.
960     // Perhaps keep track of captured type parameters for each type.
961     if (!anyChange && !HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
962         return this;
963     }
964 
965     const util::StringView hash = checker->GetHashFromSubstitution(substitution);
966     if (cache) {
967         if (auto *inst = GetInstantiatedType(hash); inst != nullptr) {
968             return inst;
969         }
970     }
971 
972     if (!relation->TypeInstantiationPossible(base)) {
973         return this;
974     }
975     relation->IncreaseTypeRecursionCount(base);
976 
977     auto *const copiedType = checker->CreateNewETSObjectType(name_, declNode_, flags_);
978     SetCopiedTypeProperties(relation, copiedType, std::move(newTypeArgs), base);
979 
980     if (cache) {
981         GetInstantiationMap().try_emplace(hash, copiedType);
982     }
983 
984     if (superType_ != nullptr) {
985         copiedType->SetSuperType(superType_->Substitute(relation, substitution)->AsETSObjectType());
986     }
987     for (auto *itf : interfaces_) {
988         auto *newItf = itf->Substitute(relation, substitution)->AsETSObjectType();
989         copiedType->AddInterface(newItf);
990     }
991 
992     relation->DecreaseTypeRecursionCount(base);
993 
994     return copiedType;
995 }
996 
Substitute(TypeRelation * relation,const Substitution * substitution)997 ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitution *substitution)
998 {
999     return Substitute(relation, substitution, true);
1000 }
1001 
SubstituteArguments(TypeRelation * relation,ArenaVector<Type * > const & arguments)1002 ETSObjectType *ETSObjectType::SubstituteArguments(TypeRelation *relation, ArenaVector<Type *> const &arguments)
1003 {
1004     if (arguments.empty()) {
1005         return this;
1006     }
1007 
1008     auto *checker = relation->GetChecker()->AsETSChecker();
1009     auto *substitution = checker->NewSubstitution();
1010 
1011     ASSERT(baseType_ == nullptr);
1012     ASSERT(typeArguments_.size() == arguments.size());
1013 
1014     for (size_t ix = 0; ix < typeArguments_.size(); ix++) {
1015         substitution->emplace(typeArguments_[ix]->AsETSTypeParameter(),
1016                               checker->MaybePromotedBuiltinType(arguments[ix]));
1017     }
1018 
1019     return Substitute(relation, substitution);
1020 }
1021 
InstantiateProperties() const1022 void ETSObjectType::InstantiateProperties() const
1023 {
1024     ASSERT(relation_ != nullptr);
1025     auto *checker = relation_->GetChecker()->AsETSChecker();
1026 
1027     if (baseType_ == nullptr || baseType_ == this) {
1028         checker->ResolveDeclaredMembersOfObject(this);
1029         return;
1030     }
1031 
1032     ASSERT(!propertiesInstantiated_);
1033     declNode_->Check(checker);
1034 
1035     for (auto *const it : baseType_->ConstructSignatures()) {
1036         auto *newSig = it->Substitute(relation_, effectiveSubstitution_);
1037         constructSignatures_.push_back(newSig);
1038     }
1039 
1040     for (auto const &[_, prop] : baseType_->InstanceFields()) {
1041         (void)_;
1042         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1043         properties_[static_cast<size_t>(PropertyType::INSTANCE_FIELD)].emplace(prop->Name(), copiedProp);
1044     }
1045 
1046     for (auto const &[_, prop] : baseType_->StaticFields()) {
1047         (void)_;
1048         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1049         properties_[static_cast<size_t>(PropertyType::STATIC_FIELD)].emplace(prop->Name(), copiedProp);
1050     }
1051 
1052     for (auto const &[_, prop] : baseType_->InstanceMethods()) {
1053         (void)_;
1054         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1055         properties_[static_cast<size_t>(PropertyType::INSTANCE_METHOD)].emplace(prop->Name(), copiedProp);
1056     }
1057 
1058     for (auto const &[_, prop] : baseType_->StaticMethods()) {
1059         (void)_;
1060         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1061         properties_[static_cast<size_t>(PropertyType::STATIC_METHOD)].emplace(prop->Name(), copiedProp);
1062     }
1063 
1064     for (auto const &[_, prop] : baseType_->InstanceDecls()) {
1065         (void)_;
1066         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1067         properties_[static_cast<size_t>(PropertyType::INSTANCE_DECL)].emplace(prop->Name(), copiedProp);
1068     }
1069 
1070     for (auto const &[_, prop] : baseType_->StaticDecls()) {
1071         (void)_;
1072         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, effectiveSubstitution_);
1073         properties_[static_cast<size_t>(PropertyType::STATIC_DECL)].emplace(prop->Name(), copiedProp);
1074     }
1075 }
1076 
DebugInfoTypeFromName(std::stringstream & ss,util::StringView asmName)1077 void ETSObjectType::DebugInfoTypeFromName(std::stringstream &ss, util::StringView asmName)
1078 {
1079     ss << compiler::Signatures::CLASS_REF_BEGIN;
1080     auto copied = asmName.Mutf8();
1081     std::replace(copied.begin(), copied.end(), *compiler::Signatures::METHOD_SEPARATOR.begin(),
1082                  *compiler::Signatures::NAMESPACE_SEPARATOR.begin());
1083     ss << copied;
1084     ss << compiler::Signatures::MANGLE_SEPARATOR;
1085 }
1086 
GetPrecedence(checker::ETSChecker * checker,ETSObjectType const * type)1087 std::uint32_t ETSObjectType::GetPrecedence(checker::ETSChecker *checker, ETSObjectType const *type) noexcept
1088 {
1089     ASSERT(type != nullptr);
1090     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_BYTE)) {
1091         return 1U;
1092     }
1093     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_CHAR)) {
1094         return 2U;
1095     }
1096     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_SHORT)) {
1097         return 3U;
1098     }
1099     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_INT)) {
1100         return 4U;
1101     }
1102     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_LONG)) {
1103         return 5U;
1104     }
1105     if (checker->Relation()->IsIdenticalTo(const_cast<ETSObjectType *>(type),
1106                                            checker->GetGlobalTypesHolder()->GlobalIntegralBuiltinType())) {
1107         return 5U;
1108     }
1109     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_FLOAT)) {
1110         return 6U;
1111     }
1112     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE)) {
1113         return 7U;
1114     }
1115     if (checker->Relation()->IsIdenticalTo(const_cast<ETSObjectType *>(type),
1116                                            checker->GetGlobalTypesHolder()->GlobalFloatingBuiltinType())) {
1117         return 7U;
1118     }
1119     if (type->HasObjectFlag(ETSObjectFlags::BUILTIN_BIGINT)) {
1120         return 8U;
1121     }
1122     return 0U;
1123 }
AddReExports(ETSObjectType * reExport)1124 void ETSObjectType::AddReExports(ETSObjectType *reExport)
1125 {
1126     if (std::find(reExports_.begin(), reExports_.end(), reExport) == reExports_.end()) {
1127         reExports_.push_back(reExport);
1128     }
1129 }
1130 
AddReExportAlias(util::StringView const & value,util::StringView const & key)1131 void ETSObjectType::AddReExportAlias(util::StringView const &value, util::StringView const &key)
1132 {
1133     reExportAlias_.insert({key, value});
1134 }
1135 
GetReExportAliasValue(util::StringView const & key) const1136 util::StringView ETSObjectType::GetReExportAliasValue(util::StringView const &key) const
1137 {
1138     auto ret = reExportAlias_.find(key);
1139     if (reExportAlias_.end() == ret) {
1140         return key;
1141     }
1142     return ret->second;
1143 }
1144 
IsReExportHaveAliasValue(util::StringView const & key) const1145 bool ETSObjectType::IsReExportHaveAliasValue(util::StringView const &key) const
1146 {
1147     return std::any_of(reExportAlias_.begin(), reExportAlias_.end(),
1148                        [&](const auto &val) { return val.second == key; });
1149 }
1150 
ReExports() const1151 const ArenaVector<ETSObjectType *> &ETSObjectType::ReExports() const
1152 {
1153     return reExports_;
1154 }
1155 
ToAssemblerType(std::stringstream & ss) const1156 void ETSObjectType::ToAssemblerType([[maybe_unused]] std::stringstream &ss) const
1157 {
1158     ss << assemblerName_;
1159 }
1160 
ToDebugInfoType(std::stringstream & ss) const1161 void ETSObjectType::ToDebugInfoType(std::stringstream &ss) const
1162 {
1163     DebugInfoTypeFromName(ss, assemblerName_);
1164 }
1165 
ToDebugInfoSignatureType(std::stringstream & ss) const1166 void ETSObjectType::ToDebugInfoSignatureType(std::stringstream &ss) const
1167 {
1168     ss << compiler::Signatures::GENERIC_BEGIN;
1169     ss << assemblerName_;
1170     ss << compiler::Signatures::GENERIC_END;
1171 }
1172 
1173 }  // namespace ark::es2panda::checker
1174