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 "boxingConverter.h"
17 #include "checker/ETSchecker.h"
18 #include "checker/ets/typeRelationContext.h"
19 #include "checker/types/ets/etsDynamicType.h"
20 #include "checker/types/ets/etsObjectType.h"
21 #include "checker/types/ets/etsTupleType.h"
22 #include "ir/astNode.h"
23 #include "ir/typeNode.h"
24 #include "ir/base/classDefinition.h"
25 #include "ir/base/classElement.h"
26 #include "ir/base/classProperty.h"
27 #include "ir/base/classStaticBlock.h"
28 #include "ir/base/methodDefinition.h"
29 #include "ir/base/scriptFunction.h"
30 #include "ir/ets/etsNewClassInstanceExpression.h"
31 #include "ir/ets/etsTypeReference.h"
32 #include "ir/ets/etsTypeReferencePart.h"
33 #include "ir/ets/etsUnionType.h"
34 #include "ir/expressions/assignmentExpression.h"
35 #include "ir/expressions/callExpression.h"
36 #include "ir/expressions/functionExpression.h"
37 #include "ir/expressions/identifier.h"
38 #include "ir/expressions/memberExpression.h"
39 #include "ir/statements/blockStatement.h"
40 #include "ir/statements/expressionStatement.h"
41 #include "ir/statements/variableDeclarator.h"
42 #include "ir/ts/tsClassImplements.h"
43 #include "ir/ts/tsInterfaceDeclaration.h"
44 #include "ir/ts/tsInterfaceHeritage.h"
45 #include "ir/ts/tsTypeParameter.h"
46 #include "ir/ts/tsTypeParameterDeclaration.h"
47 #include "varbinder/declaration.h"
48 #include "varbinder/variableFlags.h"
49 #include "generated/signatures.h"
50 
51 namespace ark::es2panda::checker {
GetSuperType(ETSObjectType *type)52 ETSObjectType *ETSChecker::GetSuperType(ETSObjectType *type)
53 {
54     ComputeSuperType(type);
55     if (type == GlobalETSObjectType()) {
56         return GlobalETSObjectType();
57     }
58     if (type->SuperType() == nullptr) {
59         return nullptr;
60     }
61     return type->SuperType();
62 }
63 
ComputeSuperType(ETSObjectType *type)64 bool ETSChecker::ComputeSuperType(ETSObjectType *type)
65 {
66     if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) {
67         return true;
68     }
69 
70     ASSERT(type->Variable() && type->GetDeclNode()->IsClassDefinition());
71     auto *classDef = type->GetDeclNode()->AsClassDefinition();
72 
73     if (classDef->Super() == nullptr) {
74         type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER);
75         if (type != GlobalETSObjectType()) {
76             type->SetSuperType(GlobalETSObjectType());
77         }
78         return true;
79     }
80 
81     TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, classDef->Ident()->Start());
82     if (tse.HasTypeError()) {
83         type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER);
84         return false;
85     }
86 
87     Type *superType = classDef->Super()->AsTypeNode()->GetType(this);
88     if (superType == nullptr) {
89         return true;
90     }
91     if (!superType->IsETSObjectType() || !superType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) {
92         LogTypeError({"The super type of '", classDef->Ident()->Name(), "' class is not extensible."},
93                      classDef->Super()->Start());
94         type->SetSuperType(GlobalETSObjectType());
95         return true;
96     }
97 
98     ETSObjectType *superObj = superType->AsETSObjectType();
99 
100     // struct node has class definition, too
101     if (superObj->GetDeclNode()->Parent()->IsETSStructDeclaration()) {
102         LogTypeError({"struct ", classDef->Ident()->Name(), " is not extensible."}, classDef->Super()->Start());
103     }
104 
105     if (superObj->GetDeclNode()->IsFinal()) {
106         LogTypeError("Cannot inherit with 'final' modifier.", classDef->Super()->Start());
107         /* It still makes sense to treat superObj as the supertype in future checking */
108     }
109     if (GetSuperType(superObj) == nullptr) {
110         superObj = GlobalETSObjectType();
111     }
112     type->SetSuperType(superObj);
113     type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER);
114     return true;
115 }
116 
ValidateImplementedInterface(ETSObjectType *type, Type *interface, std::unordered_set<Type *> *extendsSet, const lexer::SourcePosition &pos)117 void ETSChecker::ValidateImplementedInterface(ETSObjectType *type, Type *interface,
118                                               std::unordered_set<Type *> *extendsSet, const lexer::SourcePosition &pos)
119 {
120     if (!interface->IsETSObjectType() || !interface->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
121         LogTypeError("Interface expected here.", pos);
122         return;
123     }
124 
125     if (!extendsSet->insert(interface).second) {
126         LogTypeError("Repeated interface.", pos);
127     }
128 
129     type->AddInterface(interface->AsETSObjectType());
130     GetInterfaces(interface->AsETSObjectType());
131 }
132 
GetInterfacesOfClass(ETSObjectType *type)133 void ETSChecker::GetInterfacesOfClass(ETSObjectType *type)
134 {
135     if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES)) {
136         return;
137     }
138 
139     const auto *declNode = type->GetDeclNode()->AsClassDefinition();
140 
141     std::unordered_set<Type *> extendsSet;
142     for (auto *it : declNode->Implements()) {
143         ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start());
144     }
145     type->AddObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES);
146 }
147 
GetInterfacesOfInterface(ETSObjectType *type)148 void ETSChecker::GetInterfacesOfInterface(ETSObjectType *type)
149 {
150     if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES)) {
151         return;
152     }
153 
154     const auto *declNode = type->GetDeclNode()->AsTSInterfaceDeclaration();
155 
156     TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, declNode->Id()->Start());
157     if (tse.HasTypeError()) {
158         type->Interfaces().clear();
159         return;
160     }
161 
162     std::unordered_set<Type *> extendsSet;
163     for (auto *it : declNode->Extends()) {
164         ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start());
165     }
166     type->AddObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES);
167 }
168 
GetInterfaces(ETSObjectType *type)169 ArenaVector<ETSObjectType *> ETSChecker::GetInterfaces(ETSObjectType *type)
170 {
171     ASSERT(type->GetDeclNode()->IsClassDefinition() || type->GetDeclNode()->IsTSInterfaceDeclaration());
172 
173     if (type->GetDeclNode()->IsClassDefinition()) {
174         GetInterfacesOfClass(type);
175     } else {
176         GetInterfacesOfInterface(type);
177     }
178 
179     return type->Interfaces();
180 }
181 
CreateUnconstrainedTypeParameters( ir::TSTypeParameterDeclaration const *typeParams)182 std::pair<ArenaVector<Type *>, bool> ETSChecker::CreateUnconstrainedTypeParameters(
183     ir::TSTypeParameterDeclaration const *typeParams)
184 {
185     bool ok = true;
186     ArenaVector<Type *> result {Allocator()->Adapter()};
187     checker::ScopeContext scopeCtx(this, typeParams->Scope());
188 
189     // Note: we have to run pure check loop first to avoid endless loop because of possible circular dependencies
190     Type2TypeMap extends {};
191     TypeSet typeParameterDecls {};
192     for (auto *const typeParam : typeParams->Params()) {
193         ok &= CheckDefaultTypeParameter(typeParam, typeParameterDecls);
194         if (auto *const constraint = typeParam->Constraint();
195             constraint != nullptr && constraint->IsETSTypeReference() &&
196             constraint->AsETSTypeReference()->Part()->Name()->IsIdentifier()) {
197             ok &= CheckTypeParameterConstraint(typeParam, extends);
198         }
199     }
200 
201     for (auto *const typeParam : typeParams->Params()) {
202         result.emplace_back(SetUpParameterType(typeParam));
203     }
204 
205     return {result, ok};
206 }
207 
AssignTypeParameterConstraints(ir::TSTypeParameterDeclaration const *typeParams)208 void ETSChecker::AssignTypeParameterConstraints(ir::TSTypeParameterDeclaration const *typeParams)
209 {
210     ConstraintCheckScope ctScope(this);
211     // The type parameter might be used in the constraint, like 'K extend Comparable<K>',
212     // so we need to create their type first, then set up the constraint
213     for (auto *const param : typeParams->Params()) {
214         SetUpTypeParameterConstraint(param);
215     }
216     ctScope.TryCheckConstraints();
217 }
218 
CheckDefaultTypeParameter(const ir::TSTypeParameter *param, TypeSet &typeParameterDecls)219 bool ETSChecker::CheckDefaultTypeParameter(const ir::TSTypeParameter *param, TypeSet &typeParameterDecls)
220 {
221     bool ok = true;
222     const auto typeParamVar = param->Name()->Variable();
223     if (typeParameterDecls.count(typeParamVar) != 0U) {
224         LogTypeError({"Duplicate type parameter '", param->Name()->Name().Utf8(), "'."}, param->Start());
225         return false;
226     }
227 
228     std::function<void(ir::AstNode *)> checkDefault = [&typeParameterDecls, this, &checkDefault,
229                                                        &ok](ir::AstNode *node) {
230         if (node->IsETSTypeReferencePart()) {
231             ir::ETSTypeReferencePart *defaultTypePart = node->AsETSTypeReferencePart();
232             if (defaultTypePart->Name()->Variable()->TsType() == nullptr &&
233                 (defaultTypePart->Name()->Variable()->Flags() & varbinder::VariableFlags::TYPE_PARAMETER) != 0U &&
234                 typeParameterDecls.count(defaultTypePart->Name()->Variable()) == 0U) {
235                 LogTypeError({"Type Parameter ", defaultTypePart->Name()->AsIdentifier()->Name().Utf8(),
236                               " should be defined before use."},
237                              node->Start());
238                 ok = false;
239             }
240         }
241         node->Iterate(checkDefault);
242     };
243 
244     if (param->DefaultType() != nullptr) {
245         param->DefaultType()->Iterate(checkDefault);
246     }
247 
248     typeParameterDecls.emplace(typeParamVar);
249     return ok;
250 }
251 
CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends)252 bool ETSChecker::CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends)
253 {
254     const auto typeParamVar = param->Name()->Variable();
255     const auto constraintVar = param->Constraint()->AsETSTypeReference()->Part()->Name()->Variable();
256     extends.emplace(typeParamVar, constraintVar);
257     auto it = extends.find(constraintVar);
258     while (it != extends.cend()) {
259         if (it->second == typeParamVar) {
260             LogTypeError({"Type parameter '", param->Name()->Name().Utf8(), "' has circular constraint dependency."},
261                          param->Constraint()->Start());
262             return false;
263         }
264         it = extends.find(it->second);
265     }
266 
267     return true;
268 }
269 
SetUpTypeParameterConstraint(ir::TSTypeParameter *const param)270 void ETSChecker::SetUpTypeParameterConstraint(ir::TSTypeParameter *const param)
271 {
272     ETSTypeParameter *const paramType = param->Name()->Variable()->TsType()->AsETSTypeParameter();
273     auto const traverseReferenced =
274         [this, scope = param->Parent()->AsTSTypeParameterDeclaration()->Scope()](ir::TypeNode *typeNode) {
275             if (!typeNode->IsETSTypeReference()) {
276                 return;
277             }
278             const auto typeName = typeNode->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name();
279             auto *const found = scope->FindLocal(typeName, varbinder::ResolveBindingOptions::BINDINGS);
280             if (found != nullptr) {
281                 SetUpTypeParameterConstraint(found->Declaration()->Node()->AsTSTypeParameter());
282             }
283         };
284 
285     if (param->Constraint() != nullptr) {
286         traverseReferenced(param->Constraint());
287         auto *const constraint = param->Constraint()->GetType(this);
288         // invalid: T extends int[]
289         if (!constraint->IsETSObjectType() && !constraint->IsETSTypeParameter() && !constraint->IsETSUnionType()) {
290             LogTypeError("Extends constraint must be an object", param->Constraint()->Start());
291         }
292         paramType->SetConstraintType(constraint);
293     } else {
294         paramType->SetConstraintType(GlobalETSNullishObjectType());
295     }
296 
297     if (param->DefaultType() != nullptr) {
298         traverseReferenced(param->DefaultType());
299         // NOTE: #14993 ensure default matches constraint
300         paramType->SetDefaultType(MaybePromotedBuiltinType(param->DefaultType()->GetType(this)));
301     }
302 }
303 
SetUpParameterType(ir::TSTypeParameter *const param)304 ETSTypeParameter *ETSChecker::SetUpParameterType(ir::TSTypeParameter *const param)
305 {
306     if (param->Name()->Variable() != nullptr && param->Name()->Variable()->TsType() != nullptr) {
307         ASSERT(param->Name()->Variable()->TsType()->IsETSTypeParameter());
308         return param->Name()->Variable()->TsType()->AsETSTypeParameter();
309     }
310 
311     auto *const paramType = CreateTypeParameter();
312 
313     paramType->AddTypeFlag(TypeFlag::GENERIC);
314     paramType->SetDeclNode(param);
315     paramType->SetVariable(param->Variable());
316     // NOTE: #15026 recursive type parameter workaround
317     paramType->SetConstraintType(GlobalETSNullishObjectType());
318 
319     param->Name()->Variable()->SetTsType(paramType);
320     return paramType;
321 }
322 
CreateTypeForClassOrInterfaceTypeParameters(ETSObjectType *type)323 void ETSChecker::CreateTypeForClassOrInterfaceTypeParameters(ETSObjectType *type)
324 {
325     if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS)) {
326         return;
327     }
328 
329     ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->IsClassDefinition()
330                                                      ? type->GetDeclNode()->AsClassDefinition()->TypeParams()
331                                                      : type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams();
332     auto [typeParamTypes, ok] = CreateUnconstrainedTypeParameters(typeParams);
333     type->SetTypeArguments(std::move(typeParamTypes));
334     if (ok) {
335         AssignTypeParameterConstraints(typeParams);
336     }
337     type->AddObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS);
338     type->AddObjectFlag(ETSObjectFlags::INCOMPLETE_INSTANTIATION);
339 }
340 
BuildBasicInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl)341 ETSObjectType *ETSChecker::BuildBasicInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl)
342 {
343     auto *var = interfaceDecl->Id()->Variable();
344     ASSERT(var);
345 
346     checker::ETSObjectType *interfaceType {};
347     if (var->TsType() == nullptr) {
348         interfaceType = CreateETSObjectType(var->Name(), interfaceDecl, checker::ETSObjectFlags::INTERFACE);
349         interfaceType->SetVariable(var);
350         var->SetTsType(interfaceType);
351     } else {
352         interfaceType = var->TsType()->AsETSObjectType();
353     }
354 
355     ConstraintCheckScope ctScope(this);
356     if (interfaceDecl->TypeParams() != nullptr) {
357         interfaceType->AddTypeFlag(TypeFlag::GENERIC);
358         CreateTypeForClassOrInterfaceTypeParameters(interfaceType);
359     }
360 
361     GetInterfaces(interfaceType);
362     interfaceType->SetSuperType(GlobalETSObjectType());
363     ctScope.TryCheckConstraints();
364     return interfaceType;
365 }
366 
BuildBasicClassProperties(ir::ClassDefinition *classDef)367 ETSObjectType *ETSChecker::BuildBasicClassProperties(ir::ClassDefinition *classDef)
368 {
369     if (classDef->IsFinal() && classDef->IsAbstract()) {
370         LogTypeError("Cannot use both 'final' and 'abstract' modifiers.", classDef->Start());
371     }
372 
373     auto *var = classDef->Ident()->Variable();
374     ASSERT(var);
375 
376     const util::StringView &className = classDef->Ident()->Name();
377 
378     checker::ETSObjectType *classType {};
379     if (var->TsType() == nullptr) {
380         classType = CreateETSObjectType(className, classDef, checker::ETSObjectFlags::CLASS);
381         classType->SetVariable(var);
382         var->SetTsType(classType);
383         if (classDef->IsAbstract()) {
384             classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT);
385         }
386     } else {
387         classType = var->TsType()->AsETSObjectType();
388     }
389 
390     classDef->SetTsType(classType);
391 
392     ConstraintCheckScope ctScope(this);
393     if (classDef->TypeParams() != nullptr) {
394         classType->AddTypeFlag(TypeFlag::GENERIC);
395         CreateTypeForClassOrInterfaceTypeParameters(classType);
396     }
397 
398     auto *enclosingClass = Context().ContainingClass();
399     classType->SetEnclosingType(enclosingClass);
400     CheckerStatus newStatus = CheckerStatus::IN_CLASS;
401 
402     if (classDef->IsInner()) {
403         newStatus |= CheckerStatus::INNER_CLASS;
404         classType->AddObjectFlag(checker::ETSObjectFlags::INNER);
405     }
406 
407     auto savedContext = checker::SavedCheckerContext(this, newStatus, classType);
408 
409     if (!classType->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) {
410         GetSuperType(classType);
411         GetInterfaces(classType);
412     }
413     ctScope.TryCheckConstraints();
414     return classType;
415 }
416 
BuildAnonymousClassProperties(ir::ClassDefinition *classDef, ETSObjectType *superType)417 ETSObjectType *ETSChecker::BuildAnonymousClassProperties(ir::ClassDefinition *classDef, ETSObjectType *superType)
418 {
419     auto classType = CreateETSObjectType(classDef->Ident()->Name(), classDef, checker::ETSObjectFlags::CLASS);
420     classDef->SetTsType(classType);
421     classType->SetSuperType(superType);
422     classType->AddObjectFlag(checker::ETSObjectFlags::RESOLVED_SUPER);
423 
424     return classType;
425 }
426 
ResolveDeclaredFieldsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope)427 static void ResolveDeclaredFieldsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope)
428 {
429     for (auto &[_, it] : scope->InstanceFieldScope()->Bindings()) {
430         (void)_;
431         ASSERT(it->Declaration()->Node()->IsClassProperty());
432         auto *classProp = it->Declaration()->Node()->AsClassProperty();
433         it->AddFlag(checker->GetAccessFlagFromNode(classProp));
434         type->AddProperty<PropertyType::INSTANCE_FIELD>(it->AsLocalVariable());
435     }
436 
437     for (auto &[_, it] : scope->StaticFieldScope()->Bindings()) {
438         (void)_;
439         ASSERT(it->Declaration()->Node()->IsClassProperty());
440         auto *classProp = it->Declaration()->Node()->AsClassProperty();
441         it->AddFlag(checker->GetAccessFlagFromNode(classProp));
442         type->AddProperty<PropertyType::STATIC_FIELD>(it->AsLocalVariable());
443     }
444 }
445 
ResolveDeclaredMethodsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope)446 static void ResolveDeclaredMethodsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope)
447 {
448     for (auto &[_, it] : scope->InstanceMethodScope()->Bindings()) {
449         (void)_;
450         auto *method = it->Declaration()->Node()->AsMethodDefinition();
451         auto *function = method->Function();
452 
453         if (function->IsProxy()) {
454             continue;
455         }
456 
457         it->AddFlag(checker->GetAccessFlagFromNode(method));
458         auto *funcType = checker->BuildMethodSignature(method);
459         it->SetTsType(funcType);
460         funcType->SetVariable(it);
461         method->SetTsType(funcType);
462         type->AddProperty<PropertyType::INSTANCE_METHOD>(it->AsLocalVariable());
463     }
464 
465     for (auto &[_, it] : scope->StaticMethodScope()->Bindings()) {
466         (void)_;
467         if (!it->Declaration()->Node()->IsMethodDefinition()) {
468             continue;
469         }
470 
471         auto *method = it->Declaration()->Node()->AsMethodDefinition();
472         auto *function = method->Function();
473 
474         if (function->IsProxy()) {
475             continue;
476         }
477 
478         it->AddFlag(checker->GetAccessFlagFromNode(method));
479         auto *funcType = checker->BuildMethodSignature(method);
480         it->SetTsType(funcType);
481         funcType->SetVariable(it);
482         method->SetTsType(funcType);
483 
484         if (method->IsConstructor()) {
485             type->AddConstructSignature(funcType->CallSignatures());
486             continue;
487         }
488 
489         type->AddProperty<PropertyType::STATIC_METHOD>(it->AsLocalVariable());
490     }
491 }
492 
ResolveDeclaredDeclsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope)493 static void ResolveDeclaredDeclsOfObject(ETSChecker *checker, const ETSObjectType *type, varbinder::ClassScope *scope)
494 {
495     for (auto &[_, it] : scope->InstanceDeclScope()->Bindings()) {
496         (void)_;
497         it->AddFlag(checker->GetAccessFlagFromNode(it->Declaration()->Node()));
498         type->AddProperty<PropertyType::INSTANCE_DECL>(it->AsLocalVariable());
499     }
500 
501     for (auto &[_, it] : scope->StaticDeclScope()->Bindings()) {
502         (void)_;
503         it->AddFlag(checker->GetAccessFlagFromNode(it->Declaration()->Node()));
504         type->AddProperty<PropertyType::STATIC_DECL>(it->AsLocalVariable());
505     }
506 }
507 
ResolveDeclaredMembersOfObject(const ETSObjectType *type)508 void ETSChecker::ResolveDeclaredMembersOfObject(const ETSObjectType *type)
509 {
510     if (type->IsPropertiesInstantiated()) {
511         return;
512     }
513 
514     auto *declNode = type->GetDeclNode();
515 
516     if (declNode == nullptr || !(declNode->IsClassDefinition() || declNode->IsTSInterfaceDeclaration())) {
517         return;
518     }
519 
520     if (type->IsGeneric() && type != type->GetOriginalBaseType()) {
521         const auto *baseType = type->GetOriginalBaseType();
522         auto *baseDeclNode = baseType->GetDeclNode();
523         checker::CheckerStatus baseStatus = baseDeclNode->IsTSInterfaceDeclaration()
524                                                 ? checker::CheckerStatus::IN_INTERFACE
525                                                 : checker::CheckerStatus::IN_CLASS;
526         auto baseScope = baseDeclNode->IsTSInterfaceDeclaration() ? baseDeclNode->AsTSInterfaceDeclaration()->Scope()
527                                                                   : baseDeclNode->AsClassDefinition()->Scope();
528         auto savedContext = checker::SavedCheckerContext(this, baseStatus, baseType);
529         checker::ScopeContext scopeCtx(this, baseScope);
530         ResolveDeclaredMembersOfObject(baseType);
531         return;
532     }
533 
534     checker::CheckerStatus status =
535         declNode->IsTSInterfaceDeclaration() ? checker::CheckerStatus::IN_INTERFACE : checker::CheckerStatus::IN_CLASS;
536     auto *scope = declNode->IsTSInterfaceDeclaration() ? declNode->AsTSInterfaceDeclaration()->Scope()
537                                                        : declNode->AsClassDefinition()->Scope();
538     auto savedContext = checker::SavedCheckerContext(this, status, type);
539     checker::ScopeContext scopeCtx(this, scope);
540 
541     ResolveDeclaredFieldsOfObject(this, type, scope->AsClassScope());
542     ResolveDeclaredMethodsOfObject(this, type, scope->AsClassScope());
543     ResolveDeclaredDeclsOfObject(this, type, scope->AsClassScope());
544 }
545 
HasETSFunctionType(ir::TypeNode *typeAnnotation)546 bool ETSChecker::HasETSFunctionType(ir::TypeNode *typeAnnotation)
547 {
548     if (typeAnnotation->IsETSFunctionType()) {
549         return true;
550     }
551     std::unordered_set<ir::TypeNode *> childrenSet;
552 
553     if (!typeAnnotation->IsETSTypeReference()) {
554         return false;
555     }
556 
557     auto const addTypeAlias = [&childrenSet, &typeAnnotation](varbinder::Decl *typeDecl) {
558         typeAnnotation = typeDecl->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation();
559         if (!typeAnnotation->IsETSUnionType()) {
560             childrenSet.insert(typeAnnotation);
561             return;
562         }
563         for (auto *type : typeAnnotation->AsETSUnionType()->Types()) {
564             if (type->IsETSTypeReference()) {
565                 childrenSet.insert(type);
566             }
567         }
568     };
569 
570     auto *typeDecl = typeAnnotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Variable()->Declaration();
571     if (typeDecl != nullptr && typeDecl->IsTypeAliasDecl()) {
572         addTypeAlias(typeDecl);
573     }
574 
575     for (auto *child : childrenSet) {
576         if (HasETSFunctionType(child)) {
577             return true;
578         }
579     }
580     return false;
581 }
582 
CollectAbstractSignaturesFromObject(const ETSObjectType *objType)583 std::vector<Signature *> ETSChecker::CollectAbstractSignaturesFromObject(const ETSObjectType *objType)
584 {
585     std::vector<Signature *> abstracts;
586     for (const auto &prop : objType->Methods()) {
587         GetTypeOfVariable(prop);
588 
589         if (!prop->TsType()->IsETSFunctionType()) {
590             continue;
591         }
592 
593         for (auto *sig : prop->TsType()->AsETSFunctionType()->CallSignatures()) {
594             if (sig->HasSignatureFlag(SignatureFlags::ABSTRACT) && !sig->HasSignatureFlag(SignatureFlags::PRIVATE)) {
595                 abstracts.push_back(sig);
596             }
597         }
598     }
599 
600     return abstracts;
601 }
602 
CreateFunctionTypesFromAbstracts(const std::vector<Signature *> &abstracts, ArenaVector<ETSFunctionType *> *target)603 void ETSChecker::CreateFunctionTypesFromAbstracts(const std::vector<Signature *> &abstracts,
604                                                   ArenaVector<ETSFunctionType *> *target)
605 {
606     for (auto *it : abstracts) {
607         auto name = it->Function()->Id()->Name();
608         auto *found = FindFunctionInVectorGivenByName(name, *target);
609         if (found != nullptr) {
610             found->AddCallSignature(it);
611             continue;
612         }
613 
614         auto *created = CreateETSFunctionType(it);
615         target->push_back(created);
616     }
617 }
618 
ComputeAbstractsFromInterface(ETSObjectType *interfaceType)619 void ETSChecker::ComputeAbstractsFromInterface(ETSObjectType *interfaceType)
620 {
621     auto cached = cachedComputedAbstracts_.find(interfaceType);
622     if (cached != cachedComputedAbstracts_.end()) {
623         return;
624     }
625 
626     for (auto *it : interfaceType->Interfaces()) {
627         ComputeAbstractsFromInterface(it);
628     }
629 
630     ArenaVector<ETSFunctionType *> merged(Allocator()->Adapter());
631     CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(interfaceType), &merged);
632     std::unordered_set<ETSObjectType *> abstractInheritanceTarget;
633 
634     for (auto *interface : interfaceType->Interfaces()) {
635         auto found = cachedComputedAbstracts_.find(interface);
636         ASSERT(found != cachedComputedAbstracts_.end());
637 
638         if (!abstractInheritanceTarget.insert(found->first).second) {
639             continue;
640         }
641 
642         MergeComputedAbstracts(merged, found->second.first);
643 
644         for (auto *base : found->second.second) {
645             abstractInheritanceTarget.insert(base);
646         }
647     }
648 
649     cachedComputedAbstracts_.insert({interfaceType, {merged, abstractInheritanceTarget}});
650 }
651 
GetAbstractsForClass(ETSObjectType *classType)652 ArenaVector<ETSFunctionType *> &ETSChecker::GetAbstractsForClass(ETSObjectType *classType)
653 {
654     ArenaVector<ETSFunctionType *> merged(Allocator()->Adapter());
655     CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(classType), &merged);
656 
657     std::unordered_set<ETSObjectType *> abstractInheritanceTarget;
658     if (classType->SuperType() != nullptr) {
659         auto base = cachedComputedAbstracts_.find(classType->SuperType());
660         ASSERT(base != cachedComputedAbstracts_.end());
661         MergeComputedAbstracts(merged, base->second.first);
662 
663         abstractInheritanceTarget.insert(base->first);
664         for (auto *it : base->second.second) {
665             abstractInheritanceTarget.insert(it);
666         }
667     }
668 
669     for (auto *it : classType->Interfaces()) {
670         ComputeAbstractsFromInterface(it);
671         auto found = cachedComputedAbstracts_.find(it);
672         ASSERT(found != cachedComputedAbstracts_.end());
673 
674         if (!abstractInheritanceTarget.insert(found->first).second) {
675             continue;
676         }
677 
678         MergeComputedAbstracts(merged, found->second.first);
679 
680         for (auto *interface : found->second.second) {
681             abstractInheritanceTarget.insert(interface);
682         }
683     }
684 
685     return cachedComputedAbstracts_.insert({classType, {merged, abstractInheritanceTarget}}).first->second.first;
686 }
687 
DoObjectImplementInterface(const ETSObjectType *interfaceType, const ETSObjectType *target)688 static bool DoObjectImplementInterface(const ETSObjectType *interfaceType, const ETSObjectType *target)
689 {
690     return std::any_of(interfaceType->Interfaces().begin(), interfaceType->Interfaces().end(),
691                        [&target](auto *it) { return it == target || DoObjectImplementInterface(it, target); });
692 }
693 
CheckIfInterfaceCanBeFoundOnDifferentPaths(const ETSObjectType *classType, const ETSObjectType *interfaceType)694 static bool CheckIfInterfaceCanBeFoundOnDifferentPaths(const ETSObjectType *classType,
695                                                        const ETSObjectType *interfaceType)
696 {
697     return std::count_if(classType->Interfaces().begin(), classType->Interfaces().end(),
698                          [&interfaceType](auto *it) { return DoObjectImplementInterface(it, interfaceType); }) == 1;
699 }
700 
701 static void GetInterfacesOfClass(ETSObjectType *type, ArenaVector<ETSObjectType *> &interfaces)
702 {
703     for (auto &classInterface : type->Interfaces()) {
704         if (std::find(interfaces.begin(), interfaces.end(), classInterface) == interfaces.end()) {
705             interfaces.emplace_back(classInterface);
706             GetInterfacesOfClass(classInterface, interfaces);
707         }
708     }
709 }
710 
711 void ETSChecker::CheckIfOverrideIsValidInInterface(const ETSObjectType *classType, Signature *sig,
712                                                    ir::ScriptFunction *func)
713 {
714     if (AreOverrideEquivalent(func->Signature(), sig) && func->IsStatic() == sig->Function()->IsStatic()) {
715         if (CheckIfInterfaceCanBeFoundOnDifferentPaths(classType, func->Signature()->Owner()) &&
716             (Relation()->IsSupertypeOf(func->Signature()->Owner(), sig->Owner()) ||
717              Relation()->IsSupertypeOf(sig->Owner(), func->Signature()->Owner()))) {
718             return;
719         }
720 
721         LogTypeError({"Method '", sig->Function()->Id()->Name(), "' is declared in ", sig->Owner()->Name(), " and ",
722                       func->Signature()->Owner()->Name(), " interfaces."},
723                      classType->GetDeclNode()->Start());
724     }
725 }
726 
727 void ETSChecker::CheckFunctionRedeclarationInInterface(const ETSObjectType *classType,
728                                                        ArenaVector<Signature *> &similarSignatures,
729                                                        ir::ScriptFunction *func)
730 {
731     for (auto *const sig : similarSignatures) {
732         if (sig != func->Signature() && func->HasBody()) {
733             if (classType == sig->Owner()) {
734                 return;
735             }
736 
737             CheckIfOverrideIsValidInInterface(classType, sig, func);
738         }
739     }
740 
741     similarSignatures.push_back(func->Signature());
742 }
743 
744 void ETSChecker::CheckInterfaceFunctions(ETSObjectType *classType)
745 {
746     ArenaVector<ETSObjectType *> interfaces(Allocator()->Adapter());
747     ArenaVector<Signature *> similarSignatures(Allocator()->Adapter());
748     interfaces.emplace_back(classType);
749     checker::GetInterfacesOfClass(classType, interfaces);
750 
751     for (auto *const &interface : interfaces) {
752         for (auto *const &prop : interface->Methods()) {
753             if (auto *const func = prop->Declaration()->Node()->AsMethodDefinition()->Function();
754                 func->Body() != nullptr) {
755                 CheckFunctionRedeclarationInInterface(classType, similarSignatures, func);
756             }
757         }
758     }
759 }
760 
761 /// Traverse the interface inheritance tree and collects implemented methods
762 void ETSChecker::CollectImplementedMethodsFromInterfaces(ETSObjectType *classType,
763                                                          std::vector<Signature *> *implementedSignatures,
764                                                          const ArenaVector<ETSFunctionType *> &abstractsToBeImplemented)
765 {
766     std::vector<ETSObjectType *> collectedInterfaces;
767 
768     for (auto &classInterface : classType->Interfaces()) {
769         collectedInterfaces.emplace_back(classInterface);
770     }
771 
772     size_t index = 0;
773 
774     while (index < collectedInterfaces.size()) {
775         for (auto &it : abstractsToBeImplemented) {
776             for (const auto &prop : collectedInterfaces[index]->Methods()) {
777                 GetTypeOfVariable(prop);
778                 AddImplementedSignature(implementedSignatures, prop, it);
779             }
780         }
781 
782         for (auto &currentInterfaceChild : collectedInterfaces[index]->Interfaces()) {
783             collectedInterfaces.emplace_back(currentInterfaceChild);
784         }
785 
786         index++;
787     }
788 }
789 
790 void ETSChecker::ValidateAbstractSignature(ArenaVector<ETSFunctionType *>::iterator &it,
791                                            ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
792                                            const std::vector<Signature *> &implementedSignatures,
793                                            bool &functionOverridden, Accessor &isGetSetExternal)
794 {
795     for (auto abstractSignature = (*it)->CallSignatures().begin();
796          abstractSignature != (*it)->CallSignatures().end();) {
797         bool foundSignature = false;
798         isGetSetExternal.isGetter = (*abstractSignature)->HasSignatureFlag(SignatureFlags::GETTER);
799         isGetSetExternal.isSetter = (*abstractSignature)->HasSignatureFlag(SignatureFlags::SETTER);
800         isGetSetExternal.isExternal = (*abstractSignature)->Function()->IsExternal();
801         for (auto *const implemented : implementedSignatures) {
802             if (implemented->HasSignatureFlag(SignatureFlags::NEED_RETURN_TYPE)) {
803                 implemented->OwnerVar()->Declaration()->Node()->Check(this);
804             }
805             Signature *substImplemented = AdjustForTypeParameters(*abstractSignature, implemented);
806 
807             if (substImplemented == nullptr) {
808                 continue;
809             }
810 
811             if (!AreOverrideEquivalent(*abstractSignature, substImplemented) ||
812                 !IsReturnTypeSubstitutable(substImplemented, *abstractSignature)) {
813                 continue;
814             }
815 
816             if ((*it)->CallSignatures().size() > 1) {
817                 abstractSignature = (*it)->CallSignatures().erase(abstractSignature);
818                 foundSignature = true;
819             } else {
820                 it = abstractsToBeImplemented.erase(it);
821                 functionOverridden = true;
822             }
823 
824             break;
825         }
826 
827         if (functionOverridden) {
828             break;
829         }
830 
831         if (!foundSignature) {
832             ++abstractSignature;
833         }
834     }
835 }
836 
837 void ETSChecker::ValidateNonOverriddenFunction(ETSObjectType *classType, ArenaVector<ETSFunctionType *>::iterator &it,
838                                                ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
839                                                bool &functionOverridden, const Accessor &isGetSet)
840 {
841     auto superClassType = classType->SuperType();
842     while (!functionOverridden && superClassType != nullptr) {
843         for (auto *field : superClassType->Fields()) {
844             if (field->Name() == (*it)->Name()) {
845                 auto *newProp =
846                     field->Declaration()->Node()->Clone(Allocator(), classType->GetDeclNode())->AsClassProperty();
847                 newProp->AddModifier(ir::ModifierFlags::SUPER_OWNER);
848                 newProp->AddModifier(isGetSet.isGetter && isGetSet.isSetter ? ir::ModifierFlags::GETTER_SETTER
849                                      : isGetSet.isGetter                    ? ir::ModifierFlags::GETTER
850                                                                             : ir::ModifierFlags::SETTER);
851                 auto *newFieldDecl = Allocator()->New<varbinder::LetDecl>(newProp->Key()->AsIdentifier()->Name());
852                 newFieldDecl->BindNode(newProp);
853 
854                 auto newFieldVar = classType->GetDeclNode()
855                                        ->Scope()
856                                        ->AsClassScope()
857                                        ->InstanceFieldScope()
858                                        ->AddDecl(Allocator(), newFieldDecl, ScriptExtension::ETS)
859                                        ->AsLocalVariable();
860                 newFieldVar->AddFlag(varbinder::VariableFlags::PROPERTY);
861                 newFieldVar->AddFlag(varbinder::VariableFlags::PUBLIC);
862                 classType->AddProperty<PropertyType::INSTANCE_FIELD>(newFieldVar);
863                 it = abstractsToBeImplemented.erase(it);
864                 functionOverridden = true;
865                 break;
866             }
867         }
868 
869         superClassType = superClassType->SuperType();
870     }
871 }
872 
873 void ETSChecker::ApplyModifiersAndRemoveImplementedAbstracts(ArenaVector<ETSFunctionType *>::iterator &it,
874                                                              ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
875                                                              ETSObjectType *classType, bool &functionOverridden,
876                                                              const Accessor &isGetSetExternal)
877 {
878     for (auto *field : classType->Fields()) {
879         if (field->Name() == (*it)->Name()) {
880             field->Declaration()->Node()->AddModifier(isGetSetExternal.isGetter && isGetSetExternal.isSetter
881                                                           ? ir::ModifierFlags::GETTER_SETTER
882                                                       : isGetSetExternal.isGetter ? ir::ModifierFlags::GETTER
883                                                                                   : ir::ModifierFlags::SETTER);
884             it = abstractsToBeImplemented.erase(it);
885             functionOverridden = true;
886             break;
887         }
888     }
889 }
890 
891 void ETSChecker::ValidateAbstractMethodsToBeImplemented(ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
892                                                         ETSObjectType *classType,
893                                                         const std::vector<Signature *> &implementedSignatures)
894 {
895     SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK);
896     for (auto it = abstractsToBeImplemented.begin(); it != abstractsToBeImplemented.end();) {
897         bool functionOverridden = false;
898         Accessor isGetSetExternal;
899 
900         ValidateAbstractSignature(it, abstractsToBeImplemented, implementedSignatures, functionOverridden,
901                                   isGetSetExternal);
902 
903         if (functionOverridden) {
904             continue;
905         }
906 
907         if (!isGetSetExternal.isGetter && !isGetSetExternal.isSetter) {
908             it++;
909             continue;
910         }
911 
912         ApplyModifiersAndRemoveImplementedAbstracts(it, abstractsToBeImplemented, classType, functionOverridden,
913                                                     isGetSetExternal);
914 
915         if (functionOverridden) {
916             continue;
917         }
918 
919         ValidateNonOverriddenFunction(classType, it, abstractsToBeImplemented, functionOverridden, isGetSetExternal);
920 
921         if (!functionOverridden) {
922             it++;
923         }
924     }
925 }
926 
927 void ETSChecker::MaybeReportErrorsForOverridingValidation(ArenaVector<ETSFunctionType *> &abstractsToBeImplemented,
928                                                           ETSObjectType *classType, const lexer::SourcePosition &pos,
929                                                           bool reportError)
930 {
931     if (!abstractsToBeImplemented.empty() && reportError) {
932         auto unimplementedSignature = abstractsToBeImplemented.front()->CallSignatures().front();
933         auto containingObjectName = GetContainingObjectNameFromSignature(unimplementedSignature);
934         if (unimplementedSignature->HasSignatureFlag(SignatureFlags::GETTER)) {
935             LogTypeError({classType->Name(), " is not abstract and does not implement getter for ",
936                           unimplementedSignature->Function()->Id()->Name(), " property in ", containingObjectName},
937                          pos);
938             return;
939         }
940         if (unimplementedSignature->HasSignatureFlag(SignatureFlags::SETTER)) {
941             LogTypeError({classType->Name(), " is not abstract and does not implement setter for ",
942                           unimplementedSignature->Function()->Id()->Name(), " property in ", containingObjectName},
943                          pos);
944             return;
945         }
946         LogTypeError({classType->Name(), " is not abstract and does not override abstract method ",
947                       unimplementedSignature->Function()->Id()->Name(), unimplementedSignature, " in ",
948                       containingObjectName},
949                      pos);
950     }
951 }
952 
953 void ETSChecker::ValidateOverriding(ETSObjectType *classType, const lexer::SourcePosition &pos)
954 {
955     if (classType->HasObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS)) {
956         return;
957     }
958 
959     bool throwError = true;
960     if (classType->HasObjectFlag(ETSObjectFlags::ABSTRACT)) {
961         throwError = false;
962     }
963 
964     if (classType->SuperType() != nullptr) {
965         ValidateOverriding(classType->SuperType(), classType->SuperType()->GetDeclNode()->Start());
966     }
967 
968     auto &abstractsToBeImplemented = GetAbstractsForClass(classType);
969     std::vector<Signature *> implementedSignatures;
970 
971     // Since interfaces can define function bodies we have to collect the implemented ones first
972     CollectImplementedMethodsFromInterfaces(classType, &implementedSignatures, abstractsToBeImplemented);
973     CheckInterfaceFunctions(classType);
974 
975     auto *superIter = classType;
976     do {
977         for (auto &it : abstractsToBeImplemented) {
978             for (const auto &prop : superIter->Methods()) {
979                 GetTypeOfVariable(prop);
980                 AddImplementedSignature(&implementedSignatures, prop, it);
981             }
982         }
983         superIter = superIter->SuperType();
984     } while (superIter != nullptr);
985     ValidateAbstractMethodsToBeImplemented(abstractsToBeImplemented, classType, implementedSignatures);
986     MaybeReportErrorsForOverridingValidation(abstractsToBeImplemented, classType, pos, throwError);
987 
988     classType->AddObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS);
989 }
990 
991 void ETSChecker::AddImplementedSignature(std::vector<Signature *> *implementedSignatures,
992                                          varbinder::LocalVariable *function, ETSFunctionType *it)
993 {
994     if (!function->TsType()->IsETSFunctionType()) {
995         return;
996     }
997 
998     for (auto signature : function->TsType()->AsETSFunctionType()->CallSignatures()) {
999         if (signature->Function()->IsAbstract() || signature->Function()->IsStatic()) {
1000             continue;
1001         }
1002 
1003         if (signature->Function()->Id()->Name() == it->Name()) {
1004             implementedSignatures->emplace_back(signature);
1005         }
1006     }
1007 }
1008 
1009 void ETSChecker::CheckLocalClass(ir::ClassDefinition *classDef, CheckerStatus &checkerStatus)
1010 {
1011     if (classDef->IsLocal()) {
1012         checkerStatus |= CheckerStatus::IN_LOCAL_CLASS;
1013         if (!classDef->Parent()->Parent()->IsBlockStatement()) {
1014             LogTypeError("Local classes must be defined between balanced braces", classDef->Start());
1015         }
1016     }
1017 }
1018 
1019 void ETSChecker::CheckClassDefinition(ir::ClassDefinition *classDef)
1020 {
1021     classDef->SetClassDefinitionChecked();
1022     auto *classType = classDef->TsTypeOrError()->AsETSObjectType();
1023     if (classType->SuperType() != nullptr) {
1024         classType->SuperType()->GetDeclNode()->Check(this);
1025     }
1026 
1027     auto newStatus = checker::CheckerStatus::IN_CLASS;
1028     if (Context().ContainingClass() != classType) {
1029         classType->SetEnclosingType(Context().ContainingClass());
1030     }
1031 
1032     if (classDef->IsInner()) {
1033         newStatus |= CheckerStatus::INNER_CLASS;
1034         classType->AddObjectFlag(checker::ETSObjectFlags::INNER);
1035     }
1036 
1037     classDef->IsGlobal() ? classType->AddObjectFlag(checker::ETSObjectFlags::GLOBAL)
1038                          : CheckLocalClass(classDef, newStatus);
1039 
1040     checker::ScopeContext scopeCtx(this, classDef->Scope());
1041     auto savedContext = SavedCheckerContext(this, newStatus, classType);
1042 
1043     ResolveDeclaredMembersOfObject(classType);
1044 
1045     if (classDef->IsAbstract()) {
1046         AddStatus(checker::CheckerStatus::IN_ABSTRACT);
1047         classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT);
1048     }
1049 
1050     if (classDef->IsStatic() && !Context().ContainingClass()->HasObjectFlag(ETSObjectFlags::GLOBAL)) {
1051         AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT);
1052     }
1053 
1054     // NOTE(gogabr): temporary, until we have proper bridges, see #16485
1055     // Don't check overriding for synthetic functional classes.
1056     if ((static_cast<ir::AstNode *>(classDef)->Modifiers() & ir::ModifierFlags::FUNCTIONAL) == 0) {
1057         ValidateOverriding(classType, classDef->Start());
1058     }
1059     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1060     TransformProperties(classType);
1061 
1062     for (auto *it : classDef->Body()) {
1063         if (it->IsClassProperty()) {
1064             it->Check(this);
1065         }
1066     }
1067 
1068     for (auto *it : classDef->Body()) {
1069         if (!it->IsClassProperty()) {
1070             it->Check(this);
1071         }
1072     }
1073 
1074     if (classDef->IsGlobal() || classType->SuperType() == nullptr) {
1075         return;
1076     }
1077 
1078     CheckConstructors(classDef, classType);
1079     CheckValidInheritance(classType, classDef);
1080     CheckConstFields(classType);
1081     CheckGetterSetterProperties(classType);
1082     CheckInvokeMethodsLegitimacy(classType);
1083 }
1084 
1085 void ETSChecker::CheckConstructors(ir::ClassDefinition *classDef, ETSObjectType *classType)
1086 {
1087     if (!classDef->IsDeclare()) {
1088         for (auto *it : classType->ConstructSignatures()) {
1089             CheckCyclicConstructorCall(it);
1090             CheckImplicitSuper(classType, it);
1091             CheckThisOrSuperCallInConstructor(classType, it);
1092         }
1093     }
1094 }
1095 
1096 bool IsAsyncMethod(ir::AstNode *node)
1097 {
1098     if (!node->IsMethodDefinition()) {
1099         return false;
1100     }
1101     auto *method = node->AsMethodDefinition();
1102     return method->Function()->IsAsyncFunc() && !method->Function()->IsProxy();
1103 }
1104 
1105 void ETSChecker::CreateAsyncProxyMethods(ir::ClassDefinition *classDef)
1106 {
1107     ArenaVector<ir::MethodDefinition *> asyncImpls(Allocator()->Adapter());
1108 
1109     for (auto *it : classDef->Body()) {
1110         if (!IsAsyncMethod(it)) {
1111             continue;
1112         }
1113 
1114         auto *asyncMethod = it->AsMethodDefinition();
1115         auto *proxy = CreateAsyncProxy(asyncMethod, classDef);
1116         asyncImpls.push_back(proxy);
1117 
1118         for (auto *overload : asyncMethod->Overloads()) {
1119             if (!IsAsyncMethod(overload)) {
1120                 continue;
1121             }
1122 
1123             auto *impl = CreateAsyncProxy(overload, classDef, false);
1124             impl->Function()->Id()->SetVariable(proxy->Function()->Id()->Variable());
1125             proxy->AddOverload(impl);
1126         }
1127     }
1128 
1129     for (auto *it : asyncImpls) {
1130         it->SetParent(classDef);
1131         it->Check(this);
1132         classDef->Body().push_back(it);
1133     }
1134 }
1135 
1136 void ETSChecker::CheckImplicitSuper(ETSObjectType *classType, Signature *ctorSig)
1137 {
1138     if (classType == GlobalETSObjectType()) {
1139         return;
1140     }
1141 
1142     auto &stmts = ctorSig->Function()->Body()->AsBlockStatement()->Statements();
1143     const auto thisCall = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
1144         return stmt->IsExpressionStatement() && stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1145                stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression();
1146     });
1147     // There is an alternate constructor invocation, no need for super constructor invocation
1148     if (thisCall != stmts.end()) {
1149         return;
1150     }
1151 
1152     const auto superExpr = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
1153         return stmt->IsExpressionStatement() && stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1154                stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsSuperExpression();
1155     });
1156     // There is no super expression
1157     if (superExpr == stmts.end()) {
1158         const auto superTypeCtorSigs = classType->SuperType()->ConstructSignatures();
1159         const auto superTypeCtorSig = std::find_if(superTypeCtorSigs.begin(), superTypeCtorSigs.end(),
1160                                                    [](const Signature *sig) { return sig->Params().empty(); });
1161         // Super type has no parameterless ctor
1162         if (superTypeCtorSig == superTypeCtorSigs.end()) {
1163             LogTypeError("Must call super constructor", ctorSig->Function()->Start());
1164         }
1165 
1166         ctorSig->Function()->AddFlag(ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED);
1167     }
1168 }
1169 
1170 void ETSChecker::CheckThisOrSuperCallInConstructor(ETSObjectType *classType, Signature *ctorSig)
1171 {
1172     if (classType == GlobalETSObjectType()) {
1173         return;
1174     }
1175 
1176     for (auto it : ctorSig->Function()->Body()->AsBlockStatement()->Statements()) {
1177         if (it->IsExpressionStatement() && it->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1178             (it->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression() ||
1179              it->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsSuperExpression())) {
1180             ArenaVector<const ir::Expression *> expressions =
1181                 ArenaVector<const ir::Expression *>(Allocator()->Adapter());
1182             expressions.insert(expressions.end(),
1183                                it->AsExpressionStatement()->GetExpression()->AsCallExpression()->Arguments().begin(),
1184                                it->AsExpressionStatement()->GetExpression()->AsCallExpression()->Arguments().end());
1185             CheckExpressionsInConstructor(expressions);
1186         }
1187     }
1188 }
1189 
1190 void ETSChecker::CheckExpressionsInConstructor(const ArenaVector<const ir::Expression *> &arguments)
1191 {
1192     for (auto *arg : arguments) {
1193         auto expressions = CheckMemberOrCallOrObjectExpressionInConstructor(arg);
1194 
1195         if (arg->IsETSNewClassInstanceExpression()) {
1196             expressions.insert(expressions.end(), arg->AsETSNewClassInstanceExpression()->GetArguments().begin(),
1197                                arg->AsETSNewClassInstanceExpression()->GetArguments().end());
1198         } else if (arg->IsArrayExpression()) {
1199             expressions.insert(expressions.end(), arg->AsArrayExpression()->Elements().begin(),
1200                                arg->AsArrayExpression()->Elements().end());
1201         } else if (arg->IsBinaryExpression()) {
1202             expressions.push_back(arg->AsBinaryExpression()->Left());
1203             expressions.push_back(arg->AsBinaryExpression()->Right());
1204         } else if (arg->IsAssignmentExpression()) {
1205             expressions.push_back(arg->AsAssignmentExpression()->Left());
1206             expressions.push_back(arg->AsAssignmentExpression()->Right());
1207         } else if (arg->IsTSAsExpression()) {
1208             expressions.push_back(arg->AsTSAsExpression()->Expr());
1209         } else if (arg->IsConditionalExpression()) {
1210             expressions.push_back(arg->AsConditionalExpression()->Test());
1211             expressions.push_back(arg->AsConditionalExpression()->Consequent());
1212             expressions.push_back(arg->AsConditionalExpression()->Alternate());
1213         } else if (arg->IsTypeofExpression()) {
1214             expressions.push_back(arg->AsTypeofExpression()->Argument());
1215         } else if (arg->IsTSNonNullExpression()) {
1216             expressions.push_back(arg->AsTSNonNullExpression()->Expr());
1217         } else if (arg->IsUnaryExpression()) {
1218             expressions.push_back(arg->AsUnaryExpression()->Argument());
1219         } else if (arg->IsUpdateExpression()) {
1220             expressions.push_back(arg->AsUpdateExpression()->Argument());
1221         }
1222 
1223         if (!expressions.empty()) {
1224             CheckExpressionsInConstructor(expressions);
1225         }
1226     }
1227 }
1228 
1229 ArenaVector<const ir::Expression *> ETSChecker::CheckMemberOrCallOrObjectExpressionInConstructor(
1230     const ir::Expression *arg)
1231 {
1232     ArenaVector<const ir::Expression *> expressions = ArenaVector<const ir::Expression *>(Allocator()->Adapter());
1233 
1234     if (arg->IsMemberExpression()) {
1235         if ((arg->AsMemberExpression()->Object()->IsSuperExpression() ||
1236              arg->AsMemberExpression()->Object()->IsThisExpression())) {
1237             std::stringstream ss;
1238             ss << "Using " << (arg->AsMemberExpression()->Object()->IsSuperExpression() ? "super" : "this")
1239                << " is not allowed in constructor";
1240             LogTypeError(ss.str(), arg->Start());
1241         }
1242 
1243         expressions.push_back(arg->AsMemberExpression()->Property());
1244         expressions.push_back(arg->AsMemberExpression()->Object());
1245     } else if (arg->IsCallExpression()) {
1246         expressions.insert(expressions.end(), arg->AsCallExpression()->Arguments().begin(),
1247                            arg->AsCallExpression()->Arguments().end());
1248 
1249         if (arg->AsCallExpression()->Callee()->IsMemberExpression() &&
1250             (arg->AsCallExpression()->Callee()->AsMemberExpression()->Object()->IsSuperExpression() ||
1251              arg->AsCallExpression()->Callee()->AsMemberExpression()->Object()->IsThisExpression()) &&
1252             !arg->AsCallExpression()->Callee()->AsMemberExpression()->Property()->IsStatic()) {
1253             std::stringstream ss;
1254             ss << "Using "
1255                << (arg->AsCallExpression()->Callee()->AsMemberExpression()->IsSuperExpression() ? "super" : "this")
1256                << " is not allowed in constructor";
1257             LogTypeError(ss.str(), arg->Start());
1258         }
1259     } else if (arg->IsObjectExpression()) {
1260         for (auto *prop : arg->AsObjectExpression()->Properties()) {
1261             expressions.push_back(prop->AsProperty()->Value());
1262         }
1263     }
1264 
1265     return expressions;
1266 }
1267 
1268 void ETSChecker::CheckConstFields(const ETSObjectType *classType)
1269 {
1270     for (const auto &prop : classType->Fields()) {
1271         if (!(prop->Declaration()->IsConstDecl() || prop->Declaration()->IsReadonlyDecl()) ||
1272             !prop->HasFlag(varbinder::VariableFlags::EXPLICIT_INIT_REQUIRED)) {
1273             continue;
1274         }
1275         CheckConstFieldInitialized(classType, prop);
1276     }
1277 }
1278 
1279 void ETSChecker::CheckConstFieldInitialized(const ETSObjectType *classType, varbinder::LocalVariable *classVar)
1280 {
1281     const bool classVarStatic = classVar->Declaration()->Node()->AsClassProperty()->IsStatic();
1282     for (const auto &prop : classType->Methods()) {
1283         if (!prop->TsType()->IsETSFunctionType()) {
1284             continue;
1285         }
1286 
1287         const auto &callSigs = prop->TsType()->AsETSFunctionType()->CallSignatures();
1288         for (const auto *signature : callSigs) {
1289             if ((signature->Function()->IsConstructor() && !classVarStatic) ||
1290                 (signature->Function()->IsStaticBlock() && classVarStatic)) {
1291                 CheckConstFieldInitialized(signature, classVar);
1292             }
1293         }
1294     }
1295 }
1296 
1297 void ETSChecker::FindAssignment(const ir::AstNode *node, const varbinder::LocalVariable *classVar, bool &initialized)
1298 {
1299     if (node->IsAssignmentExpression() && node->AsAssignmentExpression()->Target() == classVar) {
1300         if (initialized) {
1301             LogTypeError({"Variable '", classVar->Declaration()->Name(), "' might already have been initialized"},
1302                          node->Start());
1303         }
1304 
1305         initialized = true;
1306         return;
1307     }
1308 
1309     FindAssignments(node, classVar, initialized);
1310 }
1311 
1312 void ETSChecker::FindAssignments(const ir::AstNode *node, const varbinder::LocalVariable *classVar, bool &initialized)
1313 {
1314     node->Iterate(
1315         [this, classVar, &initialized](ir::AstNode *childNode) { FindAssignment(childNode, classVar, initialized); });
1316 }
1317 
1318 void ETSChecker::CheckConstFieldInitialized(const Signature *signature, varbinder::LocalVariable *classVar)
1319 {
1320     bool initialized = false;
1321     const auto &stmts = signature->Function()->Body()->AsBlockStatement()->Statements();
1322     const auto it = stmts.begin();
1323     if (it != stmts.end()) {
1324         if (const auto *first = *it;
1325             first->IsExpressionStatement() && first->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1326             first->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression()) {
1327             initialized = true;
1328         }
1329     }
1330 
1331     // NOTE: szd. control flow
1332     FindAssignments(signature->Function()->Body(), classVar, initialized);
1333     if (!initialized) {
1334         LogTypeError({"Variable '", classVar->Declaration()->Name(), "' might not have been initialized"},
1335                      signature->Function()->End());
1336     }
1337 
1338     classVar->RemoveFlag(varbinder::VariableFlags::EXPLICIT_INIT_REQUIRED);
1339 }
1340 
1341 void ETSChecker::CheckInnerClassMembers(const ETSObjectType *classType)
1342 {
1343     for (const auto &[_, it] : classType->StaticMethods()) {
1344         (void)_;
1345         LogTypeError("Inner class cannot have static methods", it->Declaration()->Node()->Start());
1346     }
1347 
1348     for (const auto &[_, it] : classType->StaticFields()) {
1349         (void)_;
1350         if (!it->Declaration()->IsReadonlyDecl()) {
1351             LogTypeError("Inner class cannot have non-readonly static properties", it->Declaration()->Node()->Start());
1352         }
1353     }
1354 }
1355 
1356 bool ETSChecker::ValidateArrayIndex(ir::Expression *const expr, bool relaxed)
1357 {
1358     auto *const expressionType = expr->Check(this);
1359     auto const *const unboxedExpressionType = ETSBuiltinTypeAsPrimitiveType(expressionType);
1360 
1361     Type const *const indexType = ApplyUnaryOperatorPromotion(expressionType);
1362 
1363     if (expressionType->IsETSObjectType() && (unboxedExpressionType != nullptr)) {
1364         expr->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxedExpressionType));
1365     }
1366 
1367     if (relaxed && indexType != nullptr && indexType->HasTypeFlag(TypeFlag::ETS_FLOATING_POINT)) {
1368         if (!expr->IsNumberLiteral()) {
1369             return true;
1370         }
1371 
1372         auto num = expr->AsNumberLiteral()->Number();
1373         ASSERT(num.IsReal());
1374         double value = num.GetDouble();
1375         double intpart;
1376         if (std::modf(value, &intpart) != 0.0) {
1377             LogTypeError("Index fractional part should be zero.", expr->Start());
1378             return false;
1379         }
1380         return true;
1381     }
1382 
1383     if (indexType == nullptr || !indexType->HasTypeFlag(TypeFlag::ETS_ARRAY_INDEX)) {
1384         std::stringstream message("");
1385         if (expressionType->IsNonPrimitiveType()) {
1386             message << expressionType->Variable()->Name();
1387         } else {
1388             expressionType->ToString(message);
1389         }
1390 
1391         LogTypeError(
1392             "Type '" + message.str() +
1393                 "' cannot be used as an index type. Only primitive or unboxable integral types can be used as index.",
1394             expr->Start());
1395         return false;
1396     }
1397 
1398     return true;
1399 }
1400 
1401 std::optional<int32_t> ETSChecker::GetTupleElementAccessValue(const Type *const type, const lexer::SourcePosition &pos)
1402 {
1403     ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC));
1404 
1405     switch (ETSType(type)) {
1406         case TypeFlag::BYTE: {
1407             return type->AsByteType()->GetValue();
1408         }
1409         case TypeFlag::SHORT: {
1410             return type->AsShortType()->GetValue();
1411         }
1412         case TypeFlag::INT: {
1413             return type->AsIntType()->GetValue();
1414         }
1415         case TypeFlag::LONG: {
1416             if (auto val = type->AsLongType()->GetValue();
1417                 val <= std::numeric_limits<int32_t>::max() && val >= std::numeric_limits<int32_t>::min()) {
1418                 return static_cast<int32_t>(val);
1419             }
1420 
1421             LogTypeError("Element accessor value is out of tuple size bounds.", pos);
1422             return std::nullopt;
1423         }
1424         default: {
1425             UNREACHABLE();
1426         }
1427     }
1428 }
1429 
1430 bool ETSChecker::ValidateTupleIndex(const ETSTupleType *const tuple, ir::MemberExpression *const expr)
1431 {
1432     auto *const expressionType = expr->Property()->Check(this);
1433     auto const *const unboxedExpressionType = ETSBuiltinTypeAsPrimitiveType(expressionType);
1434 
1435     if (expressionType->IsETSObjectType() && (unboxedExpressionType != nullptr)) {
1436         expr->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxedExpressionType));
1437     }
1438 
1439     const auto *const exprType = expr->Property()->TsType();
1440     ASSERT(exprType != nullptr);
1441 
1442     if (!exprType->HasTypeFlag(TypeFlag::CONSTANT) && !tuple->HasSpreadType()) {
1443         LogTypeError("Only constant expression allowed for element access on tuples.", expr->Property()->Start());
1444         return false;
1445     }
1446 
1447     if (!exprType->HasTypeFlag(TypeFlag::ETS_ARRAY_INDEX | TypeFlag::LONG)) {
1448         LogTypeError("Only integer type allowed for element access on tuples.", expr->Property()->Start());
1449         return false;
1450     }
1451 
1452     auto exprValue = GetTupleElementAccessValue(exprType, expr->Property()->Start());
1453     if (!exprValue.has_value()) {
1454         return false;  // spread the error
1455     }
1456     if (((*exprValue >= tuple->GetTupleSize()) && !tuple->HasSpreadType()) || (*exprValue < 0)) {
1457         LogTypeError("Element accessor value is out of tuple size bounds.", expr->Property()->Start());
1458         return false;
1459     }
1460 
1461     return true;
1462 }
1463 
1464 ETSObjectType *ETSChecker::CheckThisOrSuperAccess(ir::Expression *node, ETSObjectType *classType, std::string_view msg)
1465 {
1466     if ((Context().Status() & CheckerStatus::IGNORE_VISIBILITY) != 0U) {
1467         return classType;
1468     }
1469 
1470     if (node->Parent()->IsCallExpression() && (node->Parent()->AsCallExpression()->Callee() == node)) {
1471         if (Context().ContainingSignature() == nullptr) {
1472             LogTypeError({"Call to '", msg, "' must be first statement in constructor"}, node->Start());
1473             return classType;
1474         }
1475 
1476         auto *sig = Context().ContainingSignature();
1477         ASSERT(sig->Function()->Body() && sig->Function()->Body()->IsBlockStatement());
1478 
1479         if (!sig->HasSignatureFlag(checker::SignatureFlags::CONSTRUCT)) {
1480             LogTypeError({"Call to '", msg, "' must be first statement in constructor"}, node->Start());
1481             return classType;
1482         }
1483 
1484         if (sig->Function()->Body()->AsBlockStatement()->Statements().front() != node->Parent()->Parent()) {
1485             LogTypeError({"Call to '", msg, "' must be first statement in constructor"}, node->Start());
1486             return classType;
1487         }
1488     }
1489 
1490     if (HasStatus(checker::CheckerStatus::IN_STATIC_CONTEXT)) {
1491         LogTypeError({"'", msg, "' cannot be referenced from a static context"}, node->Start());
1492         return classType;
1493     }
1494 
1495     if (classType->GetDeclNode()->IsClassDefinition() && classType->GetDeclNode()->AsClassDefinition()->IsGlobal()) {
1496         LogTypeError({"Cannot reference '", msg, "' in this context."}, node->Start());
1497         return classType;
1498     }
1499 
1500     return classType;
1501 }
1502 
1503 void ETSChecker::CheckCyclicConstructorCall(Signature *signature)
1504 {
1505     ASSERT(signature->Function());
1506 
1507     if (signature->Function()->Body() == nullptr || signature->Function()->IsExternal()) {
1508         return;
1509     }
1510 
1511     auto *funcBody = signature->Function()->Body()->AsBlockStatement();
1512 
1513     TypeStackElement tse(this, signature, "Recursive constructor invocation", signature->Function()->Start());
1514     if (tse.HasTypeError()) {
1515         return;
1516     }
1517 
1518     if (!funcBody->Statements().empty() && funcBody->Statements()[0]->IsExpressionStatement() &&
1519         funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1520         funcBody->Statements()[0]
1521             ->AsExpressionStatement()
1522             ->GetExpression()
1523             ->AsCallExpression()
1524             ->Callee()
1525             ->IsThisExpression()) {
1526         auto *constructorCall = funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->AsCallExpression();
1527         ASSERT(constructorCall->Signature());
1528         CheckCyclicConstructorCall(constructorCall->Signature());
1529     }
1530 }
1531 
1532 ETSObjectType *ETSChecker::CheckExceptionOrErrorType(checker::Type *type, const lexer::SourcePosition pos)
1533 {
1534     if (!type->IsETSObjectType() || (!Relation()->IsAssignableTo(type, GlobalBuiltinExceptionType()) &&
1535                                      !Relation()->IsAssignableTo(type, GlobalBuiltinErrorType()))) {
1536         LogTypeError({"Argument must be an instance of '", compiler::Signatures::BUILTIN_EXCEPTION_CLASS, "' or '",
1537                       compiler::Signatures::BUILTIN_ERROR_CLASS, "'"},
1538                      pos);
1539         return GlobalETSObjectType();
1540     }
1541 
1542     return type->AsETSObjectType();
1543 }
1544 
1545 Type *ETSChecker::TryToInstantiate(Type *const type, ArenaAllocator *const allocator, TypeRelation *const relation,
1546                                    GlobalTypesHolder *const globalTypes)
1547 {
1548     // NOTE: Handle generic functions
1549     auto *returnType = type;
1550     const bool isIncomplete =
1551         type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INCOMPLETE_INSTANTIATION);
1552     if (const bool isFunctionType = type->IsETSFunctionType(); isFunctionType || isIncomplete) {
1553         returnType = type->Instantiate(allocator, relation, globalTypes);
1554     }
1555 
1556     return returnType;
1557 }
1558 
1559 void ETSChecker::ValidateResolvedProperty(varbinder::LocalVariable **property, const ETSObjectType *const target,
1560                                           const ir::Identifier *const ident, const PropertySearchFlags flags)
1561 {
1562     if (*property != nullptr) {
1563         return;
1564     }
1565 
1566     using Utype = std::underlying_type_t<PropertySearchFlags>;
1567     static constexpr uint32_t CORRECT_PROPERTY_SEARCH_ORDER_INSTANCE = 7U;
1568     static_assert(static_cast<Utype>(PropertySearchFlags::SEARCH_INSTANCE) == CORRECT_PROPERTY_SEARCH_ORDER_INSTANCE,
1569                   "PropertySearchFlags order changed");
1570     static constexpr uint32_t CORRECT_PROPERTY_SEARCH_ORDER_STATIC = 56U;
1571     static_assert(static_cast<Utype>(PropertySearchFlags::SEARCH_STATIC) == CORRECT_PROPERTY_SEARCH_ORDER_STATIC,
1572                   "PropertySearchFlags order changed");
1573     const auto flagsNum = static_cast<Utype>(flags);
1574     // This algorithm swaps the first 3 bits of a number with it's consecutive 3 bits, example: 0b110001 -> 0b001110
1575     // Effectively it changes PropertySearchFlags to search for the appropriate declarations
1576     const Utype x = (flagsNum ^ (flagsNum >> 3U)) & 7U;
1577     const auto newFlags = PropertySearchFlags {flagsNum ^ (x | (x << 3U))};
1578 
1579     auto *const newProp = target->GetProperty(ident->Name(), newFlags);
1580     if (newProp == nullptr) {
1581         LogTypeError({"Property '", ident->Name(), "' does not exist on type '", target->Name(), "'"}, ident->Start());
1582         return;
1583     }
1584 
1585     *property = newProp;  // trying to recover as much as possible; log the error but treat the property as legal
1586 
1587     if (IsVariableStatic(newProp)) {
1588         LogTypeError({"'", ident->Name(), "' is a static property of '", target->Name(), "'"}, ident->Start());
1589         return;
1590     }
1591 
1592     LogTypeError({"'", ident->Name(), "' is an instance property of '", target->Name(), "'"}, ident->Start());
1593 }
1594 
1595 varbinder::Variable *ETSChecker::ResolveInstanceExtension(const ir::MemberExpression *const memberExpr)
1596 {
1597     // clang-format off
1598     auto *globalFunctionVar = Scope()
1599                                 ->FindInGlobal(memberExpr->Property()->AsIdentifier()->Name(),
1600                                                 varbinder::ResolveBindingOptions::STATIC_METHODS)
1601                                 .variable;
1602     // clang-format on
1603 
1604     if (globalFunctionVar == nullptr || !ExtensionETSFunctionType(this->GetTypeOfVariable(globalFunctionVar))) {
1605         return nullptr;
1606     }
1607 
1608     return globalFunctionVar;
1609 }
1610 
1611 PropertySearchFlags ETSChecker::GetInitialSearchFlags(const ir::MemberExpression *const memberExpr)
1612 {
1613     constexpr auto FUNCTIONAL_FLAGS =
1614         PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_FUNCTIONAL | PropertySearchFlags::SEARCH_FIELD;
1615     constexpr auto GETTER_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_GETTER;
1616     constexpr auto SETTER_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_SETTER;
1617 
1618     switch (memberExpr->Parent()->Type()) {
1619         case ir::AstNodeType::CALL_EXPRESSION: {
1620             if (memberExpr->Parent()->AsCallExpression()->Callee() == memberExpr) {
1621                 return FUNCTIONAL_FLAGS;
1622             }
1623 
1624             break;
1625         }
1626         case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
1627             if (memberExpr->Parent()->AsETSNewClassInstanceExpression()->GetTypeRef() == memberExpr) {
1628                 return PropertySearchFlags::SEARCH_DECL;
1629             }
1630             break;
1631         }
1632         case ir::AstNodeType::MEMBER_EXPRESSION: {
1633             return PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL | GETTER_FLAGS;
1634         }
1635         case ir::AstNodeType::UPDATE_EXPRESSION:
1636         case ir::AstNodeType::UNARY_EXPRESSION:
1637         case ir::AstNodeType::BINARY_EXPRESSION: {
1638             return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS;
1639         }
1640         case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
1641             const auto *const assignmentExpr = memberExpr->Parent()->AsAssignmentExpression();
1642 
1643             if (assignmentExpr->Left() == memberExpr) {
1644                 if (assignmentExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
1645                     return PropertySearchFlags::SEARCH_FIELD | SETTER_FLAGS;
1646                 }
1647                 return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS | SETTER_FLAGS;
1648             }
1649 
1650             auto const *targetType = assignmentExpr->Left()->TsTypeOrError();
1651             if (targetType->IsETSObjectType() &&
1652                 targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
1653                 return FUNCTIONAL_FLAGS;
1654             }
1655 
1656             return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS;
1657         }
1658         default: {
1659             break;
1660         }
1661     }
1662 
1663     return PropertySearchFlags::SEARCH_FIELD | FUNCTIONAL_FLAGS | GETTER_FLAGS;
1664 }
1665 
1666 PropertySearchFlags ETSChecker::GetSearchFlags(const ir::MemberExpression *const memberExpr,
1667                                                const varbinder::Variable *targetRef)
1668 {
1669     auto searchFlag = GetInitialSearchFlags(memberExpr);
1670     searchFlag |= PropertySearchFlags::SEARCH_IN_BASE | PropertySearchFlags::SEARCH_IN_INTERFACES;
1671     if (targetRef != nullptr &&
1672         (targetRef->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE) ||
1673          (targetRef->HasFlag(varbinder::VariableFlags::TYPE_ALIAS) &&
1674           targetRef->TsType()->Variable()->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE)))) {
1675         searchFlag &= ~PropertySearchFlags::SEARCH_INSTANCE;
1676     } else if (memberExpr->Object()->IsThisExpression() ||
1677                (targetRef != nullptr && targetRef->Declaration() != nullptr &&
1678                 targetRef->Declaration()->IsLetOrConstDecl()) ||
1679                (memberExpr->Object()->IsIdentifier() && memberExpr->ObjType()->GetDeclNode() != nullptr &&
1680                 memberExpr->ObjType()->GetDeclNode()->IsTSInterfaceDeclaration())) {
1681         searchFlag &= ~PropertySearchFlags::SEARCH_STATIC;
1682     }
1683     return searchFlag;
1684 }
1685 
1686 const varbinder::Variable *ETSChecker::GetTargetRef(const ir::MemberExpression *const memberExpr)
1687 {
1688     if (memberExpr->Object()->IsIdentifier()) {
1689         return memberExpr->Object()->AsIdentifier()->Variable();
1690     }
1691     if (memberExpr->Object()->IsMemberExpression()) {
1692         return memberExpr->Object()->AsMemberExpression()->PropVar();
1693     }
1694     return nullptr;
1695 }
1696 
1697 void ETSChecker::ValidateReadonlyProperty(const ir::MemberExpression *const memberExpr, const ETSFunctionType *propType,
1698                                           const lexer::SourcePosition sourcePos)
1699 {
1700     ir::ClassProperty *classProp = nullptr;
1701     ETSObjectType *currentObj = memberExpr->ObjType();
1702     bool foundInThis = false;
1703     while (classProp == nullptr && currentObj != nullptr) {
1704         classProp = FindClassProperty(currentObj, propType);
1705         if (classProp != nullptr && currentObj == memberExpr->ObjType()) {
1706             foundInThis = true;
1707         }
1708 
1709         currentObj = currentObj->SuperType();
1710     }
1711 
1712     if (classProp != nullptr && this->Context().ContainingSignature() != nullptr && classProp->IsReadonly()) {
1713         if (!foundInThis || (!this->Context().ContainingSignature()->Function()->IsConstructor())) {
1714             LogTypeError("Cannot assign to this property because it is readonly.", sourcePos);
1715             return;
1716         }
1717 
1718         if (IsInitializedProperty(memberExpr->ObjType()->GetDeclNode()->AsClassDefinition(), classProp)) {
1719             LogTypeError("Readonly field already initialized at declaration.", sourcePos);
1720         }
1721     }
1722 }
1723 
1724 void ETSChecker::ValidateGetterSetter(const ir::MemberExpression *const memberExpr,
1725                                       const varbinder::LocalVariable *const prop, PropertySearchFlags searchFlag)
1726 {
1727     auto *propType = prop->TsType()->AsETSFunctionType();
1728     ASSERT((propType->FindGetter() != nullptr) == propType->HasTypeFlag(TypeFlag::GETTER));
1729     ASSERT((propType->FindSetter() != nullptr) == propType->HasTypeFlag(TypeFlag::SETTER));
1730 
1731     auto const &sourcePos = memberExpr->Property()->Start();
1732     auto callExpr = memberExpr->Parent()->IsCallExpression() ? memberExpr->Parent()->AsCallExpression() : nullptr;
1733 
1734     if ((searchFlag & PropertySearchFlags::IS_GETTER) != 0) {
1735         if (!propType->HasTypeFlag(TypeFlag::GETTER)) {
1736             LogTypeError("Cannot read from this property because it is writeonly.", sourcePos);
1737             return;
1738         }
1739         ValidateSignatureAccessibility(memberExpr->ObjType(), callExpr, propType->FindGetter(), sourcePos);
1740     }
1741 
1742     if ((searchFlag & PropertySearchFlags::IS_SETTER) != 0) {
1743         ValidateReadonlyProperty(memberExpr, propType, sourcePos);
1744         ValidateSignatureAccessibility(memberExpr->ObjType(), callExpr, propType->FindSetter(), sourcePos);
1745     }
1746 }
1747 
1748 ir::ClassProperty *ETSChecker::FindClassProperty(const ETSObjectType *const objectType, const ETSFunctionType *propType)
1749 {
1750     auto propName =
1751         util::UString(std::string(compiler::Signatures::PROPERTY) + propType->Name().Mutf8(), Allocator()).View();
1752 
1753     ir::ClassProperty *classProp = nullptr;
1754     if (objectType->GetDeclNode()->IsClassDefinition()) {
1755         auto body = objectType->GetDeclNode()->AsClassDefinition()->Body();
1756         auto foundValue = std::find_if(body.begin(), body.end(), [propName](ir::AstNode *node) {
1757             return node->IsClassProperty() && node->AsClassProperty()->Key()->AsIdentifier()->Name() == propName;
1758         });
1759         if (foundValue != body.end()) {
1760             classProp = (*foundValue)->AsClassProperty();
1761         }
1762     }
1763 
1764     return classProp;
1765 }
1766 
1767 bool ETSChecker::IsInitializedProperty(const ir::ClassDefinition *classDefinition, const ir::ClassProperty *prop)
1768 {
1769     std::string targetName = prop->Key()->AsIdentifier()->Name().Mutf8();
1770     if (targetName.find(compiler::Signatures::PROPERTY) == 0) {
1771         targetName = targetName.substr(compiler::Signatures::PROPERTY.size());
1772     }
1773 
1774     for (auto *it : classDefinition->Body()) {
1775         if (it->IsClassProperty() && it->AsClassProperty()->Value() != nullptr) {
1776             return FindPropertyInAssignment(it, targetName);
1777         }
1778     }
1779 
1780     return false;
1781 }
1782 
1783 bool ETSChecker::FindPropertyInAssignment(const ir::AstNode *it, const std::string &targetName)
1784 {
1785     return it->AsClassProperty()->Value()->FindChild([&targetName](ir::AstNode *node) {
1786         return node->IsIdentifier() && node->AsIdentifier()->Name().Is(targetName) && node->Parent() != nullptr &&
1787                node->Parent()->IsMemberExpression();
1788     }) != nullptr;
1789 }
1790 
1791 void ETSChecker::ValidateVarDeclaratorOrClassProperty(const ir::MemberExpression *const memberExpr,
1792                                                       varbinder::LocalVariable *const prop)
1793 {
1794     const auto [target_ident,
1795                 type_annotation] = [memberExpr]() -> std::pair<const ir::Identifier *, const ir::TypeNode *> {
1796         if (memberExpr->Parent()->IsVariableDeclarator()) {
1797             const auto *const ident = memberExpr->Parent()->AsVariableDeclarator()->Id()->AsIdentifier();
1798             return {ident, ident->TypeAnnotation()};
1799         }
1800         return {memberExpr->Parent()->AsClassProperty()->Key()->AsIdentifier(),
1801                 memberExpr->Parent()->AsClassProperty()->TypeAnnotation()};
1802     }();
1803 
1804     GetTypeOfVariable(prop);
1805 
1806     if (prop->TsType()->IsETSFunctionType() && !IsVariableGetterSetter(prop)) {
1807         if (type_annotation == nullptr) {
1808             LogTypeError({"Cannot infer type for ", target_ident->Name(),
1809                           " because method reference needs an explicit target type"},
1810                          target_ident->Start());
1811             return;
1812         }
1813 
1814         auto *targetType = GetTypeOfVariable(target_ident->Variable());
1815         ASSERT(targetType != nullptr);
1816 
1817         if (!targetType->IsETSObjectType() ||
1818             !targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
1819             LogTypeError({"Method ", memberExpr->Property()->AsIdentifier()->Name(), " does not exist on this type."},
1820                          memberExpr->Property()->Start());
1821         }
1822     }
1823 }
1824 
1825 // NOLINTNEXTLINE(readability-function-size)
1826 std::vector<ResolveResult *> ETSChecker::ResolveMemberReference(const ir::MemberExpression *const memberExpr,
1827                                                                 const ETSObjectType *const target)
1828 {
1829     std::vector<ResolveResult *> resolveRes {};
1830 
1831     if (target->IsETSDynamicType() && !target->AsETSDynamicType()->HasDecl()) {
1832         auto propName = memberExpr->Property()->AsIdentifier()->Name();
1833         varbinder::LocalVariable *propVar = target->AsETSDynamicType()->GetPropertyDynamic(propName, this);
1834         resolveRes.emplace_back(Allocator()->New<ResolveResult>(propVar, ResolvedKind::PROPERTY));
1835         return resolveRes;
1836     }
1837 
1838     varbinder::Variable *globalFunctionVar = nullptr;
1839 
1840     if (memberExpr->Parent()->IsCallExpression() && memberExpr->Parent()->AsCallExpression()->Callee() == memberExpr) {
1841         globalFunctionVar = ResolveInstanceExtension(memberExpr);
1842     } else if (target->GetDeclNode() != nullptr && target->GetDeclNode()->IsClassDefinition() &&
1843                !target->GetDeclNode()->AsClassDefinition()->IsClassDefinitionChecked()) {
1844         this->CheckClassDefinition(target->GetDeclNode()->AsClassDefinition());
1845     }
1846     const auto *const targetRef = GetTargetRef(memberExpr);
1847     auto searchFlag = GetSearchFlags(memberExpr, targetRef);
1848     if (target->HasTypeFlag(TypeFlag::GENERIC) && (searchFlag & PropertySearchFlags::SEARCH_STATIC) != 0) {
1849         searchFlag |= PropertySearchFlags::SEARCH_ALL;
1850     }
1851 
1852     auto searchName = target->GetReExportAliasValue(memberExpr->Property()->AsIdentifier()->Name());
1853     auto *prop = target->GetProperty(searchName, searchFlag);
1854 
1855     if (memberExpr->Parent()->IsCallExpression() && memberExpr->Parent()->AsCallExpression()->Callee() == memberExpr) {
1856         globalFunctionVar = ResolveInstanceExtension(memberExpr);
1857     }
1858 
1859     if (globalFunctionVar == nullptr ||
1860         (targetRef != nullptr && targetRef->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE))) {
1861         /*
1862             Instance extension function can only be called by class instance, if a property is accessed by
1863             CLASS or INTERFACE type, it couldn't be an instance extension function call
1864 
1865             Example code:
1866                 class A {}
1867                 static function A.xxx() {}
1868                 function main() {
1869                     A.xxx()
1870                 }
1871 
1872             !NB: When supporting static extension function, the above code case would be supported
1873         */
1874         ValidateResolvedProperty(&prop, target, memberExpr->Property()->AsIdentifier(), searchFlag);
1875         if (prop == nullptr) {
1876             return resolveRes;
1877         }
1878     } else {
1879         resolveRes.emplace_back(
1880             Allocator()->New<ResolveResult>(globalFunctionVar, ResolvedKind::INSTANCE_EXTENSION_FUNCTION));
1881 
1882         if (prop == nullptr) {
1883             // No matched property, but have possible matched global extension function
1884             return resolveRes;
1885         }
1886     }
1887 
1888     resolveRes.emplace_back(Allocator()->New<ResolveResult>(prop, ResolvedKind::PROPERTY));
1889 
1890     ResolveMemberReferenceValidate(prop, searchFlag, memberExpr);
1891 
1892     return resolveRes;
1893 }
1894 
1895 void ETSChecker::ResolveMemberReferenceValidate(varbinder::LocalVariable *const prop,
1896                                                 PropertySearchFlags const searchFlag,
1897                                                 const ir::MemberExpression *const memberExpr)
1898 {
1899     if (prop->HasFlag(varbinder::VariableFlags::METHOD) && !IsVariableGetterSetter(prop) &&
1900         (searchFlag & PropertySearchFlags::IS_FUNCTIONAL) == 0) {
1901         LogTypeError("Method used in wrong context", memberExpr->Property()->Start());
1902         return;
1903     }
1904 
1905     if (IsVariableGetterSetter(prop)) {
1906         ValidateGetterSetter(memberExpr, prop, searchFlag);
1907     }
1908 
1909     // Before returning the computed property variable, we have to validate the special case where we are in a variable
1910     // declaration, and the properties type is a function type but the currently declared variable doesn't have a type
1911     // annotation
1912     if (memberExpr->Parent()->IsVariableDeclarator() || memberExpr->Parent()->IsClassProperty()) {
1913         ValidateVarDeclaratorOrClassProperty(memberExpr, prop);
1914     }
1915 }
1916 
1917 void ETSChecker::CheckValidInheritance(ETSObjectType *classType, ir::ClassDefinition *classDef)
1918 {
1919     if (classType->SuperType() == nullptr) {
1920         return;
1921     }
1922 
1923     if (classDef->TypeParams() != nullptr &&
1924         (Relation()->IsAssignableTo(classType->SuperType(), GlobalBuiltinExceptionType()) ||
1925          Relation()->IsAssignableTo(classType->SuperType(), GlobalBuiltinErrorType()))) {
1926         LogTypeError({"Generics are not allowed as '", compiler::Signatures::BUILTIN_EXCEPTION_CLASS, "' or '",
1927                       compiler::Signatures::BUILTIN_ERROR_CLASS, "' subclasses."},
1928                      classDef->TypeParams()->Start());
1929     }
1930 
1931     const auto &allProps = classType->GetAllProperties();
1932 
1933     for (auto *it : allProps) {
1934         const auto searchFlag = PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE |
1935                                 PropertySearchFlags::SEARCH_IN_INTERFACES |
1936                                 PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION;
1937         auto *foundInSuper = classType->SuperType()->GetProperty(it->Name(), searchFlag);
1938 
1939         ETSObjectType *interfaceFound = nullptr;
1940         if (foundInSuper != nullptr) {
1941             CheckProperties(classType, classDef, it, foundInSuper, interfaceFound);
1942         }
1943 
1944         auto interfaceList = GetInterfaces(classType);
1945         varbinder::LocalVariable *foundInInterface = nullptr;
1946         for (auto *interface : interfaceList) {
1947             auto *propertyFound = interface->GetProperty(it->Name(), searchFlag);
1948             if (propertyFound == nullptr) {
1949                 continue;
1950             }
1951             foundInInterface = propertyFound;
1952             interfaceFound = interface;
1953             break;
1954         }
1955         if (foundInInterface == nullptr) {
1956             continue;
1957         }
1958 
1959         CheckProperties(classType, classDef, it, foundInInterface, interfaceFound);
1960     }
1961 }
1962 
1963 void ETSChecker::CheckProperties(ETSObjectType *classType, ir::ClassDefinition *classDef, varbinder::LocalVariable *it,
1964                                  varbinder::LocalVariable *found, ETSObjectType *interfaceFound)
1965 {
1966     if (found->TsType() == nullptr) {
1967         GetTypeOfVariable(found);
1968     }
1969 
1970     if (!IsSameDeclarationType(it, found)) {
1971         if (IsVariableStatic(it) != IsVariableStatic(found)) {
1972             return;
1973         }
1974 
1975         if (it->TsType()->IsETSFunctionType()) {
1976             auto getter = it->TsType()->AsETSFunctionType()->FindGetter();
1977             if (getter != nullptr && getter->ReturnType() == found->TsType()) {
1978                 return;
1979             }
1980             auto setter = it->TsType()->AsETSFunctionType()->FindSetter();
1981             if (setter != nullptr && setter->Params().front()->TsType() == found->TsType()) {
1982                 return;
1983             }
1984         }
1985 
1986         const char *targetType {};
1987 
1988         if (it->HasFlag(varbinder::VariableFlags::PROPERTY)) {
1989             targetType = "field";
1990         } else if (it->HasFlag(varbinder::VariableFlags::METHOD)) {
1991             targetType = "method";
1992         } else if (it->HasFlag(varbinder::VariableFlags::CLASS)) {
1993             targetType = "class";
1994         } else if (it->HasFlag(varbinder::VariableFlags::INTERFACE)) {
1995             targetType = "interface";
1996         } else {
1997             targetType = "enum";
1998         }
1999 
2000         if (interfaceFound != nullptr) {
2001             LogTypeError({"Cannot inherit from interface ", interfaceFound->Name(), " because ", targetType, " ",
2002                           it->Name(), " is inherited with a different declaration type"},
2003                          interfaceFound->GetDeclNode()->Start());
2004             return;
2005         }
2006         LogTypeError({"Cannot inherit from class ", classType->SuperType()->Name(), ", because ", targetType, " ",
2007                       it->Name(), " is inherited with a different declaration type"},
2008                      classDef->Super()->Start());
2009     }
2010 }
2011 
2012 void ETSChecker::TransformProperties(ETSObjectType *classType)
2013 {
2014     auto propertyList = classType->Fields();
2015     auto *const classDef = classType->GetDeclNode()->AsClassDefinition();
2016 
2017     for (auto *const field : propertyList) {
2018         ASSERT(field->Declaration()->Node()->IsClassProperty());
2019         auto *const originalProp = field->Declaration()->Node()->AsClassProperty();
2020 
2021         if ((originalProp->Modifiers() & ir::ModifierFlags::GETTER_SETTER) == 0U) {
2022             continue;
2023         }
2024 
2025         if (!field->HasFlag(varbinder::VariableFlags::PUBLIC)) {
2026             LogTypeError("Interface property implementation cannot be generated as non-public",
2027                          field->Declaration()->Node()->Start());
2028         }
2029         classType->RemoveProperty<checker::PropertyType::INSTANCE_FIELD>(field);
2030         GenerateGetterSetterPropertyAndMethod(originalProp, classType);
2031     }
2032 
2033     for (auto it = classDef->Body().begin(); it != classDef->Body().end(); ++it) {
2034         if ((*it)->IsClassProperty() && ((*it)->Modifiers() & ir::ModifierFlags::GETTER_SETTER) != 0U) {
2035             classDef->Body().erase(it);
2036         }
2037     }
2038 }
2039 
2040 void ETSChecker::CheckGetterSetterProperties(ETSObjectType *classType)
2041 {
2042     auto const checkGetterSetter = [this](varbinder::LocalVariable *var, util::StringView name) {
2043         auto const *type = var->TsType()->AsETSFunctionType();
2044         auto const *sigGetter = type->FindGetter();
2045         auto const *sigSetter = type->FindSetter();
2046 
2047         for (auto const *sig : type->CallSignatures()) {
2048             if (!sig->Function()->IsGetter() && !sig->Function()->IsSetter()) {
2049                 LogTypeError({"Method cannot use the same name as ", name, " accessor property"},
2050                              sig->Function()->Start());
2051                 return;
2052             }
2053             if (sig != sigGetter && sig != sigSetter) {
2054                 LogTypeError("Duplicate accessor definition", sig->Function()->Start());
2055                 return;
2056             }
2057         }
2058         if (sigSetter != nullptr && ((sigGetter->Function()->Modifiers() ^ sigSetter->Function()->Modifiers()) &
2059                                      ir::ModifierFlags::ACCESSOR_MODIFIERS) != 0) {
2060             LogTypeError("Getter and setter methods must have the same accessor modifiers",
2061                          sigGetter->Function()->Start());
2062         }
2063     };
2064 
2065     for (const auto &[name, var] : classType->InstanceMethods()) {
2066         if (IsVariableGetterSetter(var)) {
2067             checkGetterSetter(var, name);
2068         }
2069     }
2070 
2071     for (const auto &[name, var] : classType->StaticMethods()) {
2072         if (IsVariableGetterSetter(var)) {
2073             checkGetterSetter(var, name);
2074         }
2075     }
2076 }
2077 
2078 void ETSChecker::AddElementsToModuleObject(ETSObjectType *moduleObj, const util::StringView &str)
2079 {
2080     for (const auto &[name, var] : VarBinder()->GetScope()->Bindings()) {
2081         if (name.Is(str.Mutf8()) || name.Is(compiler::Signatures::ETS_GLOBAL)) {
2082             continue;
2083         }
2084 
2085         if (var->HasFlag(varbinder::VariableFlags::METHOD)) {
2086             moduleObj->AddProperty<checker::PropertyType::STATIC_METHOD>(var->AsLocalVariable());
2087         } else if (var->HasFlag(varbinder::VariableFlags::PROPERTY)) {
2088             moduleObj->AddProperty<checker::PropertyType::STATIC_FIELD>(var->AsLocalVariable());
2089         } else {
2090             moduleObj->AddProperty<checker::PropertyType::STATIC_DECL>(var->AsLocalVariable());
2091         }
2092     }
2093 }
2094 
2095 // This function computes effective runtime view of type
2096 Type *ETSChecker::GetApparentType(Type *type)
2097 {
2098     if (auto it = apparentTypes_.find(type); LIKELY(it != apparentTypes_.end())) {
2099         return it->second;
2100     }
2101     auto cached = [this, type](Type *res) {
2102         if (type != res) {
2103             apparentTypes_.insert({type, res});
2104         }
2105         apparentTypes_.insert({res, res});
2106         return res;
2107     };
2108 
2109     if (type->IsETSTypeParameter()) {
2110         return cached(GetApparentType(type->AsETSTypeParameter()->GetConstraintType()));
2111     }
2112     if (type->IsETSNonNullishType()) {
2113         return cached(
2114             GetNonNullishType(GetApparentType(type->AsETSNonNullishType()->GetUnderlying()->GetConstraintType())));
2115     }
2116     if (type->IsETSArrayType()) {
2117         return cached(type);
2118     }
2119     if (type->IsETSUnionType()) {
2120         bool differ = false;
2121         ArenaVector<checker::Type *> newConstituent(Allocator()->Adapter());
2122         for (auto const &ct : type->AsETSUnionType()->ConstituentTypes()) {
2123             newConstituent.push_back(GetApparentType(ct));
2124             differ |= (newConstituent.back() != ct);
2125         }
2126         return cached(differ ? CreateETSUnionType(std::move(newConstituent)) : type);
2127     }
2128     return cached(type);
2129 }
2130 
2131 Type const *ETSChecker::GetApparentType(Type const *type) const
2132 {
2133     if (auto it = apparentTypes_.find(type); LIKELY(it != apparentTypes_.end())) {
2134         return it->second;
2135     }
2136     // Relaxed for some types
2137     if (type->IsETSTypeParameter()) {
2138         return GetApparentType(type->AsETSTypeParameter()->GetConstraintType());
2139     }
2140     if (type->IsETSArrayType()) {
2141         return type;
2142     }
2143     if (type->IsETSUnionType() || type->IsETSNonNullishType()) {
2144         ASSERT_PRINT(false, std::string("Type ") + type->ToString() + " was not found in apparent_types_");
2145     }
2146     return type;
2147 }
2148 
2149 ETSObjectType *ETSChecker::GetClosestCommonAncestor(ETSObjectType *source, ETSObjectType *target)
2150 {
2151     if (source->AsETSObjectType()->GetDeclNode() == target->AsETSObjectType()->GetDeclNode()) {
2152         return source;
2153     }
2154     if (target->SuperType() == nullptr) {
2155         return GlobalETSObjectType();
2156     }
2157 
2158     auto *targetBase = GetOriginalBaseType(target->SuperType());
2159     auto *targetType = targetBase == nullptr ? target->SuperType() : targetBase;
2160 
2161     auto *sourceBase = GetOriginalBaseType(source);
2162     auto *sourceType = sourceBase == nullptr ? source : sourceBase;
2163 
2164     if (Relation()->IsSupertypeOf(targetType, sourceType)) {
2165         // NOTE: TorokG. Extending the search to find intersection types
2166         return targetType;
2167     }
2168 
2169     return GetClosestCommonAncestor(sourceType, targetType);
2170 }
2171 
2172 void ETSChecker::CheckInvokeMethodsLegitimacy(ETSObjectType *const classType)
2173 {
2174     if (classType->HasObjectFlag(ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY)) {
2175         return;
2176     }
2177 
2178     auto searchFlag = PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::SEARCH_IN_BASE |
2179                       PropertySearchFlags::SEARCH_STATIC_METHOD;
2180 
2181     auto *const invokeMethod = classType->GetProperty(compiler::Signatures::STATIC_INVOKE_METHOD, searchFlag);
2182     if (invokeMethod == nullptr) {
2183         classType->AddObjectFlag(ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
2184         return;
2185     }
2186 
2187     auto *const instantiateMethod = classType->GetProperty(compiler::Signatures::STATIC_INSTANTIATE_METHOD, searchFlag);
2188     if (instantiateMethod != nullptr) {
2189         LogTypeError({"Static ", compiler::Signatures::STATIC_INVOKE_METHOD, " method and static ",
2190                       compiler::Signatures::STATIC_INSTANTIATE_METHOD, " method both exist in class/interface ",
2191                       classType->Name(), " is not allowed."},
2192                      classType->GetDeclNode()->Start());
2193     }
2194     classType->AddObjectFlag(ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
2195 }
2196 
2197 }  // namespace ark::es2panda::checker
2198