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