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