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