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