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