• 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 "varbinder/variableFlags.h"
18 #include "checker/ets/castingContext.h"
19 #include "checker/types/ets/etsObjectType.h"
20 #include "ir/astNode.h"
21 #include "ir/typeNode.h"
22 #include "ir/base/classDefinition.h"
23 #include "ir/base/classElement.h"
24 #include "ir/base/classProperty.h"
25 #include "ir/base/methodDefinition.h"
26 #include "ir/base/classStaticBlock.h"
27 #include "ir/base/scriptFunction.h"
28 #include "ir/statements/blockStatement.h"
29 #include "ir/statements/variableDeclarator.h"
30 #include "ir/statements/expressionStatement.h"
31 #include "ir/expressions/binaryExpression.h"
32 #include "ir/expressions/identifier.h"
33 #include "ir/expressions/functionExpression.h"
34 #include "ir/expressions/memberExpression.h"
35 #include "ir/expressions/callExpression.h"
36 #include "ir/expressions/superExpression.h"
37 #include "ir/expressions/assignmentExpression.h"
38 #include "ir/expressions/thisExpression.h"
39 #include "ir/statements/classDeclaration.h"
40 #include "ir/statements/returnStatement.h"
41 #include "ir/ts/tsClassImplements.h"
42 #include "ir/ts/tsInterfaceHeritage.h"
43 #include "ir/ts/tsInterfaceBody.h"
44 #include "ir/ts/tsInterfaceDeclaration.h"
45 #include "ir/ts/tsTypeParameter.h"
46 #include "ir/ts/tsTypeParameterDeclaration.h"
47 #include "ir/ets/etsTypeReference.h"
48 #include "ir/ets/etsTypeReferencePart.h"
49 #include "ir/ets/etsNewClassInstanceExpression.h"
50 #include "varbinder/variable.h"
51 #include "varbinder/scope.h"
52 #include "varbinder/declaration.h"
53 #include "varbinder/ETSBinder.h"
54 #include "checker/ETSchecker.h"
55 #include "checker/types/typeFlag.h"
56 #include "checker/types/ets/etsDynamicType.h"
57 #include "checker/types/ets/types.h"
58 #include "checker/ets/typeRelationContext.h"
59 #include "ir/ets/etsUnionType.h"
60 
61 namespace panda::es2panda::checker {
GetSuperType(ETSObjectType * type)62 ETSObjectType *ETSChecker::GetSuperType(ETSObjectType *type)
63 {
64     if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) {
65         return type->SuperType();
66     }
67 
68     ASSERT(type->Variable() && type->GetDeclNode()->IsClassDefinition());
69     auto *classDef = type->GetDeclNode()->AsClassDefinition();
70 
71     if (classDef->Super() == nullptr) {
72         type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER);
73         if (type != GlobalETSObjectType()) {
74             type->SetSuperType(GlobalETSObjectType());
75         }
76         return GlobalETSObjectType();
77     }
78 
79     TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, classDef->Ident()->Start());
80 
81     Type *superType = classDef->Super()->AsTypeNode()->GetType(this);
82 
83     if (!superType->IsETSObjectType() || !superType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) {
84         ThrowTypeError({"The super type of '", classDef->Ident()->Name(), "' class is not extensible."},
85                        classDef->Super()->Start());
86     }
87 
88     ETSObjectType *superObj = superType->AsETSObjectType();
89 
90     // struct node has class defination, too
91     if (superObj->GetDeclNode()->Parent()->IsETSStructDeclaration()) {
92         ThrowTypeError({"struct ", classDef->Ident()->Name(), " is not extensible."}, classDef->Super()->Start());
93     }
94 
95     if (superObj->GetDeclNode()->IsFinal()) {
96         ThrowTypeError("Cannot inherit with 'final' modifier.", classDef->Super()->Start());
97     }
98 
99     type->SetSuperType(superObj);
100     GetSuperType(superObj);
101 
102     type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER);
103     return type->SuperType();
104 }
105 
ValidateImplementedInterface(ETSObjectType * type,Type * interface,std::unordered_set<Type * > * extendsSet,const lexer::SourcePosition & pos)106 void ETSChecker::ValidateImplementedInterface(ETSObjectType *type, Type *interface,
107                                               std::unordered_set<Type *> *extendsSet, const lexer::SourcePosition &pos)
108 {
109     if (!interface->IsETSObjectType() || !interface->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
110         ThrowTypeError("Interface expected here.", pos);
111     }
112 
113     if (!extendsSet->insert(interface).second) {
114         ThrowTypeError("Repeated interface.", pos);
115     }
116 
117     type->AddInterface(interface->AsETSObjectType());
118     GetInterfacesOfInterface(interface->AsETSObjectType());
119 }
120 
GetInterfacesOfClass(ETSObjectType * type)121 ArenaVector<ETSObjectType *> ETSChecker::GetInterfacesOfClass(ETSObjectType *type)
122 {
123     if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES)) {
124         return type->Interfaces();
125     }
126 
127     const auto *declNode = type->GetDeclNode()->AsClassDefinition();
128 
129     std::unordered_set<Type *> extendsSet;
130     for (auto *it : declNode->Implements()) {
131         ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start());
132     }
133 
134     type->AddObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES);
135     return type->Interfaces();
136 }
137 
GetInterfacesOfInterface(ETSObjectType * type)138 ArenaVector<ETSObjectType *> ETSChecker::GetInterfacesOfInterface(ETSObjectType *type)
139 {
140     if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES)) {
141         return type->Interfaces();
142     }
143 
144     const auto *declNode = type->GetDeclNode()->AsTSInterfaceDeclaration();
145 
146     TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, declNode->Id()->Start());
147 
148     std::unordered_set<Type *> extendsSet;
149     for (auto *it : declNode->Extends()) {
150         ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start());
151     }
152 
153     type->AddObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES);
154     return type->Interfaces();
155 }
156 
GetInterfaces(ETSObjectType * type)157 ArenaVector<ETSObjectType *> ETSChecker::GetInterfaces(ETSObjectType *type)
158 {
159     ASSERT(type->GetDeclNode()->IsClassDefinition() || type->GetDeclNode()->IsTSInterfaceDeclaration());
160 
161     if (type->GetDeclNode()->IsClassDefinition()) {
162         GetInterfacesOfClass(type);
163     } else {
164         GetInterfacesOfInterface(type);
165     }
166 
167     return type->Interfaces();
168 }
169 
CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration const * typeParams)170 ArenaVector<Type *> ETSChecker::CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration const *typeParams)
171 {
172     ArenaVector<Type *> result {Allocator()->Adapter()};
173     checker::ScopeContext scopeCtx(this, typeParams->Scope());
174 
175     // Note: we have to run pure check loop first to avoid endless loop because of possible circular dependencies
176     Type2TypeMap extends {};
177     for (auto *const typeParam : typeParams->Params()) {
178         if (auto *const constraint = typeParam->Constraint();
179             constraint != nullptr && constraint->IsETSTypeReference() &&
180             constraint->AsETSTypeReference()->Part()->Name()->IsIdentifier()) {
181             CheckTypeParameterConstraint(typeParam, extends);
182         }
183     }
184 
185     for (auto *const typeParam : typeParams->Params()) {
186         result.emplace_back(SetUpParameterType(typeParam));
187     }
188 
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 
195     return result;
196 }
197 
CheckTypeParameterConstraint(ir::TSTypeParameter * param,Type2TypeMap & extends)198 void ETSChecker::CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends)
199 {
200     const auto typeParamName = param->Name()->Name().Utf8();
201     const auto constraintName =
202         param->Constraint()->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Utf8();
203     if (typeParamName == constraintName) {
204         ThrowTypeError({"Type parameter '", typeParamName, "' cannot extend/implement itself."},
205                        param->Constraint()->Start());
206     }
207 
208     auto it = extends.find(typeParamName);
209     if (it != extends.cend()) {
210         ThrowTypeError({"Type parameter '", typeParamName, "' is duplicated in the list."},
211                        param->Constraint()->Start());
212     }
213 
214     it = extends.find(constraintName);
215     while (it != extends.cend()) {
216         if (it->second == typeParamName) {
217             ThrowTypeError({"Type parameter '", typeParamName, "' has circular constraint dependency."},
218                            param->Constraint()->Start());
219         }
220         it = extends.find(it->second);
221     }
222 
223     extends.emplace(typeParamName, constraintName);
224 }
225 
SetUpTypeParameterConstraint(ir::TSTypeParameter * const param)226 void ETSChecker::SetUpTypeParameterConstraint(ir::TSTypeParameter *const param)
227 {
228     ETSTypeParameter *const paramType = [this, param]() {
229         auto *const type = param->Name()->Variable()->TsType();
230         return type != nullptr ? type->AsETSTypeParameter() : SetUpParameterType(param);
231     }();
232 
233     auto const traverseReferenced =
234         [this, scope = param->Parent()->AsTSTypeParameterDeclaration()->Scope()](ir::TypeNode *typeNode) {
235             if (!typeNode->IsETSTypeReference()) {
236                 return;
237             }
238             const auto typeName = typeNode->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name();
239             auto *const found = scope->FindLocal(typeName, varbinder::ResolveBindingOptions::BINDINGS);
240             if (found != nullptr) {
241                 SetUpTypeParameterConstraint(found->Declaration()->Node()->AsTSTypeParameter());
242             }
243         };
244 
245     if (param->Constraint() != nullptr) {
246         traverseReferenced(param->Constraint());
247         auto *const constraint = param->Constraint()->GetType(this);
248         if (!constraint->IsETSObjectType() && !constraint->IsETSTypeParameter() && !constraint->IsETSUnionType()) {
249             ThrowTypeError("Extends constraint must be an object", param->Constraint()->Start());
250         }
251         paramType->SetConstraintType(constraint);
252     } else {
253         paramType->SetConstraintType(GlobalETSNullishObjectType());
254     }
255 
256     if (param->DefaultType() != nullptr) {
257         traverseReferenced(param->DefaultType());
258         // NOTE: #14993 ensure default matches constraint
259         paramType->SetDefaultType(MaybePromotedBuiltinType(param->DefaultType()->GetType(this)));
260     }
261 }
262 
SetUpParameterType(ir::TSTypeParameter * const param)263 ETSTypeParameter *ETSChecker::SetUpParameterType(ir::TSTypeParameter *const param)
264 {
265     auto *const paramType = CreateTypeParameter();
266 
267     paramType->AddTypeFlag(TypeFlag::GENERIC);
268     paramType->SetDeclNode(param);
269     paramType->SetVariable(param->Variable());
270     // NOTE: #15026 recursive type parameter workaround
271     paramType->SetConstraintType(GlobalETSNullishObjectType());
272 
273     param->Name()->Variable()->SetTsType(paramType);
274     return paramType;
275 }
276 
CreateTypeForClassOrInterfaceTypeParameters(ETSObjectType * type)277 void ETSChecker::CreateTypeForClassOrInterfaceTypeParameters(ETSObjectType *type)
278 {
279     if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS)) {
280         return;
281     }
282 
283     ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->IsClassDefinition()
284                                                      ? type->GetDeclNode()->AsClassDefinition()->TypeParams()
285                                                      : type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams();
286     type->SetTypeArguments(CreateTypeForTypeParameters(typeParams));
287     type->AddObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS);
288 }
289 
BuildInterfaceProperties(ir::TSInterfaceDeclaration * interfaceDecl)290 ETSObjectType *ETSChecker::BuildInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl)
291 {
292     auto *var = interfaceDecl->Id()->Variable();
293     ASSERT(var);
294 
295     checker::ETSObjectType *interfaceType {};
296     if (var->TsType() == nullptr) {
297         interfaceType = CreateETSObjectType(var->Name(), interfaceDecl,
298                                             checker::ETSObjectFlags::INTERFACE | checker::ETSObjectFlags::ABSTRACT);
299         interfaceType->SetVariable(var);
300         var->SetTsType(interfaceType);
301     } else {
302         interfaceType = var->TsType()->AsETSObjectType();
303     }
304 
305     if (interfaceDecl->TypeParams() != nullptr) {
306         interfaceType->AddTypeFlag(TypeFlag::GENERIC);
307         CreateTypeForClassOrInterfaceTypeParameters(interfaceType);
308     }
309 
310     GetInterfacesOfInterface(interfaceType);
311 
312     checker::ScopeContext scopeCtx(this, interfaceDecl->Scope());
313     auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_INTERFACE, interfaceType);
314 
315     ResolveDeclaredMembersOfObject(interfaceType);
316 
317     return interfaceType;
318 }
319 
BuildClassProperties(ir::ClassDefinition * classDef)320 ETSObjectType *ETSChecker::BuildClassProperties(ir::ClassDefinition *classDef)
321 {
322     if (classDef->IsFinal() && classDef->IsAbstract()) {
323         ThrowTypeError("Cannot use both 'final' and 'abstract' modifiers.", classDef->Start());
324     }
325 
326     auto *var = classDef->Ident()->Variable();
327     ASSERT(var);
328 
329     const util::StringView &className = classDef->Ident()->Name();
330     auto *classScope = classDef->Scope();
331 
332     checker::ETSObjectType *classType {};
333     if (var->TsType() == nullptr) {
334         classType = CreateETSObjectType(className, classDef, checker::ETSObjectFlags::CLASS);
335         classType->SetVariable(var);
336         var->SetTsType(classType);
337         if (classDef->IsAbstract()) {
338             classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT);
339         }
340     } else {
341         classType = var->TsType()->AsETSObjectType();
342     }
343 
344     classDef->SetTsType(classType);
345 
346     if (classDef->TypeParams() != nullptr) {
347         classType->AddTypeFlag(TypeFlag::GENERIC);
348         CreateTypeForClassOrInterfaceTypeParameters(classType);
349     }
350 
351     auto *enclosingClass = Context().ContainingClass();
352     classType->SetEnclosingType(enclosingClass);
353     CheckerStatus newStatus = CheckerStatus::IN_CLASS;
354 
355     if (classDef->IsInner()) {
356         newStatus |= CheckerStatus::INNER_CLASS;
357         classType->AddObjectFlag(checker::ETSObjectFlags::INNER);
358     }
359 
360     auto savedContext = checker::SavedCheckerContext(this, newStatus, classType);
361 
362     if (!classType->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) {
363         GetSuperType(classType);
364         GetInterfacesOfClass(classType);
365     }
366 
367     if (classType->HasObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS)) {
368         return classType;
369     }
370 
371     checker::ScopeContext scopeCtx(this, classScope);
372 
373     ResolveDeclaredMembersOfObject(classType);
374 
375     return classType;
376 }
377 
BuildAnonymousClassProperties(ir::ClassDefinition * classDef,ETSObjectType * superType)378 ETSObjectType *ETSChecker::BuildAnonymousClassProperties(ir::ClassDefinition *classDef, ETSObjectType *superType)
379 {
380     auto classType = CreateETSObjectType(classDef->Ident()->Name(), classDef, checker::ETSObjectFlags::CLASS);
381     classDef->SetTsType(classType);
382     classType->SetSuperType(superType);
383     classType->AddObjectFlag(checker::ETSObjectFlags::RESOLVED_SUPER);
384 
385     checker::ScopeContext scopeCtx(this, classDef->Scope());
386     auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_CLASS, classType);
387 
388     ResolveDeclaredMembersOfObject(classType);
389 
390     return classType;
391 }
392 
ResolveDeclaredFieldsOfObject(ETSChecker * checker,ETSObjectType * type,varbinder::ClassScope * scope)393 static void ResolveDeclaredFieldsOfObject(ETSChecker *checker, ETSObjectType *type, varbinder::ClassScope *scope)
394 {
395     for (auto &[_, it] : scope->InstanceFieldScope()->Bindings()) {
396         (void)_;
397         ASSERT(it->Declaration()->Node()->IsClassProperty());
398         auto *classProp = it->Declaration()->Node()->AsClassProperty();
399         it->AddFlag(checker->GetAccessFlagFromNode(classProp));
400         type->AddProperty<PropertyType::INSTANCE_FIELD>(it->AsLocalVariable());
401 
402         if (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSFunctionType()) {
403             type->AddProperty<PropertyType::INSTANCE_METHOD>(it->AsLocalVariable());
404             it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE);
405         } else if (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSTypeReference()) {
406             bool hasFunctionType = checker->HasETSFunctionType(classProp->TypeAnnotation());
407             if (hasFunctionType) {
408                 type->AddProperty<PropertyType::INSTANCE_METHOD>(it->AsLocalVariable());
409                 it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE);
410             }
411         }
412     }
413 
414     for (auto &[_, it] : scope->StaticFieldScope()->Bindings()) {
415         (void)_;
416         ASSERT(it->Declaration()->Node()->IsClassProperty());
417         auto *classProp = it->Declaration()->Node()->AsClassProperty();
418         it->AddFlag(checker->GetAccessFlagFromNode(classProp));
419         type->AddProperty<PropertyType::STATIC_FIELD>(it->AsLocalVariable());
420 
421         if (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSFunctionType()) {
422             type->AddProperty<PropertyType::STATIC_METHOD>(it->AsLocalVariable());
423             it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE);
424         } else if (classProp->TypeAnnotation() != nullptr && classProp->TypeAnnotation()->IsETSTypeReference()) {
425             bool hasFunctionType = checker->HasETSFunctionType(classProp->TypeAnnotation());
426             if (hasFunctionType) {
427                 type->AddProperty<PropertyType::STATIC_METHOD>(it->AsLocalVariable());
428                 it->AddFlag(varbinder::VariableFlags::METHOD_REFERENCE);
429             }
430         }
431     }
432 }
433 
ResolveDeclaredMethodsOfObject(ETSChecker * checker,ETSObjectType * type,varbinder::ClassScope * scope)434 static void ResolveDeclaredMethodsOfObject(ETSChecker *checker, ETSObjectType *type, varbinder::ClassScope *scope)
435 {
436     for (auto &[_, it] : scope->InstanceMethodScope()->Bindings()) {
437         (void)_;
438         auto *node = it->Declaration()->Node()->AsMethodDefinition();
439 
440         if (node->Function()->IsProxy()) {
441             continue;
442         }
443 
444         it->AddFlag(checker->GetAccessFlagFromNode(node));
445         auto *funcType = checker->BuildMethodSignature(node);
446         it->SetTsType(funcType);
447         funcType->SetVariable(it);
448         node->SetTsType(funcType);
449         type->AddProperty<PropertyType::INSTANCE_METHOD>(it->AsLocalVariable());
450     }
451 
452     for (auto &[_, it] : scope->StaticMethodScope()->Bindings()) {
453         (void)_;
454         if (!it->Declaration()->Node()->IsMethodDefinition() ||
455             it->Declaration()->Node()->AsMethodDefinition()->Function()->IsProxy()) {
456             continue;
457         }
458         auto *node = it->Declaration()->Node()->AsMethodDefinition();
459         it->AddFlag(checker->GetAccessFlagFromNode(node));
460         auto *funcType = checker->BuildMethodSignature(node);
461         it->SetTsType(funcType);
462         funcType->SetVariable(it);
463         node->SetTsType(funcType);
464 
465         if (node->IsConstructor()) {
466             type->AddConstructSignature(funcType->CallSignatures());
467             continue;
468         }
469 
470         type->AddProperty<PropertyType::STATIC_METHOD>(it->AsLocalVariable());
471     }
472 }
473 
ResolveDeclaredDeclsOfObject(ETSChecker * checker,ETSObjectType * type,varbinder::ClassScope * scope)474 static void ResolveDeclaredDeclsOfObject(ETSChecker *checker, ETSObjectType *type, varbinder::ClassScope *scope)
475 {
476     for (auto &[_, it] : scope->InstanceDeclScope()->Bindings()) {
477         (void)_;
478         it->AddFlag(checker->GetAccessFlagFromNode(it->Declaration()->Node()));
479         type->AddProperty<PropertyType::INSTANCE_DECL>(it->AsLocalVariable());
480     }
481 
482     for (auto &[_, it] : scope->StaticDeclScope()->Bindings()) {
483         (void)_;
484         it->AddFlag(checker->GetAccessFlagFromNode(it->Declaration()->Node()));
485         type->AddProperty<PropertyType::STATIC_DECL>(it->AsLocalVariable());
486     }
487 }
488 
ResolveDeclaredMembersOfObject(ETSObjectType * type)489 void ETSChecker::ResolveDeclaredMembersOfObject(ETSObjectType *type)
490 {
491     if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS)) {
492         return;
493     }
494 
495     auto *declNode = type->GetDeclNode();
496     varbinder::ClassScope *scope = declNode->IsTSInterfaceDeclaration()
497                                        ? declNode->AsTSInterfaceDeclaration()->Scope()->AsClassScope()
498                                        : declNode->AsClassDefinition()->Scope()->AsClassScope();
499 
500     ResolveDeclaredFieldsOfObject(this, type, scope);
501     ResolveDeclaredMethodsOfObject(this, type, scope);
502     ResolveDeclaredDeclsOfObject(this, type, scope);
503 
504     type->AddObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS);
505 }
506 
HasETSFunctionType(ir::TypeNode * typeAnnotation)507 bool ETSChecker::HasETSFunctionType(ir::TypeNode *typeAnnotation)
508 {
509     if (typeAnnotation->IsETSFunctionType()) {
510         return true;
511     }
512     std::unordered_set<ir::TypeNode *> childrenSet;
513 
514     if (!typeAnnotation->IsETSTypeReference()) {
515         return false;
516     }
517 
518     auto const addTypeAlias = [&childrenSet, &typeAnnotation](varbinder::Decl *typeDecl) {
519         typeAnnotation = typeDecl->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation();
520         if (!typeAnnotation->IsETSUnionType()) {
521             childrenSet.insert(typeAnnotation);
522             return;
523         }
524         for (auto *type : typeAnnotation->AsETSUnionType()->Types()) {
525             if (type->IsETSTypeReference()) {
526                 childrenSet.insert(type);
527             }
528         }
529     };
530 
531     auto *typeDecl = typeAnnotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Variable()->Declaration();
532     if (typeDecl != nullptr && typeDecl->IsTypeAliasDecl()) {
533         addTypeAlias(typeDecl);
534     }
535 
536     for (auto *child : childrenSet) {
537         if (HasETSFunctionType(child)) {
538             return true;
539         }
540     }
541     return false;
542 }
543 
CollectAbstractSignaturesFromObject(const ETSObjectType * objType)544 std::vector<Signature *> ETSChecker::CollectAbstractSignaturesFromObject(const ETSObjectType *objType)
545 {
546     std::vector<Signature *> abstracts;
547     for (const auto &prop : objType->Methods()) {
548         GetTypeOfVariable(prop);
549 
550         if (!prop->TsType()->IsETSFunctionType()) {
551             continue;
552         }
553 
554         for (auto *sig : prop->TsType()->AsETSFunctionType()->CallSignatures()) {
555             if (sig->HasSignatureFlag(SignatureFlags::ABSTRACT) && !sig->HasSignatureFlag(SignatureFlags::PRIVATE)) {
556                 abstracts.push_back(sig);
557             }
558         }
559     }
560 
561     return abstracts;
562 }
563 
CreateFunctionTypesFromAbstracts(const std::vector<Signature * > & abstracts,ArenaVector<ETSFunctionType * > * target)564 void ETSChecker::CreateFunctionTypesFromAbstracts(const std::vector<Signature *> &abstracts,
565                                                   ArenaVector<ETSFunctionType *> *target)
566 {
567     for (auto *it : abstracts) {
568         auto name = it->Function()->Id()->Name();
569         auto *found = FindFunctionInVectorGivenByName(name, *target);
570         if (found != nullptr) {
571             found->AddCallSignature(it);
572             continue;
573         }
574 
575         auto *created = CreateETSFunctionType(it);
576         created->AddTypeFlag(TypeFlag::SYNTHETIC);
577         target->push_back(created);
578     }
579 }
580 
ComputeAbstractsFromInterface(ETSObjectType * interfaceType)581 void ETSChecker::ComputeAbstractsFromInterface(ETSObjectType *interfaceType)
582 {
583     auto cached = cachedComputedAbstracts_.find(interfaceType);
584     if (cached != cachedComputedAbstracts_.end()) {
585         return;
586     }
587 
588     for (auto *it : interfaceType->Interfaces()) {
589         ComputeAbstractsFromInterface(it);
590     }
591 
592     ArenaVector<ETSFunctionType *> merged(Allocator()->Adapter());
593     CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(interfaceType), &merged);
594     std::unordered_set<ETSObjectType *> abstractInheritanceTarget;
595 
596     for (auto *interface : interfaceType->Interfaces()) {
597         auto found = cachedComputedAbstracts_.find(interface);
598         ASSERT(found != cachedComputedAbstracts_.end());
599 
600         if (!abstractInheritanceTarget.insert(found->first).second) {
601             continue;
602         }
603 
604         MergeComputedAbstracts(merged, found->second.first);
605 
606         for (auto *base : found->second.second) {
607             abstractInheritanceTarget.insert(base);
608         }
609     }
610 
611     cachedComputedAbstracts_.insert({interfaceType, {merged, abstractInheritanceTarget}});
612 }
613 
GetAbstractsForClass(ETSObjectType * classType)614 ArenaVector<ETSFunctionType *> &ETSChecker::GetAbstractsForClass(ETSObjectType *classType)
615 {
616     ArenaVector<ETSFunctionType *> merged(Allocator()->Adapter());
617     CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(classType), &merged);
618 
619     std::unordered_set<ETSObjectType *> abstractInheritanceTarget;
620     if (classType->SuperType() != nullptr) {
621         auto base = cachedComputedAbstracts_.find(classType->SuperType());
622         ASSERT(base != cachedComputedAbstracts_.end());
623         MergeComputedAbstracts(merged, base->second.first);
624 
625         abstractInheritanceTarget.insert(base->first);
626         for (auto *it : base->second.second) {
627             abstractInheritanceTarget.insert(it);
628         }
629     }
630 
631     for (auto *it : classType->Interfaces()) {
632         ComputeAbstractsFromInterface(it);
633         auto found = cachedComputedAbstracts_.find(it);
634         ASSERT(found != cachedComputedAbstracts_.end());
635 
636         if (!abstractInheritanceTarget.insert(found->first).second) {
637             continue;
638         }
639 
640         MergeComputedAbstracts(merged, found->second.first);
641 
642         for (auto *interface : found->second.second) {
643             abstractInheritanceTarget.insert(interface);
644         }
645     }
646 
647     return cachedComputedAbstracts_.insert({classType, {merged, abstractInheritanceTarget}}).first->second.first;
648 }
649 
ValidateOverriding(ETSObjectType * classType,const lexer::SourcePosition & pos)650 void ETSChecker::ValidateOverriding(ETSObjectType *classType, const lexer::SourcePosition &pos)
651 {
652     if (classType->HasObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS)) {
653         return;
654     }
655 
656     bool throwError = true;
657     if (classType->HasObjectFlag(ETSObjectFlags::ABSTRACT)) {
658         throwError = false;
659     }
660 
661     if (classType->SuperType() != nullptr) {
662         ValidateOverriding(classType->SuperType(), classType->SuperType()->GetDeclNode()->Start());
663     }
664 
665     auto &abstractsToBeImplemented = GetAbstractsForClass(classType);
666     std::vector<Signature *> implementedSignatures;
667 
668     auto *superIter = classType;
669     do {
670         for (auto &it : abstractsToBeImplemented) {
671             for (const auto &prop : superIter->Methods()) {
672                 GetTypeOfVariable(prop);
673                 AddImplementedSignature(&implementedSignatures, prop, it);
674             }
675         }
676         superIter = superIter->SuperType();
677     } while (superIter != nullptr);
678 
679     SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK);
680     for (auto it = abstractsToBeImplemented.begin(); it != abstractsToBeImplemented.end();) {
681         bool functionOverridden = false;
682         bool isGetterSetter = false;
683         for (auto abstractSignature = (*it)->CallSignatures().begin();
684              abstractSignature != (*it)->CallSignatures().end();) {
685             bool foundSignature = false;
686             isGetterSetter = (*abstractSignature)->HasSignatureFlag(SignatureFlags::GETTER_OR_SETTER);
687             for (auto *const implemented : implementedSignatures) {
688                 Signature *substImplemented = AdjustForTypeParameters(*abstractSignature, implemented);
689 
690                 if (substImplemented == nullptr) {
691                     continue;
692                 }
693 
694                 if (!AreOverrideEquivalent(*abstractSignature, substImplemented) ||
695                     !IsReturnTypeSubstitutable(substImplemented, *abstractSignature)) {
696                     continue;
697                 }
698 
699                 if ((*it)->CallSignatures().size() > 1) {
700                     abstractSignature = (*it)->CallSignatures().erase(abstractSignature);
701                     foundSignature = true;
702                 } else {
703                     it = abstractsToBeImplemented.erase(it);
704                     functionOverridden = true;
705                 }
706 
707                 break;
708             }
709 
710             if (functionOverridden) {
711                 break;
712             }
713 
714             if (!foundSignature) {
715                 abstractSignature++;
716             }
717         }
718 
719         if (isGetterSetter && !functionOverridden) {
720             for (auto *field : classType->Fields()) {
721                 if (field->Name() == (*it)->Name()) {
722                     it = abstractsToBeImplemented.erase(it);
723                     functionOverridden = true;
724                     break;
725                 }
726             }
727         }
728 
729         if (!functionOverridden) {
730             it++;
731         }
732     }
733 
734     if (!abstractsToBeImplemented.empty() && throwError) {
735         auto unimplementedSignature = abstractsToBeImplemented.front()->CallSignatures().front();
736         ThrowTypeError({classType->Name(), " is not abstract and does not override abstract method ",
737                         unimplementedSignature->Function()->Id()->Name(), unimplementedSignature, " in ",
738                         GetContainingObjectNameFromSignature(unimplementedSignature)},
739                        pos);
740     }
741 
742     classType->AddObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS);
743 }
744 
AddImplementedSignature(std::vector<Signature * > * implementedSignatures,varbinder::LocalVariable * function,ETSFunctionType * it)745 void ETSChecker::AddImplementedSignature(std::vector<Signature *> *implementedSignatures,
746                                          varbinder::LocalVariable *function, ETSFunctionType *it)
747 {
748     if (!function->TsType()->IsETSFunctionType()) {
749         return;
750     }
751 
752     for (auto signature : function->TsType()->AsETSFunctionType()->CallSignatures()) {
753         if (signature->Function()->IsAbstract() || signature->Function()->IsStatic()) {
754             continue;
755         }
756 
757         if (signature->Function()->Id()->Name() == it->Name()) {
758             implementedSignatures->emplace_back(signature);
759         }
760     }
761 }
762 
CheckClassDefinition(ir::ClassDefinition * classDef)763 void ETSChecker::CheckClassDefinition(ir::ClassDefinition *classDef)
764 {
765     auto *classType = classDef->TsType()->AsETSObjectType();
766     auto *enclosingClass = Context().ContainingClass();
767     auto newStatus = checker::CheckerStatus::IN_CLASS;
768     classType->SetEnclosingType(enclosingClass);
769 
770     if (classDef->IsInner()) {
771         newStatus |= CheckerStatus::INNER_CLASS;
772         classType->AddObjectFlag(checker::ETSObjectFlags::INNER);
773     }
774 
775     if (classDef->IsGlobal()) {
776         classType->AddObjectFlag(checker::ETSObjectFlags::GLOBAL);
777     }
778 
779     checker::ScopeContext scopeCtx(this, classDef->Scope());
780     auto savedContext = SavedCheckerContext(this, newStatus, classType);
781 
782     if (classDef->IsAbstract()) {
783         AddStatus(checker::CheckerStatus::IN_ABSTRACT);
784         classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT);
785     }
786 
787     if (classDef->IsStatic() && !Context().ContainingClass()->HasObjectFlag(ETSObjectFlags::GLOBAL)) {
788         AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT);
789     }
790 
791     for (auto *it : classDef->Body()) {
792         if (it->IsClassProperty()) {
793             it->Check(this);
794         }
795     }
796 
797     for (auto *it : classDef->Body()) {
798         if (!it->IsClassProperty()) {
799             it->Check(this);
800         }
801     }
802     CreateAsyncProxyMethods(classDef);
803 
804     if (classDef->IsGlobal()) {
805         return;
806     }
807 
808     if (!classDef->IsDeclare()) {
809         for (auto *it : classType->ConstructSignatures()) {
810             CheckCyclicConstructorCall(it);
811             CheckImplicitSuper(classType, it);
812         }
813     }
814 
815     ValidateOverriding(classType, classDef->Start());
816     CheckValidInheritance(classType, classDef);
817     CheckConstFields(classType);
818     CheckGetterSetterProperties(classType);
819     CheckInvokeMethodsLegitimacy(classType);
820 }
821 
IsAsyncMethod(ir::AstNode * node)822 static bool IsAsyncMethod(ir::AstNode *node)
823 {
824     if (!node->IsMethodDefinition()) {
825         return false;
826     }
827     auto *method = node->AsMethodDefinition();
828     return method->Function()->IsAsyncFunc() && !method->Function()->IsProxy();
829 }
830 
CreateAsyncProxyMethods(ir::ClassDefinition * classDef)831 void ETSChecker::CreateAsyncProxyMethods(ir::ClassDefinition *classDef)
832 {
833     ArenaVector<ir::MethodDefinition *> asyncImpls(Allocator()->Adapter());
834     for (auto *it : classDef->Body()) {
835         if (IsAsyncMethod(it)) {
836             auto *method = it->AsMethodDefinition();
837             asyncImpls.push_back(CreateAsyncProxy(method, classDef));
838             auto *proxy = asyncImpls.back();
839             for (auto *overload : method->Overloads()) {
840                 auto *impl = CreateAsyncProxy(overload, classDef, false);
841                 impl->Function()->Id()->SetVariable(proxy->Function()->Id()->Variable());
842                 proxy->AddOverload(impl);
843             }
844         }
845     }
846     for (auto *it : asyncImpls) {
847         it->Check(this);
848         classDef->Body().push_back(it);
849     }
850 }
851 
CheckImplicitSuper(ETSObjectType * classType,Signature * ctorSig)852 void ETSChecker::CheckImplicitSuper(ETSObjectType *classType, Signature *ctorSig)
853 {
854     if (classType == GlobalETSObjectType()) {
855         return;
856     }
857 
858     auto &stmts = ctorSig->Function()->Body()->AsBlockStatement()->Statements();
859     const auto thisCall = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
860         return stmt->IsExpressionStatement() && stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
861                stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression();
862     });
863     // There is an alternate constructor invocation, no need for super constructor invocation
864     if (thisCall != stmts.end()) {
865         return;
866     }
867 
868     const auto superExpr = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) {
869         return stmt->IsExpressionStatement() && stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
870                stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsSuperExpression();
871     });
872     // There is no super expression
873     if (superExpr == stmts.end()) {
874         const auto superTypeCtorSigs = classType->SuperType()->ConstructSignatures();
875         const auto superTypeCtorSig = std::find_if(superTypeCtorSigs.begin(), superTypeCtorSigs.end(),
876                                                    [](const Signature *sig) { return sig->Params().empty(); });
877         // Super type has no parameterless ctor
878         if (superTypeCtorSig == superTypeCtorSigs.end()) {
879             ThrowTypeError("Must call super constructor", ctorSig->Function()->Start());
880         }
881 
882         ctorSig->Function()->AddFlag(ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED);
883     }
884 }
885 
CheckConstFields(const ETSObjectType * classType)886 void ETSChecker::CheckConstFields(const ETSObjectType *classType)
887 {
888     for (const auto &prop : classType->Fields()) {
889         if (!prop->Declaration()->IsConstDecl() || !prop->HasFlag(varbinder::VariableFlags::EXPLICIT_INIT_REQUIRED)) {
890             continue;
891         }
892         CheckConstFieldInitialized(classType, prop);
893     }
894 }
895 
CheckConstFieldInitialized(const ETSObjectType * classType,varbinder::LocalVariable * classVar)896 void ETSChecker::CheckConstFieldInitialized(const ETSObjectType *classType, varbinder::LocalVariable *classVar)
897 {
898     const bool classVarStatic = classVar->Declaration()->Node()->AsClassProperty()->IsStatic();
899     for (const auto &prop : classType->Methods()) {
900         if (!prop->TsType()->IsETSFunctionType()) {
901             continue;
902         }
903 
904         const auto &callSigs = prop->TsType()->AsETSFunctionType()->CallSignatures();
905         for (const auto *signature : callSigs) {
906             if ((signature->Function()->IsConstructor() && !classVarStatic) ||
907                 (signature->Function()->IsStaticBlock() && classVarStatic)) {
908                 CheckConstFieldInitialized(signature, classVar);
909             }
910         }
911     }
912 }
913 
FindAssignment(const ir::AstNode * node,const varbinder::LocalVariable * classVar,bool & initialized)914 void ETSChecker::FindAssignment(const ir::AstNode *node, const varbinder::LocalVariable *classVar, bool &initialized)
915 {
916     if (node->IsAssignmentExpression() && node->AsAssignmentExpression()->Target() == classVar) {
917         if (initialized) {
918             ThrowTypeError({"Variable '", classVar->Declaration()->Name(), "' might already have been initialized"},
919                            node->Start());
920         }
921 
922         initialized = true;
923         return;
924     }
925 
926     FindAssignments(node, classVar, initialized);
927 }
928 
FindAssignments(const ir::AstNode * node,const varbinder::LocalVariable * classVar,bool & initialized)929 void ETSChecker::FindAssignments(const ir::AstNode *node, const varbinder::LocalVariable *classVar, bool &initialized)
930 {
931     node->Iterate(
932         [this, classVar, &initialized](ir::AstNode *childNode) { FindAssignment(childNode, classVar, initialized); });
933 }
934 
CheckConstFieldInitialized(const Signature * signature,varbinder::LocalVariable * classVar)935 void ETSChecker::CheckConstFieldInitialized(const Signature *signature, varbinder::LocalVariable *classVar)
936 {
937     bool initialized = false;
938     const auto &stmts = signature->Function()->Body()->AsBlockStatement()->Statements();
939     const auto it = stmts.begin();
940     if (it != stmts.end()) {
941         if (const auto *first = *it;
942             first->IsExpressionStatement() && first->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
943             first->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression()) {
944             initialized = true;
945         }
946     }
947 
948     // NOTE: szd. control flow
949     FindAssignments(signature->Function()->Body(), classVar, initialized);
950     if (!initialized) {
951         ThrowTypeError({"Variable '", classVar->Declaration()->Name(), "' might not have been initialized"},
952                        signature->Function()->End());
953     }
954 
955     classVar->RemoveFlag(varbinder::VariableFlags::EXPLICIT_INIT_REQUIRED);
956 }
957 
CheckInnerClassMembers(const ETSObjectType * classType)958 void ETSChecker::CheckInnerClassMembers(const ETSObjectType *classType)
959 {
960     for (const auto &[_, it] : classType->StaticMethods()) {
961         (void)_;
962         ThrowTypeError("Inner class cannot have static methods", it->Declaration()->Node()->Start());
963     }
964 
965     for (const auto &[_, it] : classType->StaticFields()) {
966         (void)_;
967         if (!it->Declaration()->IsConstDecl()) {
968             ThrowTypeError("Inner class cannot have non-const static properties", it->Declaration()->Node()->Start());
969         }
970     }
971 }
972 
ValidateArrayIndex(ir::Expression * const expr,bool relaxed)973 void ETSChecker::ValidateArrayIndex(ir::Expression *const expr, bool relaxed)
974 {
975     auto *const expressionType = expr->Check(this);
976     auto const *const unboxedExpressionType = ETSBuiltinTypeAsPrimitiveType(expressionType);
977 
978     Type const *const indexType = ApplyUnaryOperatorPromotion(expressionType);
979 
980     if (expressionType->IsETSObjectType() && (unboxedExpressionType != nullptr)) {
981         expr->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxedExpressionType));
982     }
983 
984     if (relaxed && indexType != nullptr && indexType->HasTypeFlag(TypeFlag::ETS_FLOATING_POINT)) {
985         if (!expr->IsNumberLiteral()) {
986             return;
987         }
988 
989         auto num = expr->AsNumberLiteral()->Number();
990         ASSERT(num.IsReal());
991         double value = num.GetDouble();
992         double intpart;
993         if (std::modf(value, &intpart) != 0.0) {
994             ThrowTypeError("Index fracional part should not be different from 0.0", expr->Start());
995         }
996         return;
997     }
998 
999     if (indexType == nullptr || !indexType->HasTypeFlag(TypeFlag::ETS_ARRAY_INDEX)) {
1000         std::stringstream message("");
1001         if (expressionType->IsNonPrimitiveType()) {
1002             message << expressionType->Variable()->Name();
1003         } else {
1004             expressionType->ToString(message);
1005         }
1006 
1007         ThrowTypeError(
1008             "Type '" + message.str() +
1009                 "' cannot be used as an index type. Only primitive or unboxable integral types can be used as index.",
1010             expr->Start());
1011     }
1012 }
1013 
GetTupleElementAccessValue(const Type * const type) const1014 int32_t ETSChecker::GetTupleElementAccessValue(const Type *const type) const
1015 {
1016     ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC));
1017 
1018     switch (ETSType(type)) {
1019         case TypeFlag::BYTE: {
1020             return type->AsByteType()->GetValue();
1021         }
1022         case TypeFlag::SHORT: {
1023             return type->AsShortType()->GetValue();
1024         }
1025         case TypeFlag::INT: {
1026             return type->AsIntType()->GetValue();
1027         }
1028         default: {
1029             UNREACHABLE();
1030         }
1031     }
1032 }
1033 
ValidateTupleIndex(const ETSTupleType * const tuple,const ir::MemberExpression * const expr)1034 void ETSChecker::ValidateTupleIndex(const ETSTupleType *const tuple, const ir::MemberExpression *const expr)
1035 {
1036     const auto *const exprType = expr->Property()->TsType();
1037     ASSERT(exprType != nullptr);
1038 
1039     if (!exprType->HasTypeFlag(TypeFlag::CONSTANT) && !tuple->HasSpreadType()) {
1040         ThrowTypeError("Only constant expression allowed for element access on tuples.", expr->Property()->Start());
1041     }
1042 
1043     if (!exprType->HasTypeFlag(TypeFlag::ETS_ARRAY_INDEX)) {
1044         ThrowTypeError("Only integer type allowed for element access on tuples.", expr->Property()->Start());
1045     }
1046 
1047     const int32_t exprValue = GetTupleElementAccessValue(exprType);
1048     if (((exprValue >= tuple->GetTupleSize()) && !tuple->HasSpreadType()) || (exprValue < 0)) {
1049         ThrowTypeError("Element accessor value is out of tuple size bounds.", expr->Property()->Start());
1050     }
1051 }
1052 
CheckThisOrSuperAccess(ir::Expression * node,ETSObjectType * classType,std::string_view msg)1053 ETSObjectType *ETSChecker::CheckThisOrSuperAccess(ir::Expression *node, ETSObjectType *classType, std::string_view msg)
1054 {
1055     if ((Context().Status() & CheckerStatus::IGNORE_VISIBILITY) != 0U) {
1056         return classType;
1057     }
1058 
1059     if (node->Parent()->IsCallExpression() && (node->Parent()->AsCallExpression()->Callee() == node)) {
1060         if (Context().ContainingSignature() == nullptr) {
1061             ThrowTypeError({"Call to '", msg, "' must be first statement in constructor"}, node->Start());
1062         }
1063 
1064         auto *sig = Context().ContainingSignature();
1065         ASSERT(sig->Function()->Body() && sig->Function()->Body()->IsBlockStatement());
1066 
1067         if (!sig->HasSignatureFlag(checker::SignatureFlags::CONSTRUCT)) {
1068             ThrowTypeError({"Call to '", msg, "' must be first statement in constructor"}, node->Start());
1069         }
1070 
1071         if (sig->Function()->Body()->AsBlockStatement()->Statements().front() != node->Parent()->Parent()) {
1072             ThrowTypeError({"Call to '", msg, "' must be first statement in constructor"}, node->Start());
1073         }
1074     }
1075 
1076     if (HasStatus(checker::CheckerStatus::IN_STATIC_CONTEXT)) {
1077         ThrowTypeError({"'", msg, "' cannot be referenced from a static context"}, node->Start());
1078     }
1079 
1080     if (classType->GetDeclNode()->IsClassDefinition() && classType->GetDeclNode()->AsClassDefinition()->IsGlobal()) {
1081         ThrowTypeError({"Cannot reference '", msg, "' in this context."}, node->Start());
1082     }
1083 
1084     return classType;
1085 }
1086 
CheckCyclicConstructorCall(Signature * signature)1087 void ETSChecker::CheckCyclicConstructorCall(Signature *signature)
1088 {
1089     ASSERT(signature->Function());
1090 
1091     if (signature->Function()->Body() == nullptr || signature->Function()->IsExternal()) {
1092         return;
1093     }
1094 
1095     auto *funcBody = signature->Function()->Body()->AsBlockStatement();
1096 
1097     TypeStackElement tse(this, signature, "Recursive constructor invocation", signature->Function()->Start());
1098 
1099     if (!funcBody->Statements().empty() && funcBody->Statements()[0]->IsExpressionStatement() &&
1100         funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
1101         funcBody->Statements()[0]
1102             ->AsExpressionStatement()
1103             ->GetExpression()
1104             ->AsCallExpression()
1105             ->Callee()
1106             ->IsThisExpression()) {
1107         auto *constructorCall = funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->AsCallExpression();
1108         ASSERT(constructorCall->Signature());
1109         CheckCyclicConstructorCall(constructorCall->Signature());
1110     }
1111 }
1112 
CheckExceptionOrErrorType(checker::Type * type,const lexer::SourcePosition pos)1113 ETSObjectType *ETSChecker::CheckExceptionOrErrorType(checker::Type *type, const lexer::SourcePosition pos)
1114 {
1115     if (!type->IsETSObjectType() || (!Relation()->IsAssignableTo(type, GlobalBuiltinExceptionType()) &&
1116                                      !Relation()->IsAssignableTo(type, GlobalBuiltinErrorType()))) {
1117         ThrowTypeError({"Argument must be an instance of '", compiler::Signatures::BUILTIN_EXCEPTION_CLASS, "' or '",
1118                         compiler::Signatures::BUILTIN_ERROR_CLASS, "'"},
1119                        pos);
1120     }
1121 
1122     return type->AsETSObjectType();
1123 }
1124 
TryToInstantiate(Type * const type,ArenaAllocator * const allocator,TypeRelation * const relation,GlobalTypesHolder * const globalTypes)1125 Type *ETSChecker::TryToInstantiate(Type *const type, ArenaAllocator *const allocator, TypeRelation *const relation,
1126                                    GlobalTypesHolder *const globalTypes)
1127 {
1128     // NOTE: Handle generic functions
1129     auto *returnType = type;
1130     const bool isIncomplete =
1131         type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INCOMPLETE_INSTANTIATION);
1132     if (const bool isFunctionType = type->IsETSFunctionType(); isFunctionType || isIncomplete) {
1133         returnType = type->Instantiate(allocator, relation, globalTypes);
1134     }
1135 
1136     return returnType;
1137 }
1138 
ValidateResolvedProperty(const varbinder::LocalVariable * const property,const ETSObjectType * const target,const ir::Identifier * const ident,const PropertySearchFlags flags)1139 void ETSChecker::ValidateResolvedProperty(const varbinder::LocalVariable *const property,
1140                                           const ETSObjectType *const target, const ir::Identifier *const ident,
1141                                           const PropertySearchFlags flags)
1142 {
1143     if (property != nullptr) {
1144         return;
1145     }
1146 
1147     using Utype = std::underlying_type_t<PropertySearchFlags>;
1148     static constexpr uint32_t CORRECT_PROPERTY_SEARCH_ORDER_INSTANCE = 7U;
1149     static_assert(static_cast<Utype>(PropertySearchFlags::SEARCH_INSTANCE) == CORRECT_PROPERTY_SEARCH_ORDER_INSTANCE,
1150                   "PropertySearchFlags order changed");
1151     static constexpr uint32_t CORRECT_PROPERTY_SEARCH_ORDER_STATIC = 56U;
1152     static_assert(static_cast<Utype>(PropertySearchFlags::SEARCH_STATIC) == CORRECT_PROPERTY_SEARCH_ORDER_STATIC,
1153                   "PropertySearchFlags order changed");
1154     const auto flagsNum = static_cast<Utype>(flags);
1155     // This algorithm swaps the first 3 bits of a number with it's consecutive 3 bits, example: 0b110001 -> 0b001110
1156     // Effectively it changes PropertySearchFlags to search for the appropriate declarations
1157     const Utype x = (flagsNum ^ (flagsNum >> 3U)) & 7U;
1158     const auto newFlags = PropertySearchFlags {flagsNum ^ (x | (x << 3U))};
1159 
1160     const auto *const newProp = target->GetProperty(ident->Name(), newFlags);
1161     if (newProp == nullptr) {
1162         ThrowTypeError({"Property '", ident->Name(), "' does not exist on type '", target->Name(), "'"},
1163                        ident->Start());
1164     }
1165     if (IsVariableStatic(newProp)) {
1166         ThrowTypeError({"'", ident->Name(), "' is a static property of '", target->Name(), "'"}, ident->Start());
1167     } else {
1168         ThrowTypeError({"'", ident->Name(), "' is an instance property of '", target->Name(), "'"}, ident->Start());
1169     }
1170 }
1171 
ResolveInstanceExtension(const ir::MemberExpression * const memberExpr)1172 varbinder::Variable *ETSChecker::ResolveInstanceExtension(const ir::MemberExpression *const memberExpr)
1173 {
1174     // clang-format off
1175     auto *globalFunctionVar = Scope()
1176                                 ->FindInGlobal(memberExpr->Property()->AsIdentifier()->Name(),
1177                                                 varbinder::ResolveBindingOptions::STATIC_METHODS)
1178                                 .variable;
1179     // clang-format on
1180 
1181     if (globalFunctionVar == nullptr || !ExtensionETSFunctionType(this->GetTypeOfVariable(globalFunctionVar))) {
1182         return nullptr;
1183     }
1184 
1185     return globalFunctionVar;
1186 }
1187 
GetInitialSearchFlags(const ir::MemberExpression * const memberExpr)1188 PropertySearchFlags ETSChecker::GetInitialSearchFlags(const ir::MemberExpression *const memberExpr)
1189 {
1190     constexpr auto FUNCTIONAL_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_FUNCTIONAL;
1191     constexpr auto GETTER_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_GETTER;
1192     constexpr auto SETTER_FLAGS = PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::IS_SETTER;
1193 
1194     switch (memberExpr->Parent()->Type()) {
1195         case ir::AstNodeType::CALL_EXPRESSION: {
1196             if (memberExpr->Parent()->AsCallExpression()->Callee() == memberExpr) {
1197                 return FUNCTIONAL_FLAGS;
1198             }
1199 
1200             break;
1201         }
1202         case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
1203             if (memberExpr->Parent()->AsETSNewClassInstanceExpression()->GetTypeRef() == memberExpr) {
1204                 return PropertySearchFlags::SEARCH_DECL;
1205             }
1206             break;
1207         }
1208         case ir::AstNodeType::MEMBER_EXPRESSION: {
1209             return PropertySearchFlags::SEARCH_FIELD | PropertySearchFlags::SEARCH_DECL | GETTER_FLAGS;
1210         }
1211         case ir::AstNodeType::UPDATE_EXPRESSION:
1212         case ir::AstNodeType::UNARY_EXPRESSION:
1213         case ir::AstNodeType::BINARY_EXPRESSION: {
1214             return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS;
1215         }
1216         case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
1217             const auto *const assignmentExpr = memberExpr->Parent()->AsAssignmentExpression();
1218 
1219             if (assignmentExpr->Left() == memberExpr) {
1220                 if (assignmentExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
1221                     return PropertySearchFlags::SEARCH_FIELD | SETTER_FLAGS;
1222                 }
1223                 return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS | SETTER_FLAGS;
1224             }
1225 
1226             auto const *targetType = assignmentExpr->Left()->TsType();
1227             if (targetType->IsETSObjectType() &&
1228                 targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
1229                 return FUNCTIONAL_FLAGS;
1230             }
1231 
1232             return PropertySearchFlags::SEARCH_FIELD | GETTER_FLAGS;
1233         }
1234         default: {
1235             break;
1236         }
1237     }
1238 
1239     return PropertySearchFlags::SEARCH_FIELD | FUNCTIONAL_FLAGS | GETTER_FLAGS;
1240 }
1241 
GetSearchFlags(const ir::MemberExpression * const memberExpr,const varbinder::Variable * targetRef)1242 PropertySearchFlags ETSChecker::GetSearchFlags(const ir::MemberExpression *const memberExpr,
1243                                                const varbinder::Variable *targetRef)
1244 {
1245     auto searchFlag = GetInitialSearchFlags(memberExpr);
1246     searchFlag |= PropertySearchFlags::SEARCH_IN_BASE | PropertySearchFlags::SEARCH_IN_INTERFACES;
1247 
1248     if (targetRef != nullptr && targetRef->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE)) {
1249         searchFlag &= ~(PropertySearchFlags::SEARCH_INSTANCE);
1250     } else if (memberExpr->Object()->IsThisExpression() ||
1251                (memberExpr->Object()->IsIdentifier() && memberExpr->ObjType()->GetDeclNode() != nullptr &&
1252                 memberExpr->ObjType()->GetDeclNode()->IsTSInterfaceDeclaration())) {
1253         searchFlag &= ~(PropertySearchFlags::SEARCH_STATIC);
1254     }
1255     return searchFlag;
1256 }
1257 
GetTargetRef(const ir::MemberExpression * const memberExpr)1258 const varbinder::Variable *ETSChecker::GetTargetRef(const ir::MemberExpression *const memberExpr)
1259 {
1260     if (memberExpr->Object()->IsIdentifier()) {
1261         return memberExpr->Object()->AsIdentifier()->Variable();
1262     }
1263     if (memberExpr->Object()->IsMemberExpression()) {
1264         return memberExpr->Object()->AsMemberExpression()->PropVar();
1265     }
1266     return nullptr;
1267 }
1268 
ValidateGetterSetter(const ir::MemberExpression * const memberExpr,const varbinder::LocalVariable * const prop,PropertySearchFlags searchFlag)1269 void ETSChecker::ValidateGetterSetter(const ir::MemberExpression *const memberExpr,
1270                                       const varbinder::LocalVariable *const prop, PropertySearchFlags searchFlag)
1271 {
1272     auto *propType = prop->TsType()->AsETSFunctionType();
1273     ASSERT((propType->FindGetter() != nullptr) == propType->HasTypeFlag(TypeFlag::GETTER));
1274     ASSERT((propType->FindSetter() != nullptr) == propType->HasTypeFlag(TypeFlag::SETTER));
1275 
1276     auto const &sourcePos = memberExpr->Property()->Start();
1277     auto callExpr = memberExpr->Parent()->IsCallExpression() ? memberExpr->Parent()->AsCallExpression() : nullptr;
1278 
1279     if ((searchFlag & PropertySearchFlags::IS_GETTER) != 0) {
1280         if (!propType->HasTypeFlag(TypeFlag::GETTER)) {
1281             ThrowTypeError("Cannot read from this property because it is writeonly.", sourcePos);
1282         }
1283         ValidateSignatureAccessibility(memberExpr->ObjType(), callExpr, propType->FindGetter(), sourcePos);
1284     }
1285 
1286     if ((searchFlag & PropertySearchFlags::IS_SETTER) != 0) {
1287         if (!propType->HasTypeFlag(TypeFlag::SETTER)) {
1288             ThrowTypeError("Cannot assign to this property because it is readonly.", sourcePos);
1289         }
1290         ValidateSignatureAccessibility(memberExpr->ObjType(), callExpr, propType->FindSetter(), sourcePos);
1291     }
1292 }
1293 
ValidateVarDeclaratorOrClassProperty(const ir::MemberExpression * const memberExpr,varbinder::LocalVariable * const prop)1294 void ETSChecker::ValidateVarDeclaratorOrClassProperty(const ir::MemberExpression *const memberExpr,
1295                                                       varbinder::LocalVariable *const prop)
1296 {
1297     const auto [target_ident,
1298                 type_annotation] = [memberExpr]() -> std::pair<const ir::Identifier *, const ir::TypeNode *> {
1299         if (memberExpr->Parent()->IsVariableDeclarator()) {
1300             const auto *const ident = memberExpr->Parent()->AsVariableDeclarator()->Id()->AsIdentifier();
1301             return {ident, ident->TypeAnnotation()};
1302         }
1303         return {memberExpr->Parent()->AsClassProperty()->Key()->AsIdentifier(),
1304                 memberExpr->Parent()->AsClassProperty()->TypeAnnotation()};
1305     }();
1306 
1307     GetTypeOfVariable(prop);
1308 
1309     if (prop->TsType()->IsETSFunctionType() && !IsVariableGetterSetter(prop)) {
1310         if (type_annotation == nullptr) {
1311             ThrowTypeError({"Cannot infer type for ", target_ident->Name(),
1312                             " because method reference needs an explicit target type"},
1313                            target_ident->Start());
1314         }
1315 
1316         auto *targetType = GetTypeOfVariable(target_ident->Variable());
1317         ASSERT(targetType != nullptr);
1318 
1319         if (!targetType->IsETSObjectType() ||
1320             !targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
1321             ThrowTypeError({"Method ", memberExpr->Property()->AsIdentifier()->Name(), " does not exist on this type."},
1322                            memberExpr->Property()->Start());
1323         }
1324     }
1325 }
1326 
1327 // NOLINTNEXTLINE(readability-function-size)
ResolveMemberReference(const ir::MemberExpression * const memberExpr,const ETSObjectType * const target)1328 std::vector<ResolveResult *> ETSChecker::ResolveMemberReference(const ir::MemberExpression *const memberExpr,
1329                                                                 const ETSObjectType *const target)
1330 {
1331     std::vector<ResolveResult *> resolveRes {};
1332 
1333     if (target->IsETSDynamicType() && !target->AsETSDynamicType()->HasDecl()) {
1334         auto propName = memberExpr->Property()->AsIdentifier()->Name();
1335         varbinder::LocalVariable *propVar = target->AsETSDynamicType()->GetPropertyDynamic(propName, this);
1336         resolveRes.emplace_back(Allocator()->New<ResolveResult>(propVar, ResolvedKind::PROPERTY));
1337         return resolveRes;
1338     }
1339 
1340     const auto *const targetRef = GetTargetRef(memberExpr);
1341     auto searchFlag = GetSearchFlags(memberExpr, targetRef);
1342 
1343     if (target->HasTypeFlag(TypeFlag::GENERIC)) {
1344         searchFlag |= PropertySearchFlags::SEARCH_ALL;
1345     }
1346 
1347     auto *const prop = target->GetProperty(memberExpr->Property()->AsIdentifier()->Name(), searchFlag);
1348     varbinder::Variable *globalFunctionVar = nullptr;
1349 
1350     if (memberExpr->Parent()->IsCallExpression() && memberExpr->Parent()->AsCallExpression()->Callee() == memberExpr) {
1351         globalFunctionVar = ResolveInstanceExtension(memberExpr);
1352     }
1353 
1354     if (globalFunctionVar == nullptr ||
1355         (targetRef != nullptr && targetRef->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE))) {
1356         /*
1357             Instance extension function can only be called by class instance, if a property is accessed by
1358             CLASS or INTERFACE type, it couldn't be an instance extension function call
1359 
1360             Example code:
1361                 class A {}
1362                 static function A.xxx() {}
1363                 function main() {
1364                     A.xxx()
1365                 }
1366 
1367             !NB: When supporting static extension function, the above code case would be supported
1368         */
1369         ValidateResolvedProperty(prop, target, memberExpr->Property()->AsIdentifier(), searchFlag);
1370     } else {
1371         resolveRes.emplace_back(
1372             Allocator()->New<ResolveResult>(globalFunctionVar, ResolvedKind::INSTANCE_EXTENSION_FUNCTION));
1373 
1374         if (prop == nullptr) {
1375             // No matched property, but have possible matched global extension function
1376             return resolveRes;
1377         }
1378     }
1379 
1380     resolveRes.emplace_back(Allocator()->New<ResolveResult>(prop, ResolvedKind::PROPERTY));
1381 
1382     if (prop->HasFlag(varbinder::VariableFlags::METHOD) && !IsVariableGetterSetter(prop) &&
1383         (searchFlag & PropertySearchFlags::IS_FUNCTIONAL) == 0) {
1384         ThrowTypeError("Method used in wrong context", memberExpr->Property()->Start());
1385     }
1386 
1387     if (IsVariableGetterSetter(prop)) {
1388         ValidateGetterSetter(memberExpr, prop, searchFlag);
1389     }
1390 
1391     // Before returning the computed property variable, we have to validate the special case where we are in a variable
1392     // declaration, and the properties type is a function type but the currently declared variable doesn't have a type
1393     // annotation
1394     if (memberExpr->Parent()->IsVariableDeclarator() || memberExpr->Parent()->IsClassProperty()) {
1395         ValidateVarDeclaratorOrClassProperty(memberExpr, prop);
1396     }
1397 
1398     return resolveRes;
1399 }
1400 
CheckValidInheritance(ETSObjectType * classType,ir::ClassDefinition * classDef)1401 void ETSChecker::CheckValidInheritance(ETSObjectType *classType, ir::ClassDefinition *classDef)
1402 {
1403     if (classType->SuperType() == nullptr) {
1404         return;
1405     }
1406 
1407     if (classDef->TypeParams() != nullptr &&
1408         (Relation()->IsAssignableTo(classType->SuperType(), GlobalBuiltinExceptionType()) ||
1409          Relation()->IsAssignableTo(classType->SuperType(), GlobalBuiltinErrorType()))) {
1410         ThrowTypeError({"Generics are not allowed as '", compiler::Signatures::BUILTIN_EXCEPTION_CLASS, "' or '",
1411                         compiler::Signatures::BUILTIN_ERROR_CLASS, "' subclasses."},
1412                        classDef->TypeParams()->Start());
1413     }
1414 
1415     const auto &allProps = classType->GetAllProperties();
1416 
1417     for (auto *it : allProps) {
1418         const auto searchFlag = PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE |
1419                                 PropertySearchFlags::SEARCH_IN_INTERFACES |
1420                                 PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION;
1421         auto *found = classType->SuperType()->GetProperty(it->Name(), searchFlag);
1422 
1423         ETSObjectType *interfaceFound = nullptr;
1424         if (found == nullptr) {
1425             auto interfaceList = GetInterfacesOfClass(classType);
1426             for (auto *interface : interfaceList) {
1427                 auto *propertyFound = interface->GetProperty(it->Name(), searchFlag);
1428                 if (propertyFound == nullptr) {
1429                     continue;
1430                 }
1431                 found = propertyFound;
1432                 interfaceFound = interface;
1433                 break;
1434             }
1435         }
1436         if (found == nullptr) {
1437             continue;
1438         }
1439 
1440         if (!IsSameDeclarationType(it, found)) {
1441             const char *targetType {};
1442 
1443             if (it->HasFlag(varbinder::VariableFlags::PROPERTY)) {
1444                 targetType = "field";
1445             } else if (it->HasFlag(varbinder::VariableFlags::METHOD)) {
1446                 targetType = "method";
1447             } else if (it->HasFlag(varbinder::VariableFlags::CLASS)) {
1448                 targetType = "class";
1449             } else if (it->HasFlag(varbinder::VariableFlags::INTERFACE)) {
1450                 targetType = "interface";
1451             } else {
1452                 targetType = "enum";
1453             }
1454 
1455             if (interfaceFound != nullptr) {
1456                 ThrowTypeError({"Cannot inherit from interface ", interfaceFound->Name(), " because ", targetType, " ",
1457                                 it->Name(), " is inherited with a different declaration type"},
1458                                interfaceFound->GetDeclNode()->Start());
1459             }
1460             ThrowTypeError({"Cannot inherit from class ", classType->SuperType()->Name(), ", because ", targetType, " ",
1461                             it->Name(), " is inherited with a different declaration type"},
1462                            classDef->Super()->Start());
1463         }
1464     }
1465 }
1466 
CheckGetterSetterProperties(ETSObjectType * classType)1467 void ETSChecker::CheckGetterSetterProperties(ETSObjectType *classType)
1468 {
1469     auto const checkGetterSetter = [this](varbinder::LocalVariable *var, util::StringView name) {
1470         auto const *type = var->TsType()->AsETSFunctionType();
1471         auto const *sigGetter = type->FindGetter();
1472         auto const *sigSetter = type->FindSetter();
1473 
1474         for (auto const *sig : type->CallSignatures()) {
1475             if (!sig->Function()->IsGetter() && !sig->Function()->IsSetter()) {
1476                 ThrowTypeError({"Method cannot use the same name as ", name, " accessor property"},
1477                                sig->Function()->Start());
1478             }
1479             if (sig != sigGetter && sig != sigSetter) {
1480                 ThrowTypeError("Duplicate accessor definition", sig->Function()->Start());
1481             }
1482         }
1483 
1484         if (((sigGetter->Function()->Modifiers() ^ sigSetter->Function()->Modifiers()) &
1485              ir::ModifierFlags::ACCESSOR_MODIFIERS) != 0) {
1486             ThrowTypeError("Getter and setter methods must have the same accessor modifiers",
1487                            sigGetter->Function()->Start());
1488         }
1489     };
1490 
1491     for (const auto &[name, var] : classType->InstanceMethods()) {
1492         if (IsVariableGetterSetter(var)) {
1493             checkGetterSetter(var, name);
1494         }
1495     }
1496 
1497     for (const auto &[name, var] : classType->StaticMethods()) {
1498         if (IsVariableGetterSetter(var)) {
1499             checkGetterSetter(var, name);
1500         }
1501     }
1502 }
1503 
AddElementsToModuleObject(ETSObjectType * moduleObj,const util::StringView & str)1504 void ETSChecker::AddElementsToModuleObject(ETSObjectType *moduleObj, const util::StringView &str)
1505 {
1506     for (const auto &[name, var] : VarBinder()->GetScope()->Bindings()) {
1507         if (name.Is(str.Mutf8()) || name.Is(compiler::Signatures::ETS_GLOBAL)) {
1508             continue;
1509         }
1510 
1511         if (var->HasFlag(varbinder::VariableFlags::METHOD)) {
1512             moduleObj->AddProperty<checker::PropertyType::STATIC_METHOD>(var->AsLocalVariable());
1513         } else if (var->HasFlag(varbinder::VariableFlags::PROPERTY)) {
1514             moduleObj->AddProperty<checker::PropertyType::STATIC_FIELD>(var->AsLocalVariable());
1515         } else {
1516             moduleObj->AddProperty<checker::PropertyType::STATIC_DECL>(var->AsLocalVariable());
1517         }
1518     }
1519 }
1520 
FindLeastUpperBound(Type * source,Type * target)1521 Type *ETSChecker::FindLeastUpperBound(Type *source, Type *target)
1522 {
1523     ASSERT(source->HasTypeFlag(TypeFlag::ETS_ARRAY_OR_OBJECT) && target->HasTypeFlag(TypeFlag::ETS_ARRAY_OR_OBJECT));
1524 
1525     // GetCommonClass(GenA<A>, GenB<B>) => LUB(GenA, GenB)<T>
1526     auto commonClass = GetCommonClass(source, target);
1527     if (!commonClass->IsETSObjectType() || !commonClass->HasTypeFlag(TypeFlag::GENERIC)) {
1528         return commonClass->HasTypeFlag(TypeFlag::CONSTANT) ? commonClass->Variable()->TsType() : commonClass;
1529     }
1530 
1531     // GetRelevantArgumentedTypeFromChild(GenA<A>, LUB(GenA, GenB)<T>) => LUB(GenA, GenB)<A>
1532     ETSObjectType *relevantSourceType =
1533         GetRelevantArgumentedTypeFromChild(source->AsETSObjectType(), commonClass->AsETSObjectType());
1534     ETSObjectType *relevantTargetType =
1535         GetRelevantArgumentedTypeFromChild(target->AsETSObjectType(), commonClass->AsETSObjectType());
1536 
1537     // GetTypeargumentedLUB(LUB(GenA, GenB)<A>, LUB(GenA, GenB)<B>) => LUB(GenA, GenB)<LUB(A, B)>
1538     return GetTypeargumentedLUB(relevantSourceType, relevantTargetType);
1539 }
1540 
GetApparentType(Type * type)1541 Type *ETSChecker::GetApparentType(Type *type)
1542 {
1543     while (type->IsETSTypeParameter()) {
1544         type = type->AsETSTypeParameter()->GetConstraintType();
1545     }
1546     return type;
1547 }
1548 
GetApparentType(Type const * type)1549 Type const *ETSChecker::GetApparentType(Type const *type)
1550 {
1551     while (type->IsETSTypeParameter()) {
1552         type = type->AsETSTypeParameter()->GetConstraintType();
1553     }
1554     return type;
1555 }
1556 
MaybePromotedBuiltinType(Type * type) const1557 Type *ETSChecker::MaybePromotedBuiltinType(Type *type) const
1558 {
1559     return type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) ? checker::BoxingConverter::ETSTypeFromSource(this, type) : type;
1560 }
1561 
GetCommonClass(Type * source,Type * target)1562 Type *ETSChecker::GetCommonClass(Type *source, Type *target)
1563 {
1564     SavedTypeRelationFlagsContext checkerCtx(this->Relation(), TypeRelationFlag::IGNORE_TYPE_PARAMETERS);
1565 
1566     if (IsTypeIdenticalTo(source, target)) {
1567         return source;
1568     }
1569 
1570     if (Relation()->IsSupertypeOf(target, source)) {
1571         return target;
1572     }
1573 
1574     if (Relation()->IsSupertypeOf(source, target)) {
1575         return source;
1576     }
1577 
1578     if (source->IsETSObjectType() && target->IsETSObjectType()) {
1579         if (source->IsETSNullLike()) {
1580             return target;
1581         }
1582 
1583         if (target->IsETSNullLike()) {
1584             return source;
1585         }
1586 
1587         if (source->AsETSObjectType()->GetDeclNode() == target->AsETSObjectType()->GetDeclNode()) {
1588             return source;
1589         }
1590 
1591         return GetClosestCommonAncestor(source->AsETSObjectType(), target->AsETSObjectType());
1592     }
1593 
1594     return GlobalETSObjectType();
1595 }
1596 
GetClosestCommonAncestor(ETSObjectType * source,ETSObjectType * target)1597 ETSObjectType *ETSChecker::GetClosestCommonAncestor(ETSObjectType *source, ETSObjectType *target)
1598 {
1599     ASSERT(target->SuperType() != nullptr);
1600 
1601     auto *targetBase = GetOriginalBaseType(target->SuperType());
1602     auto *targetType = targetBase == nullptr ? target->SuperType() : targetBase;
1603 
1604     auto *sourceBase = GetOriginalBaseType(source);
1605     auto *sourceType = sourceBase == nullptr ? source : sourceBase;
1606 
1607     if (Relation()->IsSupertypeOf(targetType, sourceType)) {
1608         // NOTE: TorokG. Extending the search to find intersection types
1609         return targetType;
1610     }
1611 
1612     return GetClosestCommonAncestor(sourceType, targetType);
1613 }
1614 
GetTypeargumentedLUB(ETSObjectType * const source,ETSObjectType * const target)1615 ETSObjectType *ETSChecker::GetTypeargumentedLUB(ETSObjectType *const source, ETSObjectType *const target)
1616 {
1617     ASSERT(source->TypeArguments().size() == target->TypeArguments().size());
1618 
1619     ArenaVector<Type *> params(Allocator()->Adapter());
1620 
1621     for (uint32_t i = 0; i < source->TypeArguments().size(); i++) {
1622         params.push_back(FindLeastUpperBound(source->TypeArguments()[i], target->TypeArguments()[i]));
1623     }
1624 
1625     const util::StringView hash = GetHashFromTypeArguments(params);
1626 
1627     if (!source->GetDeclNode()->IsClassDefinition()) {
1628         return source;
1629     }
1630 
1631     ETSObjectType *templateType = source->GetDeclNode()->AsClassDefinition()->TsType()->AsETSObjectType();
1632 
1633     auto *lubType = templateType->GetInstantiatedType(hash);
1634 
1635     if (lubType == nullptr) {
1636         lubType = templateType->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsETSObjectType();
1637         lubType->SetTypeArguments(std::move(params));
1638 
1639         templateType->GetInstantiationMap().try_emplace(hash, lubType);
1640     }
1641 
1642     return lubType;
1643 }
1644 
CheckInvokeMethodsLegitimacy(ETSObjectType * const classType)1645 void ETSChecker::CheckInvokeMethodsLegitimacy(ETSObjectType *const classType)
1646 {
1647     if (classType->HasObjectFlag(ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY)) {
1648         return;
1649     }
1650 
1651     auto searchFlag = PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::SEARCH_IN_BASE |
1652                       PropertySearchFlags::SEARCH_STATIC_METHOD;
1653 
1654     auto *const invokeMethod = classType->GetProperty(compiler::Signatures::STATIC_INVOKE_METHOD, searchFlag);
1655     if (invokeMethod == nullptr) {
1656         classType->AddObjectFlag(ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
1657         return;
1658     }
1659 
1660     auto *const instantiateMethod = classType->GetProperty(compiler::Signatures::STATIC_INSTANTIATE_METHOD, searchFlag);
1661     if (instantiateMethod != nullptr) {
1662         ThrowTypeError({"Static ", compiler::Signatures::STATIC_INVOKE_METHOD, " method and static ",
1663                         compiler::Signatures::STATIC_INSTANTIATE_METHOD, " method both exist in class/interface ",
1664                         classType->Name(), " is not allowed."},
1665                        classType->GetDeclNode()->Start());
1666     }
1667     classType->AddObjectFlag(ETSObjectFlags::CHECKED_INVOKE_LEGITIMACY);
1668 }
1669 }  // namespace panda::es2panda::checker
1670