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