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
51namespace ark::es2panda::checker {
52ETSObjectType *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
64bool 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
117void 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
133void 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
148void 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
169ArenaVector<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
182std::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
208void 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
219bool 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
252bool 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
270void 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
304ETSTypeParameter *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
323void 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
341ETSObjectType *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
367ETSObjectType *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
417ETSObjectType *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
427static 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
446static 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
493static 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
508void 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
546bool 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
583std::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
603void 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
619void 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
652ArenaVector<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
688static 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
694static 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
701static 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
711void 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
727void 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
744void 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
762void 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
790void 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
837void 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
873void 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
891void 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
927void 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
953void 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
991void 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
1009void 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
1019void 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
1085void 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
1096bool 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
1105void 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
1136void 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
1170void 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
1190void 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
1229ArenaVector<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
1268void 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
1279void 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
1297void 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
1312void 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
1318void 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
1341void 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
1356bool 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
1401std::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
1430bool 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
1464ETSObjectType *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
1503void 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
1532ETSObjectType *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
1545Type *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
1559void 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
1595varbinder::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
1611PropertySearchFlags 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
1666PropertySearchFlags 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
1686const 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
1697void 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
1724void 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
1748ir::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
1767bool 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
1783bool 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
1791void 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)
1826std::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
1895void 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
1917void 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
1963void 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
2012void 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
2040void 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
2078void 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
2096Type *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
2131Type 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
2149ETSObjectType *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
2172void 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