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