• 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 "varbinder/declaration.h"
19 #include "checker/ETSchecker.h"
20 #include "checker/ets/conversion.h"
21 #include "checker/types/typeFlag.h"
22 #include "checker/types/typeRelation.h"
23 #include "ir/base/methodDefinition.h"
24 #include "ir/base/scriptFunction.h"
25 #include "ir/expressions/identifier.h"
26 
27 namespace panda::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 
GetProperty(const util::StringView & name,PropertySearchFlags flags) const44 varbinder::LocalVariable *ETSObjectType::GetProperty(const util::StringView &name, PropertySearchFlags flags) const
45 {
46     varbinder::LocalVariable *res {};
47     if ((flags & PropertySearchFlags::SEARCH_INSTANCE_FIELD) != 0) {
48         res = GetOwnProperty<PropertyType::INSTANCE_FIELD>(name);
49     }
50 
51     if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_FIELD) != 0)) {
52         res = GetOwnProperty<PropertyType::STATIC_FIELD>(name);
53     }
54 
55     if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_INSTANCE_DECL) != 0)) {
56         res = GetOwnProperty<PropertyType::INSTANCE_DECL>(name);
57     }
58 
59     if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_DECL) != 0)) {
60         res = GetOwnProperty<PropertyType::STATIC_DECL>(name);
61     }
62 
63     if (res == nullptr && (flags & PropertySearchFlags::SEARCH_METHOD) != 0) {
64         res = GetOwnProperty<PropertyType::INSTANCE_FIELD>(name);
65         if (res != nullptr && res->TsType() != nullptr && res->TsType()->IsETSDynamicType()) {
66             return res;
67         }
68         res = nullptr;
69         if ((flags & PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION) != 0) {
70             if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) != 0) {
71                 res = GetOwnProperty<PropertyType::INSTANCE_METHOD>(name);
72             }
73 
74             if (res == nullptr && ((flags & PropertySearchFlags::SEARCH_STATIC_METHOD) != 0)) {
75                 res = GetOwnProperty<PropertyType::STATIC_METHOD>(name);
76             }
77         } else {
78             res = CreateSyntheticVarFromEverySignature(name, flags);
79         }
80     }
81 
82     if ((flags & (PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::SEARCH_IN_BASE)) == 0) {
83         return res;
84     }
85 
86     if (res != nullptr) {
87         return res;
88     }
89 
90     if ((flags & PropertySearchFlags::SEARCH_IN_INTERFACES) != 0) {
91         for (auto *interface : interfaces_) {
92             res = interface->GetProperty(name, flags);
93             if (res != nullptr) {
94                 return res;
95             }
96         }
97     }
98 
99     if (superType_ != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) {
100         res = superType_->GetProperty(name, flags);
101     }
102 
103     return res;
104 }
105 
CreateSyntheticVarFromEverySignature(const util::StringView & name,PropertySearchFlags flags) const106 varbinder::LocalVariable *ETSObjectType::CreateSyntheticVarFromEverySignature(const util::StringView &name,
107                                                                               PropertySearchFlags flags) const
108 {
109     varbinder::LocalVariable *res = allocator_->New<varbinder::LocalVariable>(varbinder::VariableFlags::SYNTHETIC |
110                                                                               varbinder::VariableFlags::METHOD);
111     ETSFunctionType *funcType = CreateETSFunctionType(name);
112     funcType->AddTypeFlag(TypeFlag::SYNTHETIC);
113 
114     varbinder::LocalVariable *functionalInterface = CollectSignaturesForSyntheticType(funcType, name, flags);
115 
116     if (functionalInterface != nullptr) {
117         return functionalInterface;
118     }
119 
120     if (funcType->CallSignatures().empty()) {
121         return nullptr;
122     }
123 
124     res->SetTsType(funcType);
125     funcType->SetVariable(res);
126     return res;
127 }
128 
CreateETSFunctionType(const util::StringView & name) const129 ETSFunctionType *ETSObjectType::CreateETSFunctionType(const util::StringView &name) const
130 {
131     return allocator_->New<ETSFunctionType>(name, allocator_);
132 }
133 
CollectSignaturesForSyntheticType(ETSFunctionType * funcType,const util::StringView & name,PropertySearchFlags flags) const134 varbinder::LocalVariable *ETSObjectType::CollectSignaturesForSyntheticType(ETSFunctionType *funcType,
135                                                                            const util::StringView &name,
136                                                                            PropertySearchFlags flags) const
137 {
138     auto const addSignature = [funcType, flags](varbinder::LocalVariable *found) -> void {
139         for (auto *it : found->TsType()->AsETSFunctionType()->CallSignatures()) {
140             if (((flags & PropertySearchFlags::IGNORE_ABSTRACT) != 0) &&
141                 it->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
142                 continue;
143             }
144 
145             funcType->AddCallSignature(it);
146         }
147     };
148 
149     // During function reference resolution, if the found properties type is not a function type, then it is a
150     // functional interface, because no other property can be found in the methods of the class. We have to
151     // return the found property, because we doesn't need to create a synthetic variable for functional
152     // interfaces due to the fact, that by nature they behave as fields, and can't have overloads, and they are
153     // subjected to hiding
154     if ((flags & PropertySearchFlags::SEARCH_STATIC_METHOD) != 0) {
155         if (auto *found = GetOwnProperty<PropertyType::STATIC_METHOD>(name); found != nullptr) {
156             if (found->HasFlag(varbinder::VariableFlags::METHOD_REFERENCE)) {
157                 // Functional interface found
158                 return found;
159             }
160 
161             ASSERT(found->TsType()->IsETSFunctionType());
162             addSignature(found);
163         }
164     }
165 
166     if ((flags & PropertySearchFlags::SEARCH_INSTANCE_METHOD) != 0) {
167         if (auto *found = GetOwnProperty<PropertyType::INSTANCE_METHOD>(name); found != nullptr) {
168             if (found->HasFlag(varbinder::VariableFlags::METHOD_REFERENCE)) {
169                 // Functional interface found
170                 return found;
171             }
172 
173             ASSERT(found->TsType()->IsETSFunctionType());
174             addSignature(found);
175         }
176     }
177 
178     if (superType_ != nullptr && ((flags & PropertySearchFlags::SEARCH_IN_BASE) != 0)) {
179         return superType_->CollectSignaturesForSyntheticType(funcType, name, flags);
180     }
181 
182     return nullptr;
183 }
184 
GetAllProperties() const185 std::vector<varbinder::LocalVariable *> ETSObjectType::GetAllProperties() const
186 {
187     std::vector<varbinder::LocalVariable *> allProperties;
188     for (const auto &[_, prop] : InstanceFields()) {
189         (void)_;
190         allProperties.push_back(prop);
191     }
192 
193     for (const auto &[_, prop] : StaticFields()) {
194         (void)_;
195         allProperties.push_back(prop);
196     }
197 
198     for (const auto &[_, prop] : InstanceMethods()) {
199         (void)_;
200         allProperties.push_back(prop);
201     }
202 
203     for (const auto &[_, prop] : StaticMethods()) {
204         (void)_;
205         allProperties.push_back(prop);
206     }
207 
208     for (const auto &[_, prop] : InstanceDecls()) {
209         (void)_;
210         allProperties.push_back(prop);
211     }
212 
213     for (const auto &[_, prop] : StaticDecls()) {
214         (void)_;
215         allProperties.push_back(prop);
216     }
217 
218     return allProperties;
219 }
220 
Methods() const221 std::vector<varbinder::LocalVariable *> ETSObjectType::Methods() const
222 {
223     std::vector<varbinder::LocalVariable *> methods;
224     for (const auto &[_, prop] : InstanceMethods()) {
225         (void)_;
226         methods.push_back(prop);
227     }
228 
229     for (const auto &[_, prop] : StaticMethods()) {
230         (void)_;
231         methods.push_back(prop);
232     }
233 
234     return methods;
235 }
236 
Fields() const237 std::vector<varbinder::LocalVariable *> ETSObjectType::Fields() const
238 {
239     std::vector<varbinder::LocalVariable *> fields;
240     for (const auto &[_, prop] : InstanceFields()) {
241         (void)_;
242         fields.push_back(prop);
243     }
244 
245     for (const auto &[_, prop] : StaticFields()) {
246         (void)_;
247         fields.push_back(prop);
248     }
249 
250     return fields;
251 }
252 
ForeignProperties() const253 std::vector<const varbinder::LocalVariable *> ETSObjectType::ForeignProperties() const
254 {
255     std::vector<const varbinder::LocalVariable *> foreignProps;
256     std::unordered_set<util::StringView> ownProps;
257 
258     EnsurePropertiesInstantiated();
259     ownProps.reserve(properties_.size());
260 
261     for (const auto *prop : GetAllProperties()) {
262         ownProps.insert(prop->Name());
263     }
264 
265     auto allProps = CollectAllProperties();
266     for (const auto &[name, var] : allProps) {
267         if (ownProps.find(name) == ownProps.end()) {
268             foreignProps.push_back(var);
269         }
270     }
271 
272     return foreignProps;
273 }
274 
CollectAllProperties() const275 std::unordered_map<util::StringView, const varbinder::LocalVariable *> ETSObjectType::CollectAllProperties() const
276 {
277     std::unordered_map<util::StringView, const varbinder::LocalVariable *> propMap;
278     EnsurePropertiesInstantiated();
279     propMap.reserve(properties_.size());
280     Iterate([&propMap](const varbinder::LocalVariable *var) { propMap.insert({var->Name(), var}); });
281 
282     return propMap;
283 }
284 
ToString(std::stringstream & ss) const285 void ETSObjectType::ToString(std::stringstream &ss) const
286 {
287     ss << name_;
288 
289     if (!typeArguments_.empty()) {
290         auto const typeArgumentsSize = typeArguments_.size();
291         ss << compiler::Signatures::GENERIC_BEGIN;
292         typeArguments_[0]->ToString(ss);
293         for (std::size_t i = 1U; i < typeArgumentsSize; ++i) {
294             ss << ',';
295             typeArguments_[i]->ToString(ss);
296         }
297         ss << compiler::Signatures::GENERIC_END;
298     }
299 
300     if (IsNullish() && this != GetConstOriginalBaseType() && !name_.Is("NullType") && !IsETSNullLike() &&
301         !name_.Empty()) {
302         if (ContainsNull()) {
303             ss << "|null";
304         }
305         if (ContainsUndefined()) {
306             ss << "|undefined";
307         }
308     }
309 }
310 
IdenticalUptoNullability(TypeRelation * relation,Type * other)311 void ETSObjectType::IdenticalUptoNullability(TypeRelation *relation, Type *other)
312 {
313     relation->Result(false);
314     if (!other->IsETSObjectType() || !CheckIdenticalFlags(other->AsETSObjectType()->ObjectFlags())) {
315         return;
316     }
317 
318     auto *thisBase = GetOriginalBaseType();
319     auto *otherBase = other->AsETSObjectType()->GetOriginalBaseType();
320     if (thisBase->Variable() != otherBase->Variable()) {
321         return;
322     }
323 
324     if (relation->IgnoreTypeParameters() || (this == other)) {
325         relation->Result(true);
326         return;
327     }
328 
329     auto const otherTypeArguments = other->AsETSObjectType()->TypeArguments();
330 
331     if (HasTypeFlag(TypeFlag::GENERIC) || IsNullish()) {
332         if (!HasTypeFlag(TypeFlag::GENERIC)) {
333             relation->Result(true);
334             return;
335         }
336         if (typeArguments_.empty() != otherTypeArguments.empty()) {
337             return;
338         }
339 
340         auto const argsNumber = typeArguments_.size();
341         ASSERT(argsNumber == otherTypeArguments.size());
342 
343         for (size_t idx = 0U; idx < argsNumber; ++idx) {
344             if (typeArguments_[idx]->IsWildcardType() || otherTypeArguments[idx]->IsWildcardType()) {
345                 continue;
346             }
347 
348             // checking the nullishness of type args before getting their original base types
349             // because most probably GetOriginalBaseType will return the non-nullish version of the type
350             if (!typeArguments_[idx]->IsNullish() && otherTypeArguments[idx]->IsNullish()) {
351                 return;
352             }
353 
354             const auto getOriginalBaseTypeOrType = [&relation](Type *const originalType) {
355                 auto *const baseType = relation->GetChecker()->AsETSChecker()->GetOriginalBaseType(originalType);
356                 return baseType == nullptr ? originalType : baseType;
357             };
358 
359             auto *const typeArgType = getOriginalBaseTypeOrType(typeArguments_[idx]);
360             auto *const otherTypeArgType = getOriginalBaseTypeOrType(otherTypeArguments[idx]);
361 
362             typeArgType->Identical(relation, otherTypeArgType);
363             if (!relation->IsTrue()) {
364                 return;
365             }
366         }
367     } else {
368         if (HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
369             auto getInvokeSignature = [](const ETSObjectType *type) {
370                 auto const propInvoke =
371                     type->GetProperty(util::StringView("invoke"), PropertySearchFlags::SEARCH_INSTANCE_METHOD);
372                 ASSERT(propInvoke != nullptr);
373                 return propInvoke->TsType()->AsETSFunctionType()->CallSignatures()[0];
374             };
375 
376             auto *const thisInvokeSignature = getInvokeSignature(this);
377             auto *const otherInvokeSignature = getInvokeSignature(other->AsETSObjectType());
378 
379             relation->IsIdenticalTo(thisInvokeSignature, otherInvokeSignature);
380             return;
381         }
382     }
383 
384     relation->Result(true);
385 }
386 
Identical(TypeRelation * relation,Type * other)387 void ETSObjectType::Identical(TypeRelation *relation, Type *other)
388 {
389     if ((ContainsNull() != other->ContainsNull()) || (ContainsUndefined() != other->ContainsUndefined())) {
390         return;
391     }
392     IdenticalUptoNullability(relation, other);
393 }
394 
CheckIdenticalFlags(ETSObjectFlags target) const395 bool ETSObjectType::CheckIdenticalFlags(ETSObjectFlags target) const
396 {
397     auto cleanedTargetFlags = static_cast<ETSObjectFlags>(target & (~ETSObjectFlags::COMPLETELY_RESOLVED));
398     cleanedTargetFlags &= ~ETSObjectFlags::INCOMPLETE_INSTANTIATION;
399     cleanedTargetFlags &= ~ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS;
400     cleanedTargetFlags &= ~ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY;
401     auto cleanedSelfFlags = static_cast<ETSObjectFlags>(ObjectFlags() & (~ETSObjectFlags::COMPLETELY_RESOLVED));
402     cleanedSelfFlags &= ~ETSObjectFlags::INCOMPLETE_INSTANTIATION;
403     cleanedSelfFlags &= ~ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS;
404     cleanedSelfFlags &= ~ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY;
405     return cleanedSelfFlags == cleanedTargetFlags;
406 }
407 
AssignmentSource(TypeRelation * const relation,Type * const target)408 bool ETSObjectType::AssignmentSource(TypeRelation *const relation, Type *const target)
409 {
410     relation->Result((IsETSNullType() && target->ContainsNull()) ||
411                      (IsETSUndefinedType() && target->ContainsUndefined()));
412 
413     return relation->IsTrue();
414 }
415 
AssignmentTarget(TypeRelation * const relation,Type * source)416 void ETSObjectType::AssignmentTarget(TypeRelation *const relation, Type *source)
417 {
418     if (source->IsETSNullType()) {
419         relation->Result(ContainsNull());
420         return;
421     }
422     if (source->IsETSUndefinedType()) {
423         relation->Result(ContainsUndefined());
424         return;
425     }
426 
427     if ((source->ContainsNull() && !ContainsNull()) || (source->ContainsUndefined() && !ContainsUndefined())) {
428         return;
429     }
430 
431     if (HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
432         EnsurePropertiesInstantiated();
433         auto found = properties_[static_cast<size_t>(PropertyType::INSTANCE_METHOD)].find("invoke");
434         ASSERT(found != properties_[static_cast<size_t>(PropertyType::INSTANCE_METHOD)].end());
435         relation->IsAssignableTo(source, found->second->TsType());
436         return;
437     }
438 
439     relation->IsSupertypeOf(this, source);
440 }
441 
CastWideningNarrowing(TypeRelation * const relation,Type * const target,TypeFlag unboxFlags,TypeFlag wideningFlags,TypeFlag narrowingFlags)442 bool ETSObjectType::CastWideningNarrowing(TypeRelation *const relation, Type *const target, TypeFlag unboxFlags,
443                                           TypeFlag wideningFlags, TypeFlag narrowingFlags)
444 {
445     if (target->HasTypeFlag(unboxFlags)) {
446         conversion::Unboxing(relation, this);
447         return true;
448     }
449     if (target->HasTypeFlag(wideningFlags)) {
450         conversion::UnboxingWideningPrimitive(relation, this, target);
451         return true;
452     }
453     if (target->HasTypeFlag(narrowingFlags)) {
454         conversion::UnboxingNarrowingPrimitive(relation, this, target);
455         return true;
456     }
457     return false;
458 }
459 
CastNumericObject(TypeRelation * const relation,Type * const target)460 bool ETSObjectType::CastNumericObject(TypeRelation *const relation, Type *const target)
461 {
462     if (this->IsNullish()) {
463         return false;
464     }
465 
466     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_BYTE)) {
467         if (target->HasTypeFlag(TypeFlag::BYTE)) {
468             conversion::Unboxing(relation, this);
469             return true;
470         }
471         if (target->HasTypeFlag(TypeFlag::SHORT | TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT |
472                                 TypeFlag::DOUBLE)) {
473             conversion::UnboxingWideningPrimitive(relation, this, target);
474             return true;
475         }
476         if (target->HasTypeFlag(TypeFlag::CHAR)) {
477             conversion::UnboxingWideningNarrowingPrimitive(relation, this, target);
478             return true;
479         }
480     }
481     TypeFlag unboxFlags = TypeFlag::NONE;
482     TypeFlag wideningFlags = TypeFlag::NONE;
483     TypeFlag narrowingFlags = TypeFlag::NONE;
484     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_SHORT)) {
485         unboxFlags = TypeFlag::SHORT;
486         wideningFlags = TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE;
487         narrowingFlags = TypeFlag::BYTE | TypeFlag::CHAR;
488         if (CastWideningNarrowing(relation, target, unboxFlags, wideningFlags, narrowingFlags)) {
489             return true;
490         }
491     }
492     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_CHAR)) {
493         unboxFlags = TypeFlag::CHAR;
494         wideningFlags = TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE;
495         narrowingFlags = TypeFlag::BYTE | TypeFlag::SHORT;
496         if (CastWideningNarrowing(relation, target, unboxFlags, wideningFlags, narrowingFlags)) {
497             return true;
498         }
499     }
500     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_INT)) {
501         unboxFlags = TypeFlag::INT;
502         wideningFlags = TypeFlag::LONG | TypeFlag::FLOAT | TypeFlag::DOUBLE;
503         narrowingFlags = TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR;
504         if (CastWideningNarrowing(relation, target, unboxFlags, wideningFlags, narrowingFlags)) {
505             return true;
506         }
507     }
508     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_LONG)) {
509         unboxFlags = TypeFlag::LONG;
510         wideningFlags = TypeFlag::FLOAT | TypeFlag::DOUBLE;
511         narrowingFlags = TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT;
512         if (CastWideningNarrowing(relation, target, unboxFlags, wideningFlags, narrowingFlags)) {
513             return true;
514         }
515     }
516     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_FLOAT)) {
517         unboxFlags = TypeFlag::FLOAT;
518         wideningFlags = TypeFlag::DOUBLE;
519         narrowingFlags = TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT | TypeFlag::LONG;
520         if (CastWideningNarrowing(relation, target, unboxFlags, wideningFlags, narrowingFlags)) {
521             return true;
522         }
523     }
524     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_DOUBLE)) {
525         unboxFlags = TypeFlag::DOUBLE;
526         wideningFlags = TypeFlag::NONE;
527         narrowingFlags =
528             TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT | TypeFlag::LONG | TypeFlag::FLOAT;
529         if (CastWideningNarrowing(relation, target, unboxFlags, wideningFlags, narrowingFlags)) {
530             return true;
531         }
532     }
533     if (this->HasObjectFlag(ETSObjectFlags::BUILTIN_BOOLEAN)) {
534         if (target->HasTypeFlag(TypeFlag::ETS_BOOLEAN)) {
535             conversion::Unboxing(relation, this);
536             return true;
537         }
538     }
539     if (this->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) {
540         if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
541             if (!target->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) {
542                 conversion::WideningReference(relation, this, target->AsETSObjectType());
543                 return true;
544             }
545             auto unboxedTarget = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target);
546             CastNumericObject(relation, unboxedTarget);
547             if (relation->IsTrue()) {
548                 conversion::Boxing(relation, unboxedTarget);
549                 return true;
550             }
551             conversion::WideningReference(relation, this, target->AsETSObjectType());
552             return true;
553         }
554         conversion::Forbidden(relation);
555         return true;
556     }
557     if (target->HasTypeFlag(TypeFlag::BYTE | TypeFlag::SHORT | TypeFlag::CHAR | TypeFlag::INT | TypeFlag::LONG |
558                             TypeFlag::FLOAT | TypeFlag::DOUBLE | TypeFlag::ETS_BOOLEAN)) {
559         conversion::NarrowingReferenceUnboxing(relation, this, target);
560         return true;
561     }
562     return false;
563 }
564 
Cast(TypeRelation * const relation,Type * const target)565 void ETSObjectType::Cast(TypeRelation *const relation, Type *const target)
566 {
567     conversion::Identity(relation, this, target);
568     if (relation->IsTrue()) {
569         return;
570     }
571 
572     if (this->IsETSNullLike()) {
573         if (target->HasTypeFlag(TypeFlag::ETS_ARRAY_OR_OBJECT)) {
574             relation->GetNode()->SetTsType(target);
575             relation->Result(true);
576             return;
577         }
578 
579         conversion::Forbidden(relation);
580         return;
581     }
582 
583     if (CastNumericObject(relation, target)) {
584         return;
585     }
586 
587     if (target->HasTypeFlag(TypeFlag::ETS_ARRAY)) {
588         conversion::NarrowingReference(relation, this, target->AsETSArrayType());
589         return;
590     }
591 
592     if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
593         conversion::WideningReference(relation, this, target->AsETSObjectType());
594         if (relation->IsTrue()) {
595             return;
596         }
597 
598         conversion::NarrowingReference(relation, this, target->AsETSObjectType());
599         if (relation->IsTrue()) {
600             return;
601         }
602     }
603 
604     conversion::Forbidden(relation);
605 }
606 
IsSupertypeOf(TypeRelation * relation,Type * source)607 void ETSObjectType::IsSupertypeOf(TypeRelation *relation, Type *source)
608 {
609     relation->Result(false);
610     auto *const etsChecker = relation->GetChecker()->AsETSChecker();
611 
612     if (source->IsETSUnionType()) {
613         bool res = std::all_of(source->AsETSUnionType()->ConstituentTypes().begin(),
614                                source->AsETSUnionType()->ConstituentTypes().end(), [this, relation](Type *ct) {
615                                    relation->Result(false);
616                                    IsSupertypeOf(relation, ct);
617                                    return relation->IsTrue();
618                                });
619         relation->Result(res);
620         return;
621     }
622 
623     // 3.8.3 Subtyping among Array Types
624     auto const *const base = GetConstOriginalBaseType();
625     if (base == etsChecker->GlobalETSObjectType() && source->IsETSArrayType()) {
626         relation->Result(true);
627         return;
628     }
629 
630     if (!source->IsETSObjectType() ||
631         !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE |
632                                                   ETSObjectFlags::NULL_TYPE)) {
633         return;
634     }
635 
636     if ((!ContainsNull() && source->ContainsNull()) || (!ContainsUndefined() && source->ContainsUndefined())) {
637         return;
638     }
639     // All classes and interfaces are subtypes of Object
640     if (base == etsChecker->GlobalETSObjectType() || base == etsChecker->GlobalETSNullishObjectType()) {
641         relation->Result(true);
642         return;
643     }
644 
645     IdenticalUptoNullability(relation, source);
646     if (relation->IsTrue()) {
647         return;
648     }
649 
650     ETSObjectType *sourceObj = source->AsETSObjectType();
651     if (auto *sourceSuper = sourceObj->SuperType(); sourceSuper != nullptr) {
652         if (relation->IsSupertypeOf(this, sourceSuper)) {
653             return;
654         }
655     }
656 
657     if (HasObjectFlag(ETSObjectFlags::INTERFACE)) {
658         for (auto *itf : sourceObj->Interfaces()) {
659             if (relation->IsSupertypeOf(this, itf)) {
660                 return;
661             }
662         }
663     }
664 }
665 
AsSuper(Checker * checker,varbinder::Variable * sourceVar)666 Type *ETSObjectType::AsSuper(Checker *checker, varbinder::Variable *sourceVar)
667 {
668     if (sourceVar == nullptr) {
669         return nullptr;
670     }
671 
672     if (variable_ == sourceVar) {
673         return this;
674     }
675 
676     if (HasObjectFlag(ETSObjectFlags::INTERFACE)) {
677         Type *res = nullptr;
678         for (auto *const it : checker->AsETSChecker()->GetInterfaces(this)) {
679             res = it->AsSuper(checker, sourceVar);
680             if (res != nullptr) {
681                 return res;
682             }
683         }
684         return checker->GetGlobalTypesHolder()->GlobalETSObjectType()->AsSuper(checker, sourceVar);
685     }
686 
687     Type *const superType = checker->AsETSChecker()->GetSuperType(this);
688 
689     if (superType == nullptr) {
690         return nullptr;
691     }
692 
693     if (!superType->IsETSObjectType()) {
694         return nullptr;
695     }
696 
697     if (ETSObjectType *const superObj = superType->AsETSObjectType(); superObj->HasObjectFlag(ETSObjectFlags::CLASS)) {
698         Type *const res = superObj->AsSuper(checker, sourceVar);
699         if (res != nullptr) {
700             return res;
701         }
702     }
703 
704     if (sourceVar->TsType()->IsETSObjectType() &&
705         sourceVar->TsType()->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
706         for (auto *const it : checker->AsETSChecker()->GetInterfaces(this)) {
707             Type *const res = it->AsSuper(checker, sourceVar);
708             if (res != nullptr) {
709                 return res;
710             }
711         }
712     }
713 
714     return nullptr;
715 }
716 
CopyProperty(varbinder::LocalVariable * prop,ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)717 varbinder::LocalVariable *ETSObjectType::CopyProperty(varbinder::LocalVariable *prop, ArenaAllocator *allocator,
718                                                       TypeRelation *relation, GlobalTypesHolder *globalTypes)
719 {
720     auto *const copiedProp = prop->Copy(allocator, prop->Declaration());
721     auto *const copiedPropType = ETSChecker::TryToInstantiate(
722         relation->GetChecker()->AsETSChecker()->GetTypeOfVariable(prop), allocator, relation, globalTypes);
723     // NOTE: don't change type variable if it differs from copying one!
724     if (copiedPropType->Variable() == prop) {
725         copiedPropType->SetVariable(copiedProp);
726     }
727     copiedProp->SetTsType(copiedPropType);
728     return copiedProp;
729 }
730 
Instantiate(ArenaAllocator * const allocator,TypeRelation * const relation,GlobalTypesHolder * const globalTypes)731 Type *ETSObjectType::Instantiate(ArenaAllocator *const allocator, TypeRelation *const relation,
732                                  GlobalTypesHolder *const globalTypes)
733 {
734     auto *const checker = relation->GetChecker()->AsETSChecker();
735     std::lock_guard guard {*checker->Mutex()};
736     auto *const base = GetOriginalBaseType();
737 
738     if (!relation->TypeInstantiationPossible(base) || IsETSNullLike()) {
739         return this;
740     }
741     relation->IncreaseTypeRecursionCount(base);
742 
743     auto *const copiedType = checker->CreateNewETSObjectType(name_, declNode_, flags_);
744     copiedType->typeFlags_ = typeFlags_;
745     copiedType->RemoveObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS |
746                                  ETSObjectFlags::INCOMPLETE_INSTANTIATION | ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
747     copiedType->SetAssemblerName(assemblerName_);
748     copiedType->SetVariable(variable_);
749     copiedType->SetSuperType(superType_);
750 
751     for (auto *const it : interfaces_) {
752         copiedType->AddInterface(it);
753     }
754 
755     for (auto *const typeArgument : TypeArguments()) {
756         copiedType->TypeArguments().emplace_back(typeArgument->Instantiate(allocator, relation, globalTypes));
757     }
758     copiedType->SetBaseType(this);
759     copiedType->propertiesInstantiated_ = false;
760     copiedType->relation_ = relation;
761     copiedType->substitution_ = nullptr;
762 
763     relation->DecreaseTypeRecursionCount(base);
764 
765     return copiedType;
766 }
767 
CopyPropertyWithTypeArguments(varbinder::LocalVariable * prop,TypeRelation * relation,const Substitution * substitution)768 static varbinder::LocalVariable *CopyPropertyWithTypeArguments(varbinder::LocalVariable *prop, TypeRelation *relation,
769                                                                const Substitution *substitution)
770 {
771     auto *const checker = relation->GetChecker()->AsETSChecker();
772     auto *const copiedPropType = checker->GetTypeOfVariable(prop)->Substitute(relation, substitution);
773     auto *const copiedProp = prop->Copy(checker->Allocator(), prop->Declaration());
774     copiedPropType->SetVariable(copiedProp);
775     copiedProp->SetTsType(copiedPropType);
776     return copiedProp;
777 }
778 
GetConstOriginalBaseType() const779 ETSObjectType const *ETSObjectType::GetConstOriginalBaseType() const noexcept
780 {
781     if (auto *baseIter = GetBaseType(); baseIter != nullptr) {
782         auto *baseIterNext = baseIter->GetBaseType();
783         while (baseIterNext != nullptr && baseIterNext != baseIter) {
784             baseIter = baseIterNext;
785             baseIterNext = baseIter->GetBaseType();
786         }
787         return baseIter;
788     }
789     return this;
790 }
791 
SubstituteTypeArgs(TypeRelation * const relation,ArenaVector<Type * > & newTypeArgs,const Substitution * const substitution)792 bool ETSObjectType::SubstituteTypeArgs(TypeRelation *const relation, ArenaVector<Type *> &newTypeArgs,
793                                        const Substitution *const substitution)
794 {
795     bool anyChange = false;
796     newTypeArgs.reserve(typeArguments_.size());
797 
798     for (auto *const arg : typeArguments_) {
799         auto *const newArg = arg->Substitute(relation, substitution);
800         newTypeArgs.push_back(newArg);
801         anyChange = anyChange || (newArg != arg);
802     }
803 
804     return anyChange;
805 }
806 
SetCopiedTypeProperties(TypeRelation * const relation,ETSObjectType * const copiedType,ArenaVector<Type * > & newTypeArgs,const Substitution * const substitution)807 void ETSObjectType::SetCopiedTypeProperties(TypeRelation *const relation, ETSObjectType *const copiedType,
808                                             ArenaVector<Type *> &newTypeArgs, const Substitution *const substitution)
809 {
810     copiedType->typeFlags_ = typeFlags_;
811     copiedType->RemoveObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS |
812                                  ETSObjectFlags::INCOMPLETE_INSTANTIATION | ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
813     copiedType->SetVariable(variable_);
814     copiedType->SetBaseType(this);
815 
816     copiedType->SetTypeArguments(std::move(newTypeArgs));
817     copiedType->relation_ = relation;
818     copiedType->substitution_ = substitution;
819 }
820 
Substitute(TypeRelation * relation,const Substitution * substitution)821 Type *ETSObjectType::Substitute(TypeRelation *relation, const Substitution *substitution)
822 {
823     if (substitution == nullptr || substitution->empty()) {
824         return this;
825     }
826 
827     auto *const checker = relation->GetChecker()->AsETSChecker();
828     auto *base = GetOriginalBaseType();
829 
830     ArenaVector<Type *> newTypeArgs {checker->Allocator()->Adapter()};
831     const bool anyChange = SubstituteTypeArgs(relation, newTypeArgs, substitution);
832     // Lambda types can capture type params in their bodies, normal classes cannot.
833     // NOTE: gogabr. determine precise conditions where we do not need to copy.
834     // Perhaps keep track of captured type parameters for each type.
835     if (!anyChange && !HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
836         return this;
837     }
838 
839     const util::StringView hash = checker->GetHashFromSubstitution(substitution);
840     if (auto *inst = GetInstantiatedType(hash); inst != nullptr) {
841         return inst;
842     }
843 
844     if (!relation->TypeInstantiationPossible(base) || IsETSNullLike()) {
845         return this;
846     }
847     relation->IncreaseTypeRecursionCount(base);
848 
849     auto *const copiedType = checker->CreateNewETSObjectType(name_, declNode_, flags_);
850     SetCopiedTypeProperties(relation, copiedType, newTypeArgs, substitution);
851     GetInstantiationMap().try_emplace(hash, copiedType);
852 
853     if (superType_ != nullptr) {
854         copiedType->SetSuperType(superType_->Substitute(relation, substitution)->AsETSObjectType());
855     }
856     for (auto *itf : interfaces_) {
857         auto *newItf = itf->Substitute(relation, substitution)->AsETSObjectType();
858         copiedType->AddInterface(newItf);
859     }
860 
861     relation->DecreaseTypeRecursionCount(base);
862 
863     return copiedType;
864 }
865 
InstantiateProperties() const866 void ETSObjectType::InstantiateProperties() const
867 {
868     if (baseType_ == nullptr || baseType_ == this) {
869         return;
870     }
871     ASSERT(!propertiesInstantiated_);
872     ASSERT(relation_ != nullptr);
873 
874     for (auto *const it : baseType_->ConstructSignatures()) {
875         auto *newSig = it->Substitute(relation_, substitution_);
876         constructSignatures_.push_back(newSig);
877     }
878 
879     for (auto const &[_, prop] : baseType_->InstanceFields()) {
880         (void)_;
881         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, substitution_);
882         properties_[static_cast<size_t>(PropertyType::INSTANCE_FIELD)].emplace(prop->Name(), copiedProp);
883     }
884 
885     for (auto const &[_, prop] : baseType_->StaticFields()) {
886         (void)_;
887         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, substitution_);
888         properties_[static_cast<size_t>(PropertyType::STATIC_FIELD)].emplace(prop->Name(), copiedProp);
889     }
890 
891     for (auto const &[_, prop] : baseType_->InstanceMethods()) {
892         (void)_;
893         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, substitution_);
894         properties_[static_cast<size_t>(PropertyType::INSTANCE_METHOD)].emplace(prop->Name(), copiedProp);
895     }
896 
897     for (auto const &[_, prop] : baseType_->StaticMethods()) {
898         (void)_;
899         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, substitution_);
900         properties_[static_cast<size_t>(PropertyType::STATIC_METHOD)].emplace(prop->Name(), copiedProp);
901     }
902 
903     for (auto const &[_, prop] : baseType_->InstanceDecls()) {
904         (void)_;
905         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, substitution_);
906         properties_[static_cast<size_t>(PropertyType::INSTANCE_DECL)].emplace(prop->Name(), copiedProp);
907     }
908 
909     for (auto const &[_, prop] : baseType_->StaticDecls()) {
910         (void)_;
911         auto *copiedProp = CopyPropertyWithTypeArguments(prop, relation_, substitution_);
912         properties_[static_cast<size_t>(PropertyType::STATIC_DECL)].emplace(prop->Name(), copiedProp);
913     }
914 }
915 
DebugInfoTypeFromName(std::stringstream & ss,util::StringView asmName)916 void ETSObjectType::DebugInfoTypeFromName(std::stringstream &ss, util::StringView asmName)
917 {
918     ss << compiler::Signatures::CLASS_REF_BEGIN;
919     auto copied = asmName.Mutf8();
920     std::replace(copied.begin(), copied.end(), *compiler::Signatures::METHOD_SEPARATOR.begin(),
921                  *compiler::Signatures::NAMESPACE_SEPARATOR.begin());
922     ss << copied;
923     ss << compiler::Signatures::MANGLE_SEPARATOR;
924 }
925 
926 }  // namespace panda::es2panda::checker
927