• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "compiler/lowering/scopesInit/scopesInitPhase.h"
17 #include "varbinder/variableFlags.h"
18 #include "checker/checker.h"
19 #include "checker/checkerContext.h"
20 #include "checker/ets/narrowingWideningConverter.h"
21 #include "checker/types/globalTypesHolder.h"
22 #include "checker/types/ets/etsObjectType.h"
23 #include "ir/astNode.h"
24 #include "lexer/token/tokenType.h"
25 #include "ir/base/catchClause.h"
26 #include "ir/expression.h"
27 #include "ir/typeNode.h"
28 #include "ir/base/scriptFunction.h"
29 #include "ir/base/classProperty.h"
30 #include "ir/base/methodDefinition.h"
31 #include "ir/statements/blockStatement.h"
32 #include "ir/statements/classDeclaration.h"
33 #include "ir/statements/variableDeclarator.h"
34 #include "ir/statements/switchCaseStatement.h"
35 #include "ir/expressions/identifier.h"
36 #include "ir/expressions/arrayExpression.h"
37 #include "ir/expressions/objectExpression.h"
38 #include "ir/expressions/callExpression.h"
39 #include "ir/expressions/memberExpression.h"
40 #include "ir/expressions/literals/booleanLiteral.h"
41 #include "ir/expressions/literals/charLiteral.h"
42 #include "ir/expressions/binaryExpression.h"
43 #include "ir/expressions/assignmentExpression.h"
44 #include "ir/expressions/arrowFunctionExpression.h"
45 #include "ir/expressions/literals/numberLiteral.h"
46 #include "ir/expressions/literals/undefinedLiteral.h"
47 #include "ir/expressions/literals/nullLiteral.h"
48 #include "ir/statements/labelledStatement.h"
49 #include "ir/statements/tryStatement.h"
50 #include "ir/ets/etsFunctionType.h"
51 #include "ir/ets/etsNewClassInstanceExpression.h"
52 #include "ir/ets/etsParameterExpression.h"
53 #include "ir/ts/tsAsExpression.h"
54 #include "ir/ts/tsTypeAliasDeclaration.h"
55 #include "ir/ts/tsEnumMember.h"
56 #include "ir/ts/tsTypeParameter.h"
57 #include "ir/ets/etsTypeReference.h"
58 #include "ir/ets/etsTypeReferencePart.h"
59 #include "ir/ets/etsPrimitiveType.h"
60 #include "ir/ts/tsQualifiedName.h"
61 #include "varbinder/variable.h"
62 #include "varbinder/scope.h"
63 #include "varbinder/declaration.h"
64 #include "parser/ETSparser.h"
65 #include "parser/program/program.h"
66 #include "checker/ETSchecker.h"
67 #include "varbinder/ETSBinder.h"
68 #include "checker/ets/typeRelationContext.h"
69 #include "checker/ets/boxingConverter.h"
70 #include "checker/ets/unboxingConverter.h"
71 #include "checker/types/ets/types.h"
72 #include "util/helpers.h"
73 
74 namespace panda::es2panda::checker {
CheckTruthinessOfType(ir::Expression * expr)75 void ETSChecker::CheckTruthinessOfType(ir::Expression *expr)
76 {
77     checker::Type *type = expr->Check(this);
78     auto *unboxedType = ETSBuiltinTypeAsConditionalType(type);
79 
80     if (unboxedType == nullptr) {
81         ThrowTypeError("Condition must be of possible condition type", expr->Start());
82     }
83 
84     if (unboxedType == GlobalBuiltinVoidType() || unboxedType->IsETSVoidType()) {
85         ThrowTypeError("An expression of type 'void' cannot be tested for truthiness", expr->Start());
86     }
87 
88     if (!unboxedType->IsConditionalExprType()) {
89         ThrowTypeError("Condition must be of possible condition type", expr->Start());
90     }
91 
92     if (unboxedType != nullptr && unboxedType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
93         FlagExpressionWithUnboxing(type, unboxedType, expr);
94     }
95     expr->SetTsType(unboxedType);
96 }
97 
98 // NOTE: vpukhov. this entire function is isolated work-around until nullish type are not unions
CreateNullishType(Type * type,checker::TypeFlag nullishFlags,ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)99 Type *ETSChecker::CreateNullishType(Type *type, checker::TypeFlag nullishFlags, ArenaAllocator *allocator,
100                                     TypeRelation *relation, GlobalTypesHolder *globalTypes)
101 {
102     ASSERT((nullishFlags & ~TypeFlag::NULLISH) == 0);
103 
104     auto *const nullish = type->Instantiate(allocator, relation, globalTypes);
105 
106     // Doesnt work for primitive array types, because instantiated type is equal to original one
107 
108     if ((nullishFlags & TypeFlag::NULL_TYPE) != 0) {
109         nullish->AddTypeFlag(checker::TypeFlag::NULL_TYPE);
110     }
111     if ((nullishFlags & TypeFlag::UNDEFINED) != 0) {
112         nullish->AddTypeFlag(checker::TypeFlag::UNDEFINED);
113         if (nullish->IsETSObjectType()) {
114             nullish->AsETSObjectType()->SetAssemblerName(GlobalETSObjectType()->AssemblerName());
115         }
116     }
117     ASSERT(!nullish->HasTypeFlag(TypeFlag::ETS_PRIMITIVE));
118     return nullish;
119 }
120 
CheckNonNullishType(Type * type,lexer::SourcePosition lineInfo)121 void ETSChecker::CheckNonNullishType([[maybe_unused]] Type *type, [[maybe_unused]] lexer::SourcePosition lineInfo)
122 {
123     // NOTE: vpukhov. enable check when type inference is implemented
124     (void)type;
125 }
126 
127 // NOTE: vpukhov. rewrite with union types
GetNonNullishType(Type * type) const128 Type *ETSChecker::GetNonNullishType(Type *type) const
129 {
130     if (type->IsETSArrayType()) {
131         return type;  // give up
132     }
133     if (type->IsETSTypeParameter()) {
134         return type->AsETSTypeParameter()->GetOriginal();
135     }
136 
137     while (type->IsNullish()) {
138         type = type->AsETSObjectType()->GetBaseType();
139         ASSERT(type != nullptr);
140     }
141     return type;
142 }
143 
144 // NOTE: vpukhov. rewrite with union types
GetNonNullishType(const Type * type) const145 const Type *ETSChecker::GetNonNullishType(const Type *type) const
146 {
147     if (type->IsETSArrayType()) {
148         return type;  // give up
149     }
150     if (type->IsETSTypeParameter()) {
151         return type->AsETSTypeParameter()->GetOriginal();
152     }
153 
154     while (type->IsNullish()) {
155         type = type->AsETSObjectType()->GetBaseType();
156         ASSERT(type != nullptr);
157     }
158     return type;
159 }
160 
CreateOptionalResultType(Type * type)161 Type *ETSChecker::CreateOptionalResultType(Type *type)
162 {
163     if (type->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
164         type = PrimitiveTypeAsETSBuiltinType(type);
165         ASSERT(type->IsETSObjectType());
166         Relation()->GetNode()->AddBoxingUnboxingFlags(GetBoxingFlag(type));
167     }
168 
169     return CreateNullishType(type, checker::TypeFlag::UNDEFINED, Allocator(), Relation(), GetGlobalTypesHolder());
170 }
171 
172 // NOTE(vpukhov): #14595 could be implemented with relation
173 template <typename P>
MatchConstitutentOrConstraint(P const & pred,const Type * type)174 static bool MatchConstitutentOrConstraint(P const &pred, const Type *type)
175 {
176     if (pred(type)) {
177         return true;
178     }
179     if (type->IsETSUnionType()) {
180         for (auto const &ctype : type->AsETSUnionType()->ConstituentTypes()) {
181             if (MatchConstitutentOrConstraint(pred, ctype)) {
182                 return true;
183             }
184         }
185         return false;
186     }
187     if (type->IsETSTypeParameter()) {
188         return MatchConstitutentOrConstraint(pred, type->AsETSTypeParameter()->GetConstraintType());
189     }
190     return false;
191 }
192 
MayHaveNullValue(const Type * type) const193 bool ETSChecker::MayHaveNullValue(const Type *type) const
194 {
195     const auto pred = [](const Type *t) { return t->ContainsNull() || t->IsETSNullType(); };
196     return MatchConstitutentOrConstraint(pred, type);
197 }
198 
MayHaveUndefinedValue(const Type * type) const199 bool ETSChecker::MayHaveUndefinedValue(const Type *type) const
200 {
201     const auto pred = [](const Type *t) { return t->ContainsUndefined() || t->IsETSUndefinedType(); };
202     return MatchConstitutentOrConstraint(pred, type);
203 }
204 
MayHaveNulllikeValue(const Type * type) const205 bool ETSChecker::MayHaveNulllikeValue(const Type *type) const
206 {
207     const auto pred = [](const Type *t) { return t->IsNullishOrNullLike(); };
208     return MatchConstitutentOrConstraint(pred, type);
209 }
210 
IsConstantExpression(ir::Expression * expr,Type * type)211 bool ETSChecker::IsConstantExpression(ir::Expression *expr, Type *type)
212 {
213     return (type->HasTypeFlag(TypeFlag::CONSTANT) && (expr->IsIdentifier() || expr->IsMemberExpression()));
214 }
215 
GetNonConstantTypeFromPrimitiveType(Type * type)216 Type *ETSChecker::GetNonConstantTypeFromPrimitiveType(Type *type)
217 {
218     if (type->IsETSStringType()) {
219         // NOTE: vpukhov. remove when nullish types are unions
220         ASSERT(!type->IsNullish());
221         return GlobalBuiltinETSStringType();
222     }
223 
224     if (!type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
225         return type;
226     }
227 
228     // NOTE: vpukhov. remove when nullish types are unions
229     ASSERT(!type->IsNullish());
230 
231     if (type->HasTypeFlag(TypeFlag::LONG)) {
232         return GlobalLongType();
233     }
234 
235     if (type->HasTypeFlag(TypeFlag::BYTE)) {
236         return GlobalByteType();
237     }
238 
239     if (type->HasTypeFlag(TypeFlag::SHORT)) {
240         return GlobalShortType();
241     }
242 
243     if (type->HasTypeFlag(TypeFlag::CHAR)) {
244         return GlobalCharType();
245     }
246 
247     if (type->HasTypeFlag(TypeFlag::INT)) {
248         return GlobalIntType();
249     }
250 
251     if (type->HasTypeFlag(TypeFlag::FLOAT)) {
252         return GlobalFloatType();
253     }
254 
255     if (type->HasTypeFlag(TypeFlag::DOUBLE)) {
256         return GlobalDoubleType();
257     }
258 
259     if (type->IsETSBooleanType()) {
260         return GlobalETSBooleanType();
261     }
262     return type;
263 }
264 
GetTypeOfVariable(varbinder::Variable * const var)265 Type *ETSChecker::GetTypeOfVariable(varbinder::Variable *const var)
266 {
267     if (IsVariableGetterSetter(var)) {
268         auto *propType = var->TsType()->AsETSFunctionType();
269         if (propType->HasTypeFlag(checker::TypeFlag::GETTER)) {
270             return propType->FindGetter()->ReturnType();
271         }
272         return propType->FindSetter()->Params()[0]->TsType();
273     }
274 
275     if (var->TsType() != nullptr) {
276         return var->TsType();
277     }
278 
279     // NOTE: kbaladurin. forbid usage of imported entities as types without declarations
280     if (VarBinder()->AsETSBinder()->IsDynamicModuleVariable(var)) {
281         auto *importData = VarBinder()->AsETSBinder()->DynamicImportDataForVar(var);
282         if (importData->import->IsPureDynamic()) {
283             return GlobalBuiltinDynamicType(importData->import->Language());
284         }
285     }
286 
287     varbinder::Decl *decl = var->Declaration();
288 
289     // Before computing the given variables type, we have to make a new checker context frame so that the checking is
290     // done in the proper context, and have to enter the scope where the given variable is declared, so reference
291     // resolution works properly
292     checker::SavedCheckerContext savedContext(this, CheckerStatus::NO_OPTS);
293     checker::ScopeContext scopeCtx(this, var->GetScope());
294     auto *iter = decl->Node()->Parent();
295     while (iter != nullptr) {
296         if (iter->IsMethodDefinition()) {
297             auto *methodDef = iter->AsMethodDefinition();
298             ASSERT(methodDef->TsType());
299             Context().SetContainingSignature(methodDef->Function()->Signature());
300         }
301 
302         if (iter->IsClassDefinition()) {
303             auto *classDef = iter->AsClassDefinition();
304             ETSObjectType *containingClass {};
305 
306             if (classDef->TsType() == nullptr) {
307                 containingClass = BuildClassProperties(classDef);
308             } else {
309                 containingClass = classDef->TsType()->AsETSObjectType();
310             }
311 
312             ASSERT(classDef->TsType());
313             Context().SetContainingClass(containingClass);
314         }
315 
316         iter = iter->Parent();
317     }
318 
319     switch (decl->Type()) {
320         case varbinder::DeclType::CLASS: {
321             auto *classDef = decl->Node()->AsClassDefinition();
322             BuildClassProperties(classDef);
323             return classDef->TsType();
324         }
325         case varbinder::DeclType::ENUM_LITERAL:
326         case varbinder::DeclType::CONST:
327         case varbinder::DeclType::LET:
328         case varbinder::DeclType::VAR: {
329             auto *declNode = decl->Node();
330 
331             if (decl->Node()->IsIdentifier()) {
332                 declNode = declNode->Parent();
333             }
334 
335             return declNode->Check(this);
336         }
337         case varbinder::DeclType::FUNC: {
338             return decl->Node()->Check(this);
339         }
340         case varbinder::DeclType::IMPORT: {
341             return decl->Node()->Check(this);
342         }
343         case varbinder::DeclType::TYPE_ALIAS: {
344             return GetTypeFromTypeAliasReference(var);
345         }
346         case varbinder::DeclType::INTERFACE: {
347             return BuildInterfaceProperties(decl->Node()->AsTSInterfaceDeclaration());
348         }
349         default: {
350             UNREACHABLE();
351         }
352     }
353 
354     return var->TsType();
355 }
356 
357 // Determine if unchecked cast is needed and yield guaranteed source type
GuaranteedTypeForUncheckedCast(Type * base,Type * substituted)358 Type *ETSChecker::GuaranteedTypeForUncheckedCast(Type *base, Type *substituted)
359 {
360     if (!base->IsETSTypeParameter()) {
361         return nullptr;
362     }
363     auto *constr = base->AsETSTypeParameter()->GetConstraintType();
364     // Constraint is supertype of TypeArg AND TypeArg is supertype of Constraint
365     return Relation()->IsIdenticalTo(substituted, constr) ? nullptr : constr;
366 }
367 
368 // Determine if substituted property access requires cast from erased type
GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable * const prop)369 Type *ETSChecker::GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable *const prop)
370 {
371     if (IsVariableStatic(prop)) {
372         return nullptr;
373     }
374     if (IsVariableGetterSetter(prop)) {
375         auto *method = prop->TsType()->AsETSFunctionType();
376         if (!method->HasTypeFlag(checker::TypeFlag::GETTER)) {
377             return nullptr;
378         }
379         return GuaranteedTypeForUncheckedCallReturn(method->FindGetter());
380     }
381     // NOTE(vpukhov): mark ETSDynamicType properties
382     if (prop->Declaration() == nullptr || prop->Declaration()->Node() == nullptr) {
383         return nullptr;
384     }
385 
386     auto *baseProp = prop->Declaration()->Node()->AsClassProperty()->Id()->Variable();
387     if (baseProp == prop) {
388         return nullptr;
389     }
390     return GuaranteedTypeForUncheckedCast(GetTypeOfVariable(baseProp), GetTypeOfVariable(prop));
391 }
392 
393 // Determine if substituted method cast requires cast from erased type
GuaranteedTypeForUncheckedCallReturn(Signature * sig)394 Type *ETSChecker::GuaranteedTypeForUncheckedCallReturn(Signature *sig)
395 {
396     if (sig->HasSignatureFlag(checker::SignatureFlags::THIS_RETURN_TYPE)) {
397         return sig->ReturnType();
398     }
399     auto *baseSig = sig->Function()->Signature();
400     if (baseSig == sig) {
401         return nullptr;
402     }
403     return GuaranteedTypeForUncheckedCast(baseSig->ReturnType(), sig->ReturnType());
404 }
405 
ValidatePropertyAccess(varbinder::Variable * var,ETSObjectType * obj,const lexer::SourcePosition & pos)406 void ETSChecker::ValidatePropertyAccess(varbinder::Variable *var, ETSObjectType *obj, const lexer::SourcePosition &pos)
407 {
408     if ((Context().Status() & CheckerStatus::IGNORE_VISIBILITY) != 0U) {
409         return;
410     }
411     if (var->HasFlag(varbinder::VariableFlags::METHOD)) {
412         return;
413     }
414 
415     if (var->HasFlag(varbinder::VariableFlags::PRIVATE) || var->HasFlag(varbinder::VariableFlags::PROTECTED)) {
416         if (Context().ContainingClass() == obj && obj->IsPropertyInherited(var)) {
417             return;
418         }
419 
420         if (var->HasFlag(varbinder::VariableFlags::PROTECTED) && Context().ContainingClass()->IsDescendantOf(obj) &&
421             obj->IsPropertyInherited(var)) {
422             return;
423         }
424 
425         auto *currentOutermost = Context().ContainingClass()->OutermostClass();
426         auto *objOutermost = obj->OutermostClass();
427 
428         if (currentOutermost != nullptr && objOutermost != nullptr && currentOutermost == objOutermost &&
429             obj->IsPropertyInherited(var)) {
430             return;
431         }
432 
433         ThrowTypeError({"Property ", var->Name(), " is not visible here."}, pos);
434     }
435 }
436 
FindVariableInFunctionScope(const util::StringView name)437 varbinder::Variable *ETSChecker::FindVariableInFunctionScope(const util::StringView name)
438 {
439     return Scope()->FindInFunctionScope(name, varbinder::ResolveBindingOptions::ALL).variable;
440 }
441 
FindVariableInClassOrEnclosing(const util::StringView name,const ETSObjectType * classType)442 std::pair<const varbinder::Variable *, const ETSObjectType *> ETSChecker::FindVariableInClassOrEnclosing(
443     const util::StringView name, const ETSObjectType *classType)
444 {
445     const auto searchFlags = PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE |
446                              PropertySearchFlags::SEARCH_IN_INTERFACES;
447     auto *resolved = classType->GetProperty(name, searchFlags);
448     while (classType->EnclosingType() != nullptr && resolved == nullptr) {
449         classType = classType->EnclosingType();
450         resolved = classType->GetProperty(name, searchFlags);
451     }
452 
453     return {resolved, classType};
454 }
455 
FindVariableInGlobal(const ir::Identifier * const identifier)456 varbinder::Variable *ETSChecker::FindVariableInGlobal(const ir::Identifier *const identifier)
457 {
458     return Scope()->FindInGlobal(identifier->Name(), varbinder::ResolveBindingOptions::ALL).variable;
459 }
460 
IsVariableStatic(const varbinder::Variable * var)461 bool ETSChecker::IsVariableStatic(const varbinder::Variable *var)
462 {
463     if (var->HasFlag(varbinder::VariableFlags::METHOD)) {
464         return var->TsType()->AsETSFunctionType()->CallSignatures()[0]->HasSignatureFlag(SignatureFlags::STATIC);
465     }
466     return var->HasFlag(varbinder::VariableFlags::STATIC);
467 }
468 
IsVariableGetterSetter(const varbinder::Variable * var)469 bool ETSChecker::IsVariableGetterSetter(const varbinder::Variable *var)
470 {
471     return var->TsType() != nullptr && var->TsType()->HasTypeFlag(TypeFlag::GETTER_SETTER);
472 }
473 
ThrowError(ir::Identifier * const ident)474 void ETSChecker::ThrowError(ir::Identifier *const ident)
475 {
476     ThrowTypeError({"Unresolved reference ", ident->Name()}, ident->Start());
477 }
478 
CheckEtsFunctionType(ir::Identifier * const ident,ir::Identifier const * const id,ir::TypeNode const * const annotation)479 void ETSChecker::CheckEtsFunctionType(ir::Identifier *const ident, ir::Identifier const *const id,
480                                       ir::TypeNode const *const annotation)
481 {
482     if (annotation == nullptr) {
483         ThrowTypeError(
484             {"Cannot infer type for ", id->Name(), " because method reference needs an explicit target type"},
485             id->Start());
486     }
487 
488     const auto *const targetType = GetTypeOfVariable(id->Variable());
489     ASSERT(targetType != nullptr);
490 
491     if (!targetType->IsETSObjectType() || !targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
492         ThrowError(ident);
493     }
494 }
495 
NotResolvedError(ir::Identifier * const ident)496 void ETSChecker::NotResolvedError(ir::Identifier *const ident)
497 {
498     const auto [class_var, class_type] = FindVariableInClassOrEnclosing(ident->Name(), Context().ContainingClass());
499     if (class_var == nullptr) {
500         ThrowError(ident);
501     }
502 
503     if (IsVariableStatic(class_var)) {
504         ThrowTypeError(
505             {"Static property '", ident->Name(), "' must be accessed through it's class '", class_type->Name(), "'"},
506             ident->Start());
507     } else {
508         ThrowTypeError({"Property '", ident->Name(), "' must be accessed through 'this'"}, ident->Start());
509     }
510 }
511 
ValidateCallExpressionIdentifier(ir::Identifier * const ident,Type * const type)512 void ETSChecker::ValidateCallExpressionIdentifier(ir::Identifier *const ident, Type *const type)
513 {
514     if (ident->Parent()->AsCallExpression()->Callee() == ident && !type->IsETSFunctionType() &&
515         !type->IsETSDynamicType() &&
516         (!type->IsETSObjectType() || !type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) &&
517         !TryTransformingToStaticInvoke(ident, type)) {
518         ThrowError(ident);
519     }
520 }
521 
ValidateNewClassInstanceIdentifier(ir::Identifier * const ident,varbinder::Variable * const resolved)522 void ETSChecker::ValidateNewClassInstanceIdentifier(ir::Identifier *const ident, varbinder::Variable *const resolved)
523 {
524     if (ident->Parent()->AsETSNewClassInstanceExpression()->GetTypeRef() == ident &&
525         !resolved->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE)) {
526         ThrowError(ident);
527     }
528 }
529 
ValidateMemberIdentifier(ir::Identifier * const ident,varbinder::Variable * const resolved,Type * const type)530 void ETSChecker::ValidateMemberIdentifier(ir::Identifier *const ident, varbinder::Variable *const resolved,
531                                           Type *const type)
532 {
533     if (ident->Parent()->AsMemberExpression()->IsComputed()) {
534         if (!resolved->Declaration()->PossibleTDZ()) {
535             ThrowError(ident);
536         }
537 
538         return;
539     }
540 
541     if (!IsReferenceType(type) && !type->IsETSEnumType() && !type->IsETSStringEnumType() &&
542         !type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
543         ThrowError(ident);
544     }
545 }
546 
GetTargetIdentifierAndType(ir::Identifier * const ident)547 std::pair<const ir::Identifier *, ir::TypeNode *> ETSChecker::GetTargetIdentifierAndType(ir::Identifier *const ident)
548 {
549     if (ident->Parent()->IsClassProperty()) {
550         const auto *const classProp = ident->Parent()->AsClassProperty();
551         ASSERT(classProp->Value() && classProp->Value() == ident);
552         return std::make_pair(classProp->Key()->AsIdentifier(), classProp->TypeAnnotation());
553     }
554     const auto *const variableDecl = ident->Parent()->AsVariableDeclarator();
555     ASSERT(variableDecl->Init() && variableDecl->Init() == ident);
556     return std::make_pair(variableDecl->Id()->AsIdentifier(), variableDecl->Id()->AsIdentifier()->TypeAnnotation());
557 }
558 
ValidatePropertyOrDeclaratorIdentifier(ir::Identifier * const ident,varbinder::Variable * const resolved)559 void ETSChecker::ValidatePropertyOrDeclaratorIdentifier(ir::Identifier *const ident,
560                                                         varbinder::Variable *const resolved)
561 {
562     const auto [target_ident, typeAnnotation] = GetTargetIdentifierAndType(ident);
563 
564     if (resolved->TsType()->IsETSFunctionType()) {
565         CheckEtsFunctionType(ident, target_ident, typeAnnotation);
566         return;
567     }
568 
569     if (!resolved->Declaration()->PossibleTDZ()) {
570         ThrowError(ident);
571     }
572 }
573 
ValidateAssignmentIdentifier(ir::Identifier * const ident,varbinder::Variable * const resolved,Type * const type)574 void ETSChecker::ValidateAssignmentIdentifier(ir::Identifier *const ident, varbinder::Variable *const resolved,
575                                               Type *const type)
576 {
577     const auto *const assignmentExpr = ident->Parent()->AsAssignmentExpression();
578     if (assignmentExpr->Left() == ident && !resolved->Declaration()->PossibleTDZ()) {
579         ThrowError(ident);
580     }
581 
582     if (assignmentExpr->Right() == ident) {
583         const auto *const targetType = assignmentExpr->Left()->TsType();
584         ASSERT(targetType != nullptr);
585 
586         if (targetType->IsETSObjectType() && targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
587             if (!type->IsETSFunctionType() &&
588                 !(type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL))) {
589                 ThrowError(ident);
590             }
591 
592             return;
593         }
594 
595         if (!resolved->Declaration()->PossibleTDZ()) {
596             ThrowError(ident);
597         }
598     }
599 }
600 
ValidateBinaryExpressionIdentifier(ir::Identifier * const ident,Type * const type)601 bool ETSChecker::ValidateBinaryExpressionIdentifier(ir::Identifier *const ident, Type *const type)
602 {
603     const auto *const binaryExpr = ident->Parent()->AsBinaryExpression();
604     bool isFinished = false;
605     if (binaryExpr->OperatorType() == lexer::TokenType::KEYW_INSTANCEOF && binaryExpr->Right() == ident) {
606         if (!type->IsETSObjectType()) {
607             ThrowError(ident);
608         }
609         isFinished = true;
610     }
611     return isFinished;
612 }
613 
ValidateResolvedIdentifier(ir::Identifier * const ident,varbinder::Variable * const resolved)614 void ETSChecker::ValidateResolvedIdentifier(ir::Identifier *const ident, varbinder::Variable *const resolved)
615 {
616     if (resolved == nullptr) {
617         NotResolvedError(ident);
618     }
619 
620     auto *const resolvedType = ETSChecker::GetApparentType(GetTypeOfVariable(resolved));
621 
622     switch (ident->Parent()->Type()) {
623         case ir::AstNodeType::CALL_EXPRESSION: {
624             ValidateCallExpressionIdentifier(ident, resolvedType);
625             break;
626         }
627         case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
628             ValidateNewClassInstanceIdentifier(ident, resolved);
629             break;
630         }
631         case ir::AstNodeType::MEMBER_EXPRESSION: {
632             ValidateMemberIdentifier(ident, resolved, resolvedType);
633             break;
634         }
635         case ir::AstNodeType::BINARY_EXPRESSION: {
636             if (ValidateBinaryExpressionIdentifier(ident, resolvedType)) {
637                 return;
638             }
639 
640             [[fallthrough]];
641         }
642         case ir::AstNodeType::UPDATE_EXPRESSION:
643         case ir::AstNodeType::UNARY_EXPRESSION: {
644             if (!resolved->Declaration()->PossibleTDZ()) {
645                 ThrowError(ident);
646             }
647             break;
648         }
649         case ir::AstNodeType::CLASS_PROPERTY:
650         case ir::AstNodeType::VARIABLE_DECLARATOR: {
651             ValidatePropertyOrDeclaratorIdentifier(ident, resolved);
652             break;
653         }
654         case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
655             ValidateAssignmentIdentifier(ident, resolved, resolvedType);
656             break;
657         }
658         default: {
659             if (!resolved->Declaration()->PossibleTDZ() && !resolvedType->IsETSFunctionType()) {
660                 ThrowError(ident);
661             }
662             break;
663         }
664     }
665 }
666 
SaveCapturedVariable(varbinder::Variable * const var,const lexer::SourcePosition & pos)667 void ETSChecker::SaveCapturedVariable(varbinder::Variable *const var, const lexer::SourcePosition &pos)
668 {
669     if (!HasStatus(CheckerStatus::IN_LAMBDA)) {
670         return;
671     }
672 
673     if (var->HasFlag(varbinder::VariableFlags::PROPERTY)) {
674         Context().AddCapturedVar(var, pos);
675         return;
676     }
677 
678     if ((!var->HasFlag(varbinder::VariableFlags::LOCAL) && !var->HasFlag(varbinder::VariableFlags::METHOD)) ||
679         (var->GetScope()->Node()->IsScriptFunction() && var->GetScope()->Node()->AsScriptFunction()->IsArrow())) {
680         return;
681     }
682 
683     const auto *scopeIter = Scope();
684     while (scopeIter != var->GetScope()) {
685         if (scopeIter->IsFunctionScope()) {
686             Context().AddCapturedVar(var, pos);
687             return;
688         }
689         scopeIter = scopeIter->Parent();
690     }
691 }
692 
ResolveIdentifier(ir::Identifier * const ident)693 Type *ETSChecker::ResolveIdentifier(ir::Identifier *const ident)
694 {
695     if (ident->Variable() != nullptr) {
696         auto *const resolved = ident->Variable();
697         SaveCapturedVariable(resolved, ident->Start());
698         return GetTypeOfVariable(resolved);
699     }
700 
701     auto *resolved = FindVariableInFunctionScope(ident->Name());
702     if (resolved == nullptr) {
703         // If the reference is not found already in the current class, then it is not bound to the class, so we have to
704         // find the reference in the global class first, then in the global scope
705         resolved = FindVariableInGlobal(ident);
706     }
707 
708     ValidateResolvedIdentifier(ident, resolved);
709 
710     if (resolved->HasFlag(varbinder::VariableFlags::METHOD)) {
711         ASSERT(resolved->TsType()->IsETSFunctionType() &&
712                !resolved->TsType()->AsETSFunctionType()->CallSignatures().empty());
713         const auto *const funcType = resolved->TsType()->AsETSFunctionType();
714         if (!funcType->CallSignatures().front()->Owner()->HasObjectFlag(checker::ETSObjectFlags::GLOBAL)) {
715             // In the case of function references, it is not enough to find the first method field and use it's function
716             // type, because at the position of the call we should be able to work with every possible signature, even
717             // with ones that came from base classes.
718             // NOTE: szd.  find a better way than making a synthetic variable
719             resolved = funcType->CallSignatures().front()->Owner()->CreateSyntheticVarFromEverySignature(
720                 ident->Name(), PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::SEARCH_IN_BASE);
721         }
722     }
723 
724     ValidatePropertyAccess(resolved, Context().ContainingClass(), ident->Start());
725     SaveCapturedVariable(resolved, ident->Start());
726 
727     ident->SetVariable(resolved);
728     return GetTypeOfVariable(resolved);
729 }
730 
ValidateUnaryOperatorOperand(varbinder::Variable * variable)731 void ETSChecker::ValidateUnaryOperatorOperand(varbinder::Variable *variable)
732 {
733     if (IsVariableGetterSetter(variable)) {
734         return;
735     }
736 
737     if (variable->Declaration()->IsConstDecl()) {
738         if (HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK) &&
739             !variable->HasFlag(varbinder::VariableFlags::EXPLICIT_INIT_REQUIRED)) {
740             ThrowTypeError({"Cannot reassign constant field ", variable->Name()},
741                            variable->Declaration()->Node()->Start());
742         }
743         if (!HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK) &&
744             !variable->HasFlag(varbinder::VariableFlags::EXPLICIT_INIT_REQUIRED)) {
745             ThrowTypeError({"Cannot assign to a constant variable ", variable->Name()},
746                            variable->Declaration()->Node()->Start());
747         }
748     }
749 }
750 
ApplyBinaryOperatorPromotion(Type * left,Type * right,TypeFlag test,bool doPromotion)751 std::tuple<Type *, bool> ETSChecker::ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test,
752                                                                   bool doPromotion)
753 {
754     Type *unboxedL = ETSBuiltinTypeAsPrimitiveType(left);
755     Type *unboxedR = ETSBuiltinTypeAsPrimitiveType(right);
756     bool bothConst = false;
757 
758     if (unboxedL == nullptr || unboxedR == nullptr) {
759         return {nullptr, false};
760     }
761 
762     if (!unboxedL->HasTypeFlag(test) || !unboxedR->HasTypeFlag(test)) {
763         return {nullptr, false};
764     }
765 
766     if (unboxedL->HasTypeFlag(TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(TypeFlag::CONSTANT)) {
767         bothConst = true;
768     }
769     if (doPromotion) {
770         if (unboxedL->HasTypeFlag(TypeFlag::ETS_NUMERIC) && unboxedR->HasTypeFlag(TypeFlag::ETS_NUMERIC)) {
771             if (unboxedL->IsDoubleType() || unboxedR->IsDoubleType()) {
772                 return {GlobalDoubleType(), bothConst};
773             }
774 
775             if (unboxedL->IsFloatType() || unboxedR->IsFloatType()) {
776                 return {GlobalFloatType(), bothConst};
777             }
778 
779             if (unboxedL->IsLongType() || unboxedR->IsLongType()) {
780                 return {GlobalLongType(), bothConst};
781             }
782 
783             if (unboxedL->IsCharType() && unboxedR->IsCharType()) {
784                 return {GlobalCharType(), bothConst};
785             }
786 
787             return {GlobalIntType(), bothConst};
788         }
789 
790         if (IsTypeIdenticalTo(unboxedL, unboxedR)) {
791             return {unboxedL, bothConst};
792         }
793     }
794 
795     return {unboxedR, bothConst};
796 }
797 
ApplyConditionalOperatorPromotion(checker::ETSChecker * checker,checker::Type * unboxedL,checker::Type * unboxedR)798 checker::Type *ETSChecker::ApplyConditionalOperatorPromotion(checker::ETSChecker *checker, checker::Type *unboxedL,
799                                                              checker::Type *unboxedR)
800 {
801     if ((unboxedL->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedL->IsIntType()) ||
802         (unboxedR->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedR->IsIntType())) {
803         int value = unboxedL->IsIntType() ? unboxedL->AsIntType()->GetValue() : unboxedR->AsIntType()->GetValue();
804         checker::Type *otherType = !unboxedL->IsIntType() ? unboxedL : unboxedR;
805 
806         switch (checker::ETSChecker::ETSType(otherType)) {
807             case checker::TypeFlag::BYTE:
808             case checker::TypeFlag::CHAR: {
809                 if (value <= static_cast<int>(std::numeric_limits<char>::max()) &&
810                     value >= static_cast<int>(std::numeric_limits<char>::min())) {
811                     return checker->GetNonConstantTypeFromPrimitiveType(otherType);
812                 }
813                 break;
814             }
815             case checker::TypeFlag::SHORT: {
816                 if (value <= std::numeric_limits<int16_t>::max() && value >= std::numeric_limits<int16_t>::min()) {
817                     return checker->GlobalShortType();
818                 }
819                 break;
820             }
821             default: {
822                 return otherType;
823             }
824         }
825         return checker->GlobalIntType();
826     }
827 
828     if (unboxedL->IsDoubleType() || unboxedR->IsDoubleType()) {
829         return checker->GlobalDoubleType();
830     }
831     if (unboxedL->IsFloatType() || unboxedR->IsFloatType()) {
832         return checker->GlobalFloatType();
833     }
834     if (unboxedL->IsLongType() || unboxedR->IsLongType()) {
835         return checker->GlobalLongType();
836     }
837     if (unboxedL->IsIntType() || unboxedR->IsIntType() || unboxedL->IsCharType() || unboxedR->IsCharType()) {
838         return checker->GlobalIntType();
839     }
840     if (unboxedL->IsShortType() || unboxedR->IsShortType()) {
841         return checker->GlobalShortType();
842     }
843     if (unboxedL->IsByteType() || unboxedR->IsByteType()) {
844         return checker->GlobalByteType();
845     }
846 
847     UNREACHABLE();
848 }
849 
ApplyUnaryOperatorPromotion(Type * type,const bool createConst,const bool doPromotion,const bool isCondExpr)850 Type *ETSChecker::ApplyUnaryOperatorPromotion(Type *type, const bool createConst, const bool doPromotion,
851                                               const bool isCondExpr)
852 {
853     Type *unboxedType = isCondExpr ? ETSBuiltinTypeAsConditionalType(type) : ETSBuiltinTypeAsPrimitiveType(type);
854 
855     if (unboxedType == nullptr) {
856         return nullptr;
857     }
858     if (doPromotion) {
859         switch (ETSType(unboxedType)) {
860             case TypeFlag::BYTE:
861             case TypeFlag::SHORT:
862             case TypeFlag::CHAR: {
863                 if (!createConst) {
864                     return GlobalIntType();
865                 }
866 
867                 return CreateIntTypeFromType(unboxedType);
868             }
869             default: {
870                 break;
871             }
872         }
873     }
874     return unboxedType;
875 }
876 
IsNullLikeOrVoidExpression(const ir::Expression * expr) const877 bool ETSChecker::IsNullLikeOrVoidExpression(const ir::Expression *expr) const
878 {
879     return expr->TsType()->IsETSNullLike() || expr->TsType()->IsETSVoidType();
880 }
881 
IsResolvedAndValue(const ir::Expression * expr,Type * type) const882 std::tuple<bool, bool> ETSChecker::IsResolvedAndValue(const ir::Expression *expr, Type *type) const
883 {
884     auto [isResolve, isValue] =
885         IsNullLikeOrVoidExpression(expr) ? std::make_tuple(true, false) : type->ResolveConditionExpr();
886 
887     const Type *tsType = expr->TsType();
888     if (!tsType->ContainsUndefined() && !tsType->ContainsNull() && !tsType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
889         isResolve = true;
890         isValue = true;
891     }
892     return std::make_tuple(isResolve, isValue);
893 }
894 
HandleBooleanLogicalOperatorsExtended(Type * leftType,Type * rightType,ir::BinaryExpression * expr)895 Type *ETSChecker::HandleBooleanLogicalOperatorsExtended(Type *leftType, Type *rightType, ir::BinaryExpression *expr)
896 {
897     ASSERT(leftType->IsConditionalExprType() && rightType->IsConditionalExprType());
898 
899     auto [resolveLeft, leftValue] = IsResolvedAndValue(expr->Left(), leftType);
900     auto [resolveRight, rightValue] = IsResolvedAndValue(expr->Right(), rightType);
901 
902     if (!resolveLeft && !resolveRight) {
903         if (IsTypeIdenticalTo(leftType, rightType)) {
904             return leftType;
905         }
906         ArenaVector<checker::Type *> types(Allocator()->Adapter());
907         types.push_back(leftType);
908         types.push_back(rightType);
909         return CreateETSUnionType(std::move(types));
910     }
911 
912     switch (expr->OperatorType()) {
913         case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
914             if (leftValue) {
915                 expr->SetResult(expr->Left());
916                 return leftType->IsETSBooleanType() ? CreateETSBooleanType(true) : leftType;
917             }
918 
919             expr->SetResult(expr->Right());
920             return rightType->IsETSBooleanType() && resolveRight ? CreateETSBooleanType(rightValue) : rightType;
921         }
922         case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
923             if (leftValue) {
924                 expr->SetResult(expr->Right());
925                 return rightType->IsETSBooleanType() && resolveRight ? CreateETSBooleanType(rightValue) : rightType;
926             }
927 
928             expr->SetResult(expr->Left());
929             return leftType->IsETSBooleanType() ? CreateETSBooleanType(false) : leftType;
930         }
931         default: {
932             break;
933         }
934     }
935 
936     UNREACHABLE();
937 }
938 
HandleBooleanLogicalOperators(Type * leftType,Type * rightType,lexer::TokenType tokenType)939 Type *ETSChecker::HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType)
940 {
941     using UType = typename ETSBooleanType::UType;
942     ASSERT(leftType->IsETSBooleanType() && rightType->IsETSBooleanType());
943 
944     if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
945         return GlobalETSBooleanType();
946     }
947 
948     UType leftValue = leftType->AsETSBooleanType()->GetValue();
949     UType rightValue = rightType->AsETSBooleanType()->GetValue();
950 
951     switch (tokenType) {
952         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: {
953             return CreateETSBooleanType(leftValue ^ rightValue);
954         }
955         case lexer::TokenType::PUNCTUATOR_BITWISE_AND: {
956             return CreateETSBooleanType((static_cast<uint8_t>(leftValue) & static_cast<uint8_t>(rightValue)) != 0);
957         }
958         case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
959             return CreateETSBooleanType((static_cast<uint8_t>(leftValue) | static_cast<uint8_t>(rightValue)) != 0);
960         }
961         case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
962             return CreateETSBooleanType(leftValue || rightValue);
963         }
964         case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
965             return CreateETSBooleanType(leftValue && rightValue);
966         }
967         default: {
968             break;
969         }
970     }
971 
972     UNREACHABLE();
973     return nullptr;
974 }
975 
ResolveReturnStatement(checker::Type * funcReturnType,checker::Type * argumentType,ir::ScriptFunction * containingFunc,ir::ReturnStatement * st)976 void ETSChecker::ResolveReturnStatement(checker::Type *funcReturnType, checker::Type *argumentType,
977                                         ir::ScriptFunction *containingFunc, ir::ReturnStatement *st)
978 {
979     if (funcReturnType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT) ||
980         argumentType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) {
981         // function return type should be of reference (object) type
982         Relation()->SetFlags(checker::TypeRelationFlag::NONE);
983 
984         if (!argumentType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) {
985             argumentType = PrimitiveTypeAsETSBuiltinType(argumentType);
986             if (argumentType == nullptr) {
987                 ThrowTypeError("Invalid return statement expression", st->Argument()->Start());
988             }
989             st->Argument()->AddBoxingUnboxingFlags(GetBoxingFlag(argumentType));
990         }
991 
992         if (!funcReturnType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) {
993             funcReturnType = PrimitiveTypeAsETSBuiltinType(funcReturnType);
994             if (funcReturnType == nullptr) {
995                 ThrowTypeError("Invalid return function expression", st->Start());
996             }
997         }
998 
999         funcReturnType = FindLeastUpperBound(funcReturnType, argumentType);
1000         containingFunc->Signature()->SetReturnType(funcReturnType);
1001         containingFunc->Signature()->AddSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE);
1002     } else if (funcReturnType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE_RETURN) &&
1003                argumentType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE_RETURN)) {
1004         // function return type is of primitive type (including enums):
1005         Relation()->SetFlags(checker::TypeRelationFlag::DIRECT_RETURN |
1006                              checker::TypeRelationFlag::IN_ASSIGNMENT_CONTEXT |
1007                              checker::TypeRelationFlag::ASSIGNMENT_CONTEXT);
1008         if (Relation()->IsAssignableTo(funcReturnType, argumentType)) {
1009             funcReturnType = argumentType;
1010             containingFunc->Signature()->SetReturnType(funcReturnType);
1011             containingFunc->Signature()->AddSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE);
1012         } else if (!Relation()->IsAssignableTo(argumentType, funcReturnType)) {
1013             ThrowTypeError(
1014                 "Return statement type is not compatible with previous method's return statement "
1015                 "type(s).",
1016                 st->Argument()->Start());
1017         }
1018     } else {
1019         ThrowTypeError("Invalid return statement type(s).", st->Start());
1020     }
1021 }
1022 
CheckArrayElements(ir::Identifier * ident,ir::ArrayExpression * init)1023 checker::Type *ETSChecker::CheckArrayElements(ir::Identifier *ident, ir::ArrayExpression *init)
1024 {
1025     ArenaVector<ir::Expression *> elements = init->AsArrayExpression()->Elements();
1026     checker::Type *annotationType = nullptr;
1027     if (elements.empty()) {
1028         annotationType = Allocator()->New<ETSArrayType>(GlobalETSObjectType());
1029     } else {
1030         auto type = elements[0]->Check(this);
1031         auto const primType = ETSBuiltinTypeAsPrimitiveType(type);
1032         for (auto element : elements) {
1033             auto const eType = element->Check(this);
1034             auto const primEType = ETSBuiltinTypeAsPrimitiveType(eType);
1035             if (primEType != nullptr && primType != nullptr && primEType->HasTypeFlag(TypeFlag::ETS_NUMERIC) &&
1036                 primType->HasTypeFlag(TypeFlag::ETS_NUMERIC)) {
1037                 type = GlobalDoubleType();
1038             } else if (IsTypeIdenticalTo(type, eType)) {
1039                 continue;
1040             } else {
1041                 // NOTE: Create union type when implemented here
1042                 ThrowTypeError({"Union type is not implemented yet!"}, ident->Start());
1043             }
1044         }
1045         annotationType = Allocator()->New<ETSArrayType>(type);
1046     }
1047     return annotationType;
1048 }
1049 
CheckVariableDeclaration(ir::Identifier * ident,ir::TypeNode * typeAnnotation,ir::Expression * init,ir::ModifierFlags flags)1050 checker::Type *ETSChecker::CheckVariableDeclaration(ir::Identifier *ident, ir::TypeNode *typeAnnotation,
1051                                                     ir::Expression *init, ir::ModifierFlags flags)
1052 {
1053     const util::StringView &varName = ident->Name();
1054     ASSERT(ident->Variable());
1055     varbinder::Variable *const bindingVar = ident->Variable();
1056     checker::Type *annotationType = nullptr;
1057 
1058     const bool isConst = (flags & ir::ModifierFlags::CONST) != 0;
1059 
1060     if (typeAnnotation != nullptr) {
1061         annotationType = GetTypeFromTypeAnnotation(typeAnnotation);
1062         bindingVar->SetTsType(annotationType);
1063     }
1064 
1065     if (init == nullptr) {
1066         return annotationType;
1067     }
1068 
1069     if (typeAnnotation == nullptr) {
1070         if (init->IsArrayExpression()) {
1071             annotationType = CheckArrayElements(ident, init->AsArrayExpression());
1072             bindingVar->SetTsType(annotationType);
1073         }
1074 
1075         if (init->IsObjectExpression()) {
1076             ThrowTypeError(
1077                 {"Cannot infer type for ", ident->Name(), " because class composite needs an explicit target type"},
1078                 ident->Start());
1079         }
1080     }
1081 
1082     if (init->IsMemberExpression() && init->AsMemberExpression()->Object()->IsObjectExpression()) {
1083         ThrowTypeError({"Class composite must be constructed separately before referring their members."},
1084                        ident->Start());
1085     }
1086 
1087     if ((init->IsMemberExpression()) && (annotationType != nullptr)) {
1088         SetArrayPreferredTypeForNestedMemberExpressions(init->AsMemberExpression(), annotationType);
1089     }
1090 
1091     if (init->IsArrayExpression() && annotationType->IsETSArrayType()) {
1092         if (annotationType->IsETSTupleType()) {
1093             ValidateTupleMinElementSize(init->AsArrayExpression(), annotationType->AsETSTupleType());
1094         }
1095 
1096         init->AsArrayExpression()->SetPreferredType(annotationType);
1097     }
1098 
1099     if (init->IsObjectExpression()) {
1100         init->AsObjectExpression()->SetPreferredType(annotationType);
1101     }
1102 
1103     if (typeAnnotation != nullptr && typeAnnotation->IsETSFunctionType() && init->IsArrowFunctionExpression()) {
1104         auto *const arrowFuncExpr = init->AsArrowFunctionExpression();
1105         ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
1106         if (lambda->Params().size() == typeAnnotation->AsETSFunctionType()->Params().size() &&
1107             NeedTypeInference(lambda)) {
1108             InferTypesForLambda(lambda, typeAnnotation->AsETSFunctionType());
1109         }
1110     }
1111     checker::Type *initType = init->Check(this);
1112 
1113     if (initType == nullptr) {
1114         ThrowTypeError("Cannot get the expression type", init->Start());
1115     }
1116 
1117     if (typeAnnotation == nullptr &&
1118         (init->IsArrowFunctionExpression() ||
1119          (init->IsTSAsExpression() && init->AsTSAsExpression()->Expr()->IsArrowFunctionExpression()))) {
1120         if (init->IsArrowFunctionExpression()) {
1121             typeAnnotation = init->AsArrowFunctionExpression()->CreateTypeAnnotation(this);
1122         } else {
1123             typeAnnotation = init->AsTSAsExpression()->TypeAnnotation();
1124         }
1125         ident->SetTsTypeAnnotation(typeAnnotation);
1126         typeAnnotation->SetParent(ident);
1127         annotationType = GetTypeFromTypeAnnotation(typeAnnotation);
1128         bindingVar->SetTsType(annotationType);
1129     }
1130 
1131     if (annotationType != nullptr) {
1132         AssignmentContext(Relation(), init, initType, annotationType, init->Start(),
1133                           {"Initializers type is not assignable to the target type"});
1134         if (isConst && initType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) &&
1135             annotationType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
1136             bindingVar->SetTsType(init->TsType());
1137         }
1138         return bindingVar->TsType();
1139     }
1140 
1141     if (initType->IsETSNullLike()) {
1142         TypeFlag nullishFlags {0};
1143 
1144         if (initType->IsETSNullType()) {
1145             nullishFlags = TypeFlag::NULL_TYPE;
1146         }
1147         if (initType->IsETSUndefinedType()) {
1148             nullishFlags = TypeFlag::UNDEFINED;
1149         }
1150         initType = CreateNullishType(GetGlobalTypesHolder()->GlobalETSObjectType(), nullishFlags, Allocator(),
1151                                      Relation(), GetGlobalTypesHolder());
1152     }
1153 
1154     if (initType->IsETSObjectType() && initType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::ENUM) &&
1155         !init->IsMemberExpression()) {
1156         ThrowTypeError({"Cannot assign type '", initType->AsETSObjectType()->Name(), "' for variable ", varName, "."},
1157                        init->Start());
1158     }
1159 
1160     if (initType->IsNullish() || isConst) {
1161         bindingVar->SetTsType(initType);
1162     } else {
1163         bindingVar->SetTsType(GetNonConstantTypeFromPrimitiveType(initType));
1164     }
1165 
1166     return bindingVar->TsType();
1167 }
1168 
SetArrayPreferredTypeForNestedMemberExpressions(ir::MemberExpression * expr,Type * annotationType)1169 void ETSChecker::SetArrayPreferredTypeForNestedMemberExpressions(ir::MemberExpression *expr, Type *annotationType)
1170 {
1171     if ((expr == nullptr) || (annotationType == nullptr)) {
1172         return;
1173     }
1174 
1175     if (expr->Kind() != ir::MemberExpressionKind::ELEMENT_ACCESS) {
1176         return;
1177     }
1178 
1179     // Expand all member expressions
1180     Type *elementType = annotationType;
1181     ir::Expression *object = expr->Object();
1182     while ((object != nullptr) && (object->IsMemberExpression())) {
1183         ir::MemberExpression *memberExpr = object->AsMemberExpression();
1184         if (memberExpr->Kind() != ir::MemberExpressionKind::ELEMENT_ACCESS) {
1185             return;
1186         }
1187 
1188         object = memberExpr->Object();
1189         elementType = CreateETSArrayType(elementType);
1190     }
1191 
1192     // Set explicit target type for array
1193     if ((object != nullptr) && (object->IsArrayExpression())) {
1194         ir::ArrayExpression *array = object->AsArrayExpression();
1195         array->SetPreferredType(CreateETSArrayType(elementType));
1196     }
1197 }
1198 
GetTypeFromTypeAliasReference(varbinder::Variable * var)1199 Type *ETSChecker::GetTypeFromTypeAliasReference(varbinder::Variable *var)
1200 {
1201     if (var->TsType() != nullptr) {
1202         return var->TsType();
1203     }
1204 
1205     auto *const aliasTypeNode = var->Declaration()->Node()->AsTSTypeAliasDeclaration();
1206     TypeStackElement tse(this, aliasTypeNode, "Circular type alias reference", aliasTypeNode->Start());
1207     aliasTypeNode->Check(this);
1208     auto *const aliasedType = GetTypeFromTypeAnnotation(aliasTypeNode->TypeAnnotation());
1209 
1210     var->SetTsType(aliasedType);
1211     return aliasedType;
1212 }
1213 
GetTypeFromInterfaceReference(varbinder::Variable * var)1214 Type *ETSChecker::GetTypeFromInterfaceReference(varbinder::Variable *var)
1215 {
1216     if (var->TsType() != nullptr) {
1217         return var->TsType();
1218     }
1219 
1220     auto *interfaceType = BuildInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration());
1221     var->SetTsType(interfaceType);
1222     return interfaceType;
1223 }
1224 
GetTypeFromClassReference(varbinder::Variable * var)1225 Type *ETSChecker::GetTypeFromClassReference(varbinder::Variable *var)
1226 {
1227     if (var->TsType() != nullptr) {
1228         return var->TsType();
1229     }
1230 
1231     auto *classType = BuildClassProperties(var->Declaration()->Node()->AsClassDefinition());
1232     var->SetTsType(classType);
1233     return classType;
1234 }
1235 
ValidateGenericTypeAliasForClonedNode(ir::TSTypeAliasDeclaration * const typeAliasNode,const ir::TSTypeParameterInstantiation * const exactTypeParams)1236 void ETSChecker::ValidateGenericTypeAliasForClonedNode(ir::TSTypeAliasDeclaration *const typeAliasNode,
1237                                                        const ir::TSTypeParameterInstantiation *const exactTypeParams)
1238 {
1239     auto *const clonedNode = typeAliasNode->TypeAnnotation()->Clone(Allocator(), typeAliasNode);
1240 
1241     // Basic check, we really don't want to change the original type nodes, more precise checking should be made
1242     ASSERT(clonedNode != typeAliasNode->TypeAnnotation());
1243 
1244     // Currently only reference types are checked. This should be extended for other types in a follow up patch, but for
1245     // complete usability, if the type isn't a simple reference type, then doN't check type alias declaration at all.
1246     bool checkTypealias = true;
1247 
1248     // Only transforming a temporary cloned node, so no modification is made in the AST
1249     clonedNode->TransformChildrenRecursively(
1250         [&checkTypealias, &exactTypeParams, typeAliasNode](ir::AstNode *const node) -> ir::AstNode * {
1251             if (!node->IsETSTypeReference()) {
1252                 return node;
1253             }
1254 
1255             const auto *const nodeIdent = node->AsETSTypeReference()->Part()->Name()->AsIdentifier();
1256 
1257             size_t typeParamIdx = 0;
1258             for (const auto *const typeParam : typeAliasNode->TypeParams()->Params()) {
1259                 if (typeParam->Name()->AsIdentifier()->Variable() == nodeIdent->Variable()) {
1260                     break;
1261                 }
1262                 typeParamIdx++;
1263             }
1264 
1265             if (typeParamIdx == typeAliasNode->TypeParams()->Params().size()) {
1266                 return node;
1267             }
1268 
1269             auto *const typeParamType = exactTypeParams->Params().at(typeParamIdx);
1270 
1271             if (!typeParamType->IsETSTypeReference()) {
1272                 checkTypealias = false;
1273                 return node;
1274             }
1275 
1276             return typeParamType;
1277         });
1278 
1279     if (checkTypealias) {
1280         clonedNode->Check(this);
1281     }
1282 }
1283 
HandleTypeAlias(ir::Expression * const name,const ir::TSTypeParameterInstantiation * const typeParams)1284 Type *ETSChecker::HandleTypeAlias(ir::Expression *const name, const ir::TSTypeParameterInstantiation *const typeParams)
1285 {
1286     ASSERT(name->IsIdentifier() && name->AsIdentifier()->Variable() &&
1287            name->AsIdentifier()->Variable()->Declaration()->IsTypeAliasDecl());
1288 
1289     auto *const typeAliasNode =
1290         name->AsIdentifier()->Variable()->Declaration()->AsTypeAliasDecl()->Node()->AsTSTypeAliasDeclaration();
1291 
1292     // NOTE (mmartin): modify for default params
1293     if ((typeParams == nullptr) != (typeAliasNode->TypeParams() == nullptr)) {
1294         if (typeParams == nullptr) {
1295             ThrowTypeError("Type alias declaration is generic, but no type parameters were provided", name->Start());
1296         }
1297 
1298         ThrowTypeError("Type alias declaration is not generic, but type parameters were provided", typeParams->Start());
1299     }
1300 
1301     if (typeParams == nullptr) {
1302         return GetReferencedTypeBase(name);
1303     }
1304 
1305     for (auto *const origTypeParam : typeParams->Params()) {
1306         origTypeParam->Check(this);
1307     }
1308 
1309     Type *const aliasType = GetReferencedTypeBase(name);
1310     auto *const aliasSub = NewSubstitution();
1311 
1312     if (typeAliasNode->TypeParams()->Params().size() != typeParams->Params().size()) {
1313         ThrowTypeError("Wrong number of type parameters for generic type alias", typeParams->Start());
1314     }
1315 
1316     for (std::size_t idx = 0; idx < typeAliasNode->TypeParams()->Params().size(); ++idx) {
1317         auto *typeAliasType = typeAliasNode->TypeParams()->Params().at(idx)->Name()->Variable()->TsType();
1318         if (typeAliasType->IsETSTypeParameter()) {
1319             aliasSub->insert({typeAliasType->AsETSTypeParameter(), typeParams->Params().at(idx)->TsType()});
1320         }
1321     }
1322 
1323     ValidateGenericTypeAliasForClonedNode(typeAliasNode->AsTSTypeAliasDeclaration(), typeParams);
1324 
1325     return aliasType->Substitute(Relation(), aliasSub);
1326 }
1327 
GetTypeFromEnumReference(varbinder::Variable * var)1328 Type *ETSChecker::GetTypeFromEnumReference([[maybe_unused]] varbinder::Variable *var)
1329 {
1330     if (var->TsType() != nullptr) {
1331         return var->TsType();
1332     }
1333 
1334     auto const *const enumDecl = var->Declaration()->Node()->AsTSEnumDeclaration();
1335     if (auto *const itemInit = enumDecl->Members().front()->AsTSEnumMember()->Init(); itemInit->IsNumberLiteral()) {
1336         return CreateETSEnumType(enumDecl);
1337     } else if (itemInit->IsStringLiteral()) {  // NOLINT(readability-else-after-return)
1338         return CreateETSStringEnumType(enumDecl);
1339     } else {  // NOLINT(readability-else-after-return)
1340         ThrowTypeError("Invalid enumeration value type.", enumDecl->Start());
1341     }
1342 }
1343 
GetTypeFromTypeParameterReference(varbinder::LocalVariable * var,const lexer::SourcePosition & pos)1344 Type *ETSChecker::GetTypeFromTypeParameterReference(varbinder::LocalVariable *var, const lexer::SourcePosition &pos)
1345 {
1346     ASSERT(var->Declaration()->Node()->IsTSTypeParameter());
1347     if ((var->Declaration()->Node()->AsTSTypeParameter()->Parent()->Parent()->IsClassDefinition() ||
1348          var->Declaration()->Node()->AsTSTypeParameter()->Parent()->Parent()->IsTSInterfaceDeclaration()) &&
1349         HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) {
1350         ThrowTypeError({"Cannot make a static reference to the non-static type ", var->Name()}, pos);
1351     }
1352 
1353     return var->TsType();
1354 }
1355 
GetNameForSynteticObjectType(const util::StringView & source)1356 std::vector<util::StringView> ETSChecker::GetNameForSynteticObjectType(const util::StringView &source)
1357 {
1358     const std::string str = source.Mutf8();
1359     std::istringstream ss {str};
1360     const char delimiter = '.';
1361     std::string token;
1362 
1363     std::vector<util::StringView> syntheticName {};
1364 
1365     while (std::getline(ss, token, delimiter)) {
1366         if (!token.empty()) {
1367             util::UString sV(token, Allocator());
1368             syntheticName.emplace_back(sV.View());
1369         }
1370     }
1371 
1372     return syntheticName;
1373 }
1374 
SetPropertiesForModuleObject(checker::ETSObjectType * moduleObjType,const util::StringView & importPath)1375 void ETSChecker::SetPropertiesForModuleObject(checker::ETSObjectType *moduleObjType, const util::StringView &importPath)
1376 {
1377     auto *etsBinder = static_cast<varbinder::ETSBinder *>(VarBinder());
1378 
1379     auto extRecords = etsBinder->GetGlobalRecordTable()->Program()->ExternalSources();
1380     auto res = [etsBinder, extRecords, importPath]() {
1381         auto r = extRecords.find(importPath);
1382         return r != extRecords.end() ? r : extRecords.find(etsBinder->GetResolvedImportPath(importPath));
1383     }();
1384 
1385     // Check imported properties before assigning them to module object
1386     res->second.front()->Ast()->Check(this);
1387 
1388     for (auto [_, var] : res->second.front()->GlobalClassScope()->StaticFieldScope()->Bindings()) {
1389         (void)_;
1390         if (var->AsLocalVariable()->Declaration()->Node()->IsExported()) {
1391             moduleObjType->AddProperty<checker::PropertyType::STATIC_FIELD>(var->AsLocalVariable());
1392         }
1393     }
1394 
1395     for (auto [_, var] : res->second.front()->GlobalClassScope()->StaticMethodScope()->Bindings()) {
1396         (void)_;
1397         if (var->AsLocalVariable()->Declaration()->Node()->IsExported()) {
1398             moduleObjType->AddProperty<checker::PropertyType::STATIC_METHOD>(var->AsLocalVariable());
1399         }
1400     }
1401 
1402     for (auto [_, var] : res->second.front()->GlobalClassScope()->InstanceDeclScope()->Bindings()) {
1403         (void)_;
1404         if (var->AsLocalVariable()->Declaration()->Node()->IsExported()) {
1405             moduleObjType->AddProperty<checker::PropertyType::STATIC_DECL>(var->AsLocalVariable());
1406         }
1407     }
1408 
1409     for (auto [_, var] : res->second.front()->GlobalClassScope()->TypeAliasScope()->Bindings()) {
1410         (void)_;
1411         if (var->AsLocalVariable()->Declaration()->Node()->IsExported()) {
1412             moduleObjType->AddProperty<checker::PropertyType::STATIC_DECL>(var->AsLocalVariable());
1413         }
1414     }
1415 }
1416 
SetrModuleObjectTsType(ir::Identifier * local,checker::ETSObjectType * moduleObjType)1417 void ETSChecker::SetrModuleObjectTsType(ir::Identifier *local, checker::ETSObjectType *moduleObjType)
1418 {
1419     auto *etsBinder = static_cast<varbinder::ETSBinder *>(VarBinder());
1420 
1421     for (auto [bindingName, var] : etsBinder->TopScope()->Bindings()) {
1422         if (bindingName.Is(local->Name().Mutf8())) {
1423             var->SetTsType(moduleObjType);
1424         }
1425     }
1426 }
1427 
GetReferencedTypeFromBase(Type * baseType,ir::Expression * name)1428 Type *ETSChecker::GetReferencedTypeFromBase([[maybe_unused]] Type *baseType, [[maybe_unused]] ir::Expression *name)
1429 {
1430     return nullptr;
1431 }
1432 
GetReferencedTypeBase(ir::Expression * name)1433 Type *ETSChecker::GetReferencedTypeBase(ir::Expression *name)
1434 {
1435     if (name->IsTSQualifiedName()) {
1436         auto *qualified = name->AsTSQualifiedName();
1437         return qualified->Check(this);
1438     }
1439 
1440     ASSERT(name->IsIdentifier() && name->AsIdentifier()->Variable() != nullptr);
1441 
1442     // NOTE: kbaladurin. forbid usage imported entities as types without declarations
1443     auto *importData = VarBinder()->AsETSBinder()->DynamicImportDataForVar(name->AsIdentifier()->Variable());
1444     if (importData != nullptr && importData->import->IsPureDynamic()) {
1445         return GlobalBuiltinDynamicType(importData->import->Language());
1446     }
1447 
1448     auto *refVar = name->AsIdentifier()->Variable()->AsLocalVariable();
1449 
1450     switch (refVar->Declaration()->Node()->Type()) {
1451         case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
1452             return GetTypeFromInterfaceReference(refVar);
1453         }
1454         case ir::AstNodeType::CLASS_DECLARATION:
1455         case ir::AstNodeType::STRUCT_DECLARATION:
1456         case ir::AstNodeType::CLASS_DEFINITION: {
1457             return GetTypeFromClassReference(refVar);
1458         }
1459         case ir::AstNodeType::TS_ENUM_DECLARATION: {
1460             return GetTypeFromEnumReference(refVar);
1461         }
1462         case ir::AstNodeType::TS_TYPE_PARAMETER: {
1463             return GetTypeFromTypeParameterReference(refVar, name->Start());
1464         }
1465         case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION: {
1466             return GetTypeFromTypeAliasReference(refVar);
1467         }
1468         default: {
1469             UNREACHABLE();
1470         }
1471     }
1472 }
1473 
ConcatConstantString(util::UString & target,Type * type)1474 void ETSChecker::ConcatConstantString(util::UString &target, Type *type)
1475 {
1476     switch (ETSType(type)) {
1477         case TypeFlag::ETS_OBJECT: {
1478             ASSERT(type->IsETSStringType());
1479             target.Append(type->AsETSStringType()->GetValue());
1480             break;
1481         }
1482         case TypeFlag::ETS_BOOLEAN: {
1483             ETSBooleanType::UType value = type->AsETSBooleanType()->GetValue();
1484             target.Append(value ? "true" : "false");
1485             break;
1486         }
1487         case TypeFlag::BYTE: {
1488             ByteType::UType value = type->AsByteType()->GetValue();
1489             target.Append(std::to_string(value));
1490             break;
1491         }
1492         case TypeFlag::CHAR: {
1493             CharType::UType value = type->AsCharType()->GetValue();
1494             std::string s(1, value);
1495             target.Append(s);
1496             break;
1497         }
1498         case TypeFlag::SHORT: {
1499             ShortType::UType value = type->AsShortType()->GetValue();
1500             target.Append(std::to_string(value));
1501             break;
1502         }
1503         case TypeFlag::INT: {
1504             IntType::UType value = type->AsIntType()->GetValue();
1505             target.Append(std::to_string(value));
1506             break;
1507         }
1508         case TypeFlag::LONG: {
1509             LongType::UType value = type->AsLongType()->GetValue();
1510             target.Append(std::to_string(value));
1511             break;
1512         }
1513         case TypeFlag::FLOAT: {
1514             FloatType::UType value = type->AsFloatType()->GetValue();
1515             target.Append(std::to_string(value));
1516             break;
1517         }
1518         case TypeFlag::DOUBLE: {
1519             DoubleType::UType value = type->AsDoubleType()->GetValue();
1520             target.Append(std::to_string(value));
1521             break;
1522         }
1523         default: {
1524             UNREACHABLE();
1525         }
1526     }
1527 }
1528 
HandleStringConcatenation(Type * leftType,Type * rightType)1529 Type *ETSChecker::HandleStringConcatenation(Type *leftType, Type *rightType)
1530 {
1531     ASSERT(leftType->IsETSStringType() || rightType->IsETSStringType());
1532 
1533     if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
1534         return GlobalETSStringLiteralType();
1535     }
1536 
1537     util::UString concatenated(Allocator());
1538     ConcatConstantString(concatenated, leftType);
1539     ConcatConstantString(concatenated, rightType);
1540 
1541     return CreateETSStringLiteralType(concatenated.View());
1542 }
1543 
FindFunctionInVectorGivenByName(util::StringView name,ArenaVector<ETSFunctionType * > & list)1544 ETSFunctionType *ETSChecker::FindFunctionInVectorGivenByName(util::StringView name,
1545                                                              ArenaVector<ETSFunctionType *> &list)
1546 {
1547     for (auto *it : list) {
1548         if (it->Name() == name) {
1549             return it;
1550         }
1551     }
1552 
1553     return nullptr;
1554 }
1555 
IsFunctionContainsSignature(ETSFunctionType * funcType,Signature * signature)1556 bool ETSChecker::IsFunctionContainsSignature(ETSFunctionType *funcType, Signature *signature)
1557 {
1558     for (auto *it : funcType->CallSignatures()) {
1559         Relation()->IsIdenticalTo(it, signature);
1560         if (Relation()->IsTrue()) {
1561             return true;
1562         }
1563     }
1564 
1565     return false;
1566 }
1567 
CheckFunctionContainsClashingSignature(const ETSFunctionType * funcType,Signature * signature)1568 void ETSChecker::CheckFunctionContainsClashingSignature(const ETSFunctionType *funcType, Signature *signature)
1569 {
1570     for (auto *it : funcType->CallSignatures()) {
1571         SavedTypeRelationFlagsContext strfCtx(Relation(), TypeRelationFlag::NONE);
1572         Relation()->IsIdenticalTo(it, signature);
1573         if (Relation()->IsTrue() && it->Function()->Id()->Name() == signature->Function()->Id()->Name()) {
1574             std::stringstream ss;
1575             it->ToString(ss, nullptr, true);
1576             auto sigStr1 = ss.str();
1577             ss.str(std::string {});  // Clear buffer
1578             signature->ToString(ss, nullptr, true);
1579             auto sigStr2 = ss.str();
1580             ThrowTypeError({"Function '", it->Function()->Id()->Name(), sigStr1.c_str(),
1581                             "' is redeclared with different signature '", signature->Function()->Id()->Name(),
1582                             sigStr2.c_str(), "'"},
1583                            signature->Function()->ReturnTypeAnnotation()->Start());
1584         }
1585     }
1586 }
1587 
MergeSignatures(ETSFunctionType * target,ETSFunctionType * source)1588 void ETSChecker::MergeSignatures(ETSFunctionType *target, ETSFunctionType *source)
1589 {
1590     for (auto *s : source->CallSignatures()) {
1591         if (IsFunctionContainsSignature(target, s)) {
1592             continue;
1593         }
1594 
1595         CheckFunctionContainsClashingSignature(target, s);
1596         target->AddCallSignature(s);
1597     }
1598 }
1599 
MergeComputedAbstracts(ArenaVector<ETSFunctionType * > & merged,ArenaVector<ETSFunctionType * > & current)1600 void ETSChecker::MergeComputedAbstracts(ArenaVector<ETSFunctionType *> &merged, ArenaVector<ETSFunctionType *> &current)
1601 {
1602     for (auto *curr : current) {
1603         auto name = curr->Name();
1604         auto *found = FindFunctionInVectorGivenByName(name, merged);
1605         if (found != nullptr) {
1606             MergeSignatures(found, curr);
1607             continue;
1608         }
1609 
1610         merged.push_back(curr);
1611     }
1612 }
1613 
FindAncestorGivenByType(ir::AstNode * node,ir::AstNodeType type,const ir::AstNode * endNode)1614 ir::AstNode *ETSChecker::FindAncestorGivenByType(ir::AstNode *node, ir::AstNodeType type, const ir::AstNode *endNode)
1615 {
1616     auto *iter = node->Parent();
1617 
1618     while (iter != endNode) {
1619         if (iter->Type() == type) {
1620             return iter;
1621         }
1622 
1623         iter = iter->Parent();
1624     }
1625 
1626     return nullptr;
1627 }
1628 
GetContainingObjectNameFromSignature(Signature * signature)1629 util::StringView ETSChecker::GetContainingObjectNameFromSignature(Signature *signature)
1630 {
1631     ASSERT(signature->Function());
1632     auto *iter = signature->Function()->Parent();
1633 
1634     while (iter != nullptr) {
1635         if (iter->IsClassDefinition()) {
1636             return iter->AsClassDefinition()->Ident()->Name();
1637         }
1638 
1639         if (iter->IsTSInterfaceDeclaration()) {
1640             return iter->AsTSInterfaceDeclaration()->Id()->Name();
1641         }
1642 
1643         iter = iter->Parent();
1644     }
1645 
1646     UNREACHABLE();
1647     return {""};
1648 }
1649 
IsTypeBuiltinType(const Type * type) const1650 bool ETSChecker::IsTypeBuiltinType(const Type *type) const
1651 {
1652     if (!type->IsETSObjectType()) {
1653         return false;
1654     }
1655 
1656     switch (type->AsETSObjectType()->BuiltInKind()) {
1657         case ETSObjectFlags::BUILTIN_BOOLEAN:
1658         case ETSObjectFlags::BUILTIN_BYTE:
1659         case ETSObjectFlags::BUILTIN_SHORT:
1660         case ETSObjectFlags::BUILTIN_CHAR:
1661         case ETSObjectFlags::BUILTIN_INT:
1662         case ETSObjectFlags::BUILTIN_LONG:
1663         case ETSObjectFlags::BUILTIN_FLOAT:
1664         case ETSObjectFlags::BUILTIN_DOUBLE: {
1665             return true;
1666         }
1667         default:
1668             return false;
1669     }
1670 }
1671 
IsReferenceType(const Type * type)1672 bool ETSChecker::IsReferenceType(const Type *type)
1673 {
1674     return type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT) || type->IsETSNullLike() ||
1675            type->IsETSStringType() || type->IsETSTypeParameter() || type->IsETSUnionType() || type->IsETSBigIntType();
1676 }
1677 
FindJumpTarget(ir::AstNodeType nodeType,const ir::AstNode * node,const ir::Identifier * target)1678 const ir::AstNode *ETSChecker::FindJumpTarget(ir::AstNodeType nodeType, const ir::AstNode *node,
1679                                               const ir::Identifier *target)
1680 {
1681     const auto *iter = node->Parent();
1682 
1683     while (iter != nullptr) {
1684         switch (iter->Type()) {
1685             case ir::AstNodeType::LABELLED_STATEMENT: {
1686                 if (const auto *labelled = iter->AsLabelledStatement(); labelled->Ident()->Name() == target->Name()) {
1687                     return nodeType == ir::AstNodeType::CONTINUE_STATEMENT ? labelled->GetReferencedStatement()
1688                                                                            : labelled;
1689                 }
1690                 break;
1691             }
1692             case ir::AstNodeType::DO_WHILE_STATEMENT:
1693             case ir::AstNodeType::WHILE_STATEMENT:
1694             case ir::AstNodeType::FOR_UPDATE_STATEMENT:
1695             case ir::AstNodeType::FOR_OF_STATEMENT:
1696             case ir::AstNodeType::SWITCH_STATEMENT: {
1697                 if (target == nullptr) {
1698                     return iter;
1699                 }
1700                 break;
1701             }
1702             default: {
1703                 break;
1704             }
1705         }
1706 
1707         iter = iter->Parent();
1708     }
1709 
1710     UNREACHABLE();
1711     return nullptr;
1712 }
1713 
GetAccessFlagFromNode(const ir::AstNode * node)1714 varbinder::VariableFlags ETSChecker::GetAccessFlagFromNode(const ir::AstNode *node)
1715 {
1716     if (node->IsPrivate()) {
1717         return varbinder::VariableFlags::PRIVATE;
1718     }
1719 
1720     if (node->IsProtected()) {
1721         return varbinder::VariableFlags::PROTECTED;
1722     }
1723 
1724     return varbinder::VariableFlags::PUBLIC;
1725 }
1726 
CheckSwitchDiscriminant(ir::Expression * discriminant)1727 void ETSChecker::CheckSwitchDiscriminant(ir::Expression *discriminant)
1728 {
1729     ASSERT(discriminant->TsType());
1730 
1731     auto discriminantType = discriminant->TsType();
1732     if (discriminantType->HasTypeFlag(TypeFlag::VALID_SWITCH_TYPE)) {
1733         return;
1734     }
1735 
1736     if (discriminantType->IsETSObjectType() &&
1737         discriminantType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::VALID_SWITCH_TYPE)) {
1738         if (discriminantType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) {
1739             discriminant->SetBoxingUnboxingFlags(GetUnboxingFlag(ETSBuiltinTypeAsPrimitiveType(discriminantType)));
1740         }
1741         return;
1742     }
1743 
1744     ThrowTypeError({"Incompatible types. Found: ", discriminantType,
1745                     ", required: char , byte , short , int, long , Char , Byte , Short , Int, Long , String "
1746                     "or an enum type"},
1747                    discriminant->Start());
1748 }
1749 
ETSBuiltinTypeAsPrimitiveType(Type * objectType)1750 Type *ETSChecker::ETSBuiltinTypeAsPrimitiveType(Type *objectType)
1751 {
1752     if (objectType == nullptr) {
1753         return nullptr;
1754     }
1755 
1756     if (objectType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) || objectType->HasTypeFlag(TypeFlag::ETS_ENUM) ||
1757         objectType->HasTypeFlag(TypeFlag::ETS_STRING_ENUM)) {
1758         return objectType;
1759     }
1760 
1761     if (!objectType->IsETSObjectType() ||
1762         !objectType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) {
1763         return nullptr;
1764     }
1765 
1766     auto savedResult = Relation()->IsTrue();
1767     Relation()->Result(false);
1768 
1769     UnboxingConverter converter = UnboxingConverter(AsETSChecker(), Relation(), objectType, objectType);
1770     Relation()->Result(savedResult);
1771     return converter.Result();
1772 }
1773 
ETSBuiltinTypeAsConditionalType(Type * objectType)1774 Type *ETSChecker::ETSBuiltinTypeAsConditionalType(Type *objectType)
1775 {
1776     if ((objectType == nullptr) || !objectType->IsConditionalExprType()) {
1777         return nullptr;
1778     }
1779 
1780     return objectType;
1781 }
1782 
PrimitiveTypeAsETSBuiltinType(Type * objectType)1783 Type *ETSChecker::PrimitiveTypeAsETSBuiltinType(Type *objectType)
1784 {
1785     if (objectType == nullptr) {
1786         return nullptr;
1787     }
1788 
1789     if (objectType->IsETSObjectType() && objectType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) {
1790         return objectType;
1791     }
1792 
1793     if (!objectType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) || objectType->IsETSVoidType()) {
1794         return nullptr;
1795     }
1796 
1797     auto savedResult = Relation()->IsTrue();
1798     Relation()->Result(false);
1799 
1800     if (Checker::GetGlobalTypesHolder()->GlobalIntegerBuiltinType() == nullptr) {
1801         InitializeBuiltin(VarBinder()->TopScope()->Bindings().find("Int")->second, "Int");
1802     }
1803 
1804     BoxingConverter converter = BoxingConverter(AsETSChecker(), Relation(), objectType,
1805                                                 Checker::GetGlobalTypesHolder()->GlobalIntegerBuiltinType());
1806     Relation()->Result(savedResult);
1807     return converter.Result();
1808 }
1809 
AddBoxingUnboxingFlagsToNode(ir::AstNode * node,Type * boxingUnboxingType)1810 void ETSChecker::AddBoxingUnboxingFlagsToNode(ir::AstNode *node, Type *boxingUnboxingType)
1811 {
1812     if (boxingUnboxingType->IsETSObjectType()) {
1813         node->AddBoxingUnboxingFlags(GetBoxingFlag(boxingUnboxingType));
1814     } else {
1815         node->AddBoxingUnboxingFlags(GetUnboxingFlag(boxingUnboxingType));
1816     }
1817 }
1818 
GetBoxingFlag(Type * const boxingType)1819 ir::BoxingUnboxingFlags ETSChecker::GetBoxingFlag(Type *const boxingType)
1820 {
1821     auto typeKind = TypeKind(ETSBuiltinTypeAsPrimitiveType(boxingType));
1822     switch (typeKind) {
1823         case TypeFlag::ETS_BOOLEAN: {
1824             return ir::BoxingUnboxingFlags::BOX_TO_BOOLEAN;
1825         }
1826         case TypeFlag::BYTE: {
1827             return ir::BoxingUnboxingFlags::BOX_TO_BYTE;
1828         }
1829         case TypeFlag::CHAR: {
1830             return ir::BoxingUnboxingFlags::BOX_TO_CHAR;
1831         }
1832         case TypeFlag::SHORT: {
1833             return ir::BoxingUnboxingFlags::BOX_TO_SHORT;
1834         }
1835         case TypeFlag::INT: {
1836             return ir::BoxingUnboxingFlags::BOX_TO_INT;
1837         }
1838         case TypeFlag::LONG: {
1839             return ir::BoxingUnboxingFlags::BOX_TO_LONG;
1840         }
1841         case TypeFlag::FLOAT: {
1842             return ir::BoxingUnboxingFlags::BOX_TO_FLOAT;
1843         }
1844         case TypeFlag::DOUBLE: {
1845             return ir::BoxingUnboxingFlags::BOX_TO_DOUBLE;
1846         }
1847         default:
1848             UNREACHABLE();
1849     }
1850 }
1851 
GetUnboxingFlag(Type const * const unboxingType) const1852 ir::BoxingUnboxingFlags ETSChecker::GetUnboxingFlag(Type const *const unboxingType) const
1853 {
1854     auto typeKind = TypeKind(unboxingType);
1855     switch (typeKind) {
1856         case TypeFlag::ETS_BOOLEAN: {
1857             return ir::BoxingUnboxingFlags::UNBOX_TO_BOOLEAN;
1858         }
1859         case TypeFlag::BYTE: {
1860             return ir::BoxingUnboxingFlags::UNBOX_TO_BYTE;
1861         }
1862         case TypeFlag::CHAR: {
1863             return ir::BoxingUnboxingFlags::UNBOX_TO_CHAR;
1864         }
1865         case TypeFlag::SHORT: {
1866             return ir::BoxingUnboxingFlags::UNBOX_TO_SHORT;
1867         }
1868         case TypeFlag::INT: {
1869             return ir::BoxingUnboxingFlags::UNBOX_TO_INT;
1870         }
1871         case TypeFlag::LONG: {
1872             return ir::BoxingUnboxingFlags::UNBOX_TO_LONG;
1873         }
1874         case TypeFlag::FLOAT: {
1875             return ir::BoxingUnboxingFlags::UNBOX_TO_FLOAT;
1876         }
1877         case TypeFlag::DOUBLE: {
1878             return ir::BoxingUnboxingFlags::UNBOX_TO_DOUBLE;
1879         }
1880         default:
1881             UNREACHABLE();
1882     }
1883 }
1884 
MaybeBoxedType(const varbinder::Variable * var,ArenaAllocator * allocator) const1885 Type *ETSChecker::MaybeBoxedType(const varbinder::Variable *var, ArenaAllocator *allocator) const
1886 {
1887     auto *varType = var->TsType();
1888     if (var->HasFlag(varbinder::VariableFlags::BOXED)) {
1889         switch (TypeKind(varType)) {
1890             case TypeFlag::ETS_BOOLEAN:
1891                 return GetGlobalTypesHolder()->GlobalBooleanBoxBuiltinType();
1892             case TypeFlag::BYTE:
1893                 return GetGlobalTypesHolder()->GlobalByteBoxBuiltinType();
1894             case TypeFlag::CHAR:
1895                 return GetGlobalTypesHolder()->GlobalCharBoxBuiltinType();
1896             case TypeFlag::SHORT:
1897                 return GetGlobalTypesHolder()->GlobalShortBoxBuiltinType();
1898             case TypeFlag::INT:
1899                 return GetGlobalTypesHolder()->GlobalIntBoxBuiltinType();
1900             case TypeFlag::LONG:
1901                 return GetGlobalTypesHolder()->GlobalLongBoxBuiltinType();
1902             case TypeFlag::FLOAT:
1903                 return GetGlobalTypesHolder()->GlobalFloatBoxBuiltinType();
1904             case TypeFlag::DOUBLE:
1905                 return GetGlobalTypesHolder()->GlobalDoubleBoxBuiltinType();
1906             default: {
1907                 Type *box = GetGlobalTypesHolder()->GlobalBoxBuiltinType()->Instantiate(allocator, Relation(),
1908                                                                                         GetGlobalTypesHolder());
1909                 box->AddTypeFlag(checker::TypeFlag::GENERIC);
1910                 box->AsETSObjectType()->TypeArguments().emplace_back(varType);
1911                 return box;
1912             }
1913         }
1914     }
1915     return varType;
1916 }
1917 
CheckForSameSwitchCases(ArenaVector<ir::SwitchCaseStatement * > * cases)1918 void ETSChecker::CheckForSameSwitchCases(ArenaVector<ir::SwitchCaseStatement *> *cases)
1919 {
1920     //  Just to avoid extra nesting level
1921     auto const checkEnumType = [this](ir::Expression const *const caseTest, ETSEnumType const *const type) -> void {
1922         if (caseTest->TsType()->AsETSEnumType()->IsSameEnumLiteralType(type)) {
1923             ThrowTypeError("Case duplicate", caseTest->Start());
1924         }
1925     };
1926 
1927     for (size_t caseNum = 0; caseNum < cases->size(); caseNum++) {
1928         for (size_t compareCase = caseNum + 1; compareCase < cases->size(); compareCase++) {
1929             auto *caseTest = cases->at(caseNum)->Test();
1930             auto *compareCaseTest = cases->at(compareCase)->Test();
1931 
1932             if (caseTest == nullptr || compareCaseTest == nullptr) {
1933                 continue;
1934             }
1935 
1936             if (caseTest->TsType()->IsETSEnumType()) {
1937                 checkEnumType(caseTest, compareCaseTest->TsType()->AsETSEnumType());
1938                 continue;
1939             }
1940 
1941             if (caseTest->IsIdentifier() || caseTest->IsMemberExpression()) {
1942                 CheckIdentifierSwitchCase(caseTest, compareCaseTest, cases->at(caseNum)->Start());
1943                 continue;
1944             }
1945 
1946             if (compareCaseTest->IsIdentifier() || compareCaseTest->IsMemberExpression()) {
1947                 CheckIdentifierSwitchCase(compareCaseTest, caseTest, cases->at(compareCase)->Start());
1948                 continue;
1949             }
1950 
1951             if (GetStringFromLiteral(caseTest) != GetStringFromLiteral(compareCaseTest)) {
1952                 continue;
1953             }
1954 
1955             ThrowTypeError("Case duplicate", cases->at(compareCase)->Start());
1956         }
1957     }
1958 }
1959 
GetStringFromIdentifierValue(checker::Type * caseType) const1960 std::string ETSChecker::GetStringFromIdentifierValue(checker::Type *caseType) const
1961 {
1962     const auto identifierTypeKind = ETSChecker::TypeKind(caseType);
1963     switch (identifierTypeKind) {
1964         case TypeFlag::BYTE: {
1965             return std::to_string(caseType->AsByteType()->GetValue());
1966         }
1967         case TypeFlag::SHORT: {
1968             return std::to_string(caseType->AsShortType()->GetValue());
1969         }
1970         case TypeFlag::CHAR: {
1971             return std::to_string(caseType->AsCharType()->GetValue());
1972         }
1973         case TypeFlag::INT: {
1974             return std::to_string(caseType->AsIntType()->GetValue());
1975         }
1976         case TypeFlag::LONG: {
1977             return std::to_string(caseType->AsLongType()->GetValue());
1978         }
1979         case TypeFlag::ETS_OBJECT: {
1980             VarBinder()->ThrowError(caseType->AsETSObjectType()->Variable()->Declaration()->Node()->Start(),
1981                                     "not implemented");
1982         }
1983         default: {
1984             UNREACHABLE();
1985         }
1986     }
1987 }
1988 
IsConstantMemberOrIdentifierExpression(ir::Expression * expression)1989 bool IsConstantMemberOrIdentifierExpression(ir::Expression *expression)
1990 {
1991     if (expression->IsMemberExpression()) {
1992         return expression->AsMemberExpression()->PropVar()->Declaration()->IsConstDecl();
1993     }
1994 
1995     if (expression->IsIdentifier()) {
1996         return expression->AsIdentifier()->Variable()->Declaration()->IsConstDecl();
1997     }
1998 
1999     return false;
2000 }
2001 
CompareIdentifiersValuesAreDifferent(ir::Expression * compareValue,const std::string & caseValue)2002 bool ETSChecker::CompareIdentifiersValuesAreDifferent(ir::Expression *compareValue, const std::string &caseValue)
2003 {
2004     if (IsConstantMemberOrIdentifierExpression(compareValue)) {
2005         checker::Type *compareCaseType = compareValue->TsType();
2006 
2007         const auto compareCaseValue = GetStringFromIdentifierValue(compareCaseType);
2008         return caseValue != compareCaseValue;
2009     }
2010 
2011     return caseValue != GetStringFromLiteral(compareValue);
2012 }
2013 
CheckIdentifierSwitchCase(ir::Expression * currentCase,ir::Expression * compareCase,const lexer::SourcePosition & pos)2014 void ETSChecker::CheckIdentifierSwitchCase(ir::Expression *currentCase, ir::Expression *compareCase,
2015                                            const lexer::SourcePosition &pos)
2016 {
2017     currentCase->Check(this);
2018 
2019     if (!IsConstantMemberOrIdentifierExpression(currentCase)) {
2020         ThrowTypeError("Constant expression required", pos);
2021     }
2022 
2023     checker::Type *caseType = currentCase->TsType();
2024 
2025     if (!CompareIdentifiersValuesAreDifferent(compareCase, GetStringFromIdentifierValue(caseType))) {
2026         ThrowTypeError("Variable has same value with another switch case", pos);
2027     }
2028 }
2029 
GetStringFromLiteral(ir::Expression * caseTest) const2030 std::string ETSChecker::GetStringFromLiteral(ir::Expression *caseTest) const
2031 {
2032     switch (caseTest->Type()) {
2033         case ir::AstNodeType::CHAR_LITERAL: {
2034             return std::to_string(caseTest->AsCharLiteral()->Char());
2035         }
2036         case ir::AstNodeType::STRING_LITERAL:
2037         case ir::AstNodeType::NUMBER_LITERAL: {
2038             return util::Helpers::LiteralToPropName(caseTest).Mutf8();
2039         }
2040         default:
2041             UNREACHABLE();
2042     }
2043 }
2044 
IsSameDeclarationType(varbinder::LocalVariable * target,varbinder::LocalVariable * compare)2045 bool ETSChecker::IsSameDeclarationType(varbinder::LocalVariable *target, varbinder::LocalVariable *compare)
2046 {
2047     if (target->Declaration()->Type() != compare->Declaration()->Type()) {
2048         return false;
2049     }
2050 
2051     if ((target->HasFlag(varbinder::VariableFlags::METHOD_REFERENCE) &&
2052          !compare->HasFlag(varbinder::VariableFlags::METHOD_REFERENCE)) ||
2053         (!target->HasFlag(varbinder::VariableFlags::METHOD_REFERENCE) &&
2054          compare->HasFlag(varbinder::VariableFlags::METHOD_REFERENCE))) {
2055         return false;
2056     }
2057 
2058     return true;
2059 }
2060 
AddBoxingFlagToPrimitiveType(TypeRelation * relation,Type * target)2061 void ETSChecker::AddBoxingFlagToPrimitiveType(TypeRelation *relation, Type *target)
2062 {
2063     auto boxingResult = PrimitiveTypeAsETSBuiltinType(target);
2064     if (boxingResult != nullptr) {
2065         relation->GetNode()->AddBoxingUnboxingFlags(GetBoxingFlag(boxingResult));
2066         relation->Result(true);
2067     }
2068 }
2069 
AddUnboxingFlagToPrimitiveType(TypeRelation * relation,Type * source,Type * self)2070 void ETSChecker::AddUnboxingFlagToPrimitiveType(TypeRelation *relation, Type *source, Type *self)
2071 {
2072     auto unboxingResult = UnboxingConverter(this, relation, source, self).Result();
2073     if ((unboxingResult != nullptr) && relation->IsTrue()) {
2074         relation->GetNode()->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxingResult));
2075     }
2076 }
2077 
CheckUnboxedTypeWidenable(TypeRelation * relation,Type * target,Type * self)2078 void ETSChecker::CheckUnboxedTypeWidenable(TypeRelation *relation, Type *target, Type *self)
2079 {
2080     checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(
2081         relation, TypeRelationFlag::ONLY_CHECK_WIDENING |
2082                       (relation->ApplyNarrowing() ? TypeRelationFlag::NARROWING : TypeRelationFlag::NONE));
2083     // NOTE: vpukhov. handle union type
2084     auto unboxedType = ETSBuiltinTypeAsPrimitiveType(target);
2085     if (unboxedType == nullptr) {
2086         return;
2087     }
2088     NarrowingWideningConverter(this, relation, unboxedType, self);
2089     if (!relation->IsTrue()) {
2090         relation->Result(relation->IsAssignableTo(self, unboxedType));
2091     }
2092 }
2093 
CheckUnboxedTypesAssignable(TypeRelation * relation,Type * source,Type * target)2094 void ETSChecker::CheckUnboxedTypesAssignable(TypeRelation *relation, Type *source, Type *target)
2095 {
2096     auto *unboxedSourceType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(source);
2097     auto *unboxedTargetType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target);
2098     if (unboxedSourceType == nullptr || unboxedTargetType == nullptr) {
2099         return;
2100     }
2101     relation->IsAssignableTo(unboxedSourceType, unboxedTargetType);
2102     if (relation->IsTrue()) {
2103         relation->GetNode()->AddBoxingUnboxingFlags(
2104             relation->GetChecker()->AsETSChecker()->GetUnboxingFlag(unboxedSourceType));
2105     }
2106 }
2107 
CheckBoxedSourceTypeAssignable(TypeRelation * relation,Type * source,Type * target)2108 void ETSChecker::CheckBoxedSourceTypeAssignable(TypeRelation *relation, Type *source, Type *target)
2109 {
2110     checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(
2111         relation, (relation->ApplyWidening() ? TypeRelationFlag::WIDENING : TypeRelationFlag::NONE) |
2112                       (relation->ApplyNarrowing() ? TypeRelationFlag::NARROWING : TypeRelationFlag::NONE));
2113     auto *boxedSourceType = relation->GetChecker()->AsETSChecker()->PrimitiveTypeAsETSBuiltinType(source);
2114     if (boxedSourceType == nullptr) {
2115         return;
2116     }
2117     // Do not box primitive in case of cast to dynamic types
2118     if (target->IsETSDynamicType()) {
2119         return;
2120     }
2121     relation->IsAssignableTo(boxedSourceType, target);
2122     if (relation->IsTrue() && !relation->OnlyCheckBoxingUnboxing()) {
2123         AddBoxingFlagToPrimitiveType(relation, boxedSourceType);
2124     } else {
2125         auto unboxedTargetType = ETSBuiltinTypeAsPrimitiveType(target);
2126         if (unboxedTargetType == nullptr) {
2127             return;
2128         }
2129         NarrowingWideningConverter(this, relation, unboxedTargetType, source);
2130         if (relation->IsTrue()) {
2131             AddBoxingFlagToPrimitiveType(relation, target);
2132         }
2133     }
2134 }
2135 
CheckUnboxedSourceTypeWithWideningAssignable(TypeRelation * relation,Type * source,Type * target)2136 void ETSChecker::CheckUnboxedSourceTypeWithWideningAssignable(TypeRelation *relation, Type *source, Type *target)
2137 {
2138     auto *unboxedSourceType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(source);
2139     if (unboxedSourceType == nullptr) {
2140         return;
2141     }
2142     relation->IsAssignableTo(unboxedSourceType, target);
2143     if (!relation->IsTrue() && relation->ApplyWidening()) {
2144         relation->GetChecker()->AsETSChecker()->CheckUnboxedTypeWidenable(relation, target, unboxedSourceType);
2145     }
2146     if (!relation->OnlyCheckBoxingUnboxing()) {
2147         relation->GetNode()->AddBoxingUnboxingFlags(
2148             relation->GetChecker()->AsETSChecker()->GetUnboxingFlag(unboxedSourceType));
2149     }
2150 }
2151 
CheckRethrowingParams(const ir::AstNode * ancestorFunction,const ir::AstNode * node)2152 bool ETSChecker::CheckRethrowingParams(const ir::AstNode *ancestorFunction, const ir::AstNode *node)
2153 {
2154     for (const auto param : ancestorFunction->AsScriptFunction()->Signature()->Function()->Params()) {
2155         if (node->AsCallExpression()->Callee()->AsIdentifier()->Name().Is(
2156                 param->AsETSParameterExpression()->Ident()->Name().Mutf8())) {
2157             return true;
2158         }
2159     }
2160     return false;
2161 }
2162 
CheckThrowingStatements(ir::AstNode * node)2163 void ETSChecker::CheckThrowingStatements(ir::AstNode *node)
2164 {
2165     ir::AstNode *ancestorFunction = FindAncestorGivenByType(node, ir::AstNodeType::SCRIPT_FUNCTION);
2166 
2167     if (ancestorFunction == nullptr) {
2168         ThrowTypeError(
2169             "This statement can cause an exception, therefore it must be enclosed in a try statement with a default "
2170             "catch clause",
2171             node->Start());
2172     }
2173 
2174     if (ancestorFunction->AsScriptFunction()->IsThrowing() ||
2175         (ancestorFunction->AsScriptFunction()->IsRethrowing() &&
2176          (!node->IsThrowStatement() && CheckRethrowingParams(ancestorFunction, node)))) {
2177         return;
2178     }
2179 
2180     if (!CheckThrowingPlacement(node, ancestorFunction)) {
2181         if (ancestorFunction->AsScriptFunction()->IsRethrowing() && !node->IsThrowStatement()) {
2182             ThrowTypeError(
2183                 "This statement can cause an exception, re-throwing functions can throw exception only by their "
2184                 "parameters.",
2185                 node->Start());
2186         }
2187 
2188         ThrowTypeError(
2189             "This statement can cause an exception, therefore it must be enclosed in a try statement with a default "
2190             "catch clause",
2191             node->Start());
2192     }
2193 }
2194 
CheckThrowingPlacement(ir::AstNode * node,const ir::AstNode * ancestorFunction)2195 bool ETSChecker::CheckThrowingPlacement(ir::AstNode *node, const ir::AstNode *ancestorFunction)
2196 {
2197     ir::AstNode *startPoint = node;
2198     ir::AstNode *enclosingCatchClause = nullptr;
2199     ir::BlockStatement *enclosingFinallyBlock = nullptr;
2200     ir::AstNode *p = startPoint->Parent();
2201 
2202     bool isHandled = false;
2203     const auto predicateFunc = [&enclosingCatchClause](ir::CatchClause *clause) {
2204         return clause == enclosingCatchClause;
2205     };
2206 
2207     do {
2208         if (p->IsTryStatement() && p->AsTryStatement()->HasDefaultCatchClause()) {
2209             enclosingCatchClause = FindAncestorGivenByType(startPoint, ir::AstNodeType::CATCH_CLAUSE, p);
2210             enclosingFinallyBlock = FindFinalizerOfTryStatement(startPoint, p);
2211             const auto catches = p->AsTryStatement()->CatchClauses();
2212             if (std::any_of(catches.begin(), catches.end(), predicateFunc)) {
2213                 startPoint = enclosingCatchClause;
2214             } else if (enclosingFinallyBlock != nullptr &&
2215                        enclosingFinallyBlock == p->AsTryStatement()->FinallyBlock()) {
2216                 startPoint = enclosingFinallyBlock;
2217             } else {
2218                 isHandled = true;
2219                 break;
2220             }
2221         }
2222 
2223         p = p->Parent();
2224     } while (p != ancestorFunction);
2225 
2226     return isHandled;
2227 }
2228 
FindFinalizerOfTryStatement(ir::AstNode * startFrom,const ir::AstNode * p)2229 ir::BlockStatement *ETSChecker::FindFinalizerOfTryStatement(ir::AstNode *startFrom, const ir::AstNode *p)
2230 {
2231     auto *iter = startFrom->Parent();
2232 
2233     do {
2234         if (iter->IsBlockStatement()) {
2235             ir::BlockStatement *finallyBlock = iter->AsBlockStatement();
2236 
2237             if (finallyBlock == p->AsTryStatement()->FinallyBlock()) {
2238                 return finallyBlock;
2239             }
2240         }
2241 
2242         iter = iter->Parent();
2243     } while (iter != p);
2244 
2245     return nullptr;
2246 }
2247 
CheckRethrowingFunction(ir::ScriptFunction * func)2248 void ETSChecker::CheckRethrowingFunction(ir::ScriptFunction *func)
2249 {
2250     bool foundThrowingParam = false;
2251 
2252     // It doesn't support lambdas yet.
2253     for (auto item : func->Params()) {
2254         auto const *type = item->AsETSParameterExpression()->Ident()->TypeAnnotation();
2255 
2256         if (type->IsETSTypeReference()) {
2257             auto *typeDecl = type->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Variable()->Declaration();
2258             if (typeDecl->IsTypeAliasDecl()) {
2259                 type = typeDecl->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation();
2260             }
2261         }
2262 
2263         if (type->IsETSFunctionType() && type->AsETSFunctionType()->IsThrowing()) {
2264             foundThrowingParam = true;
2265             break;
2266         }
2267     }
2268 
2269     if (!foundThrowingParam) {
2270         ThrowTypeError("A rethrowing function must have a throwing function parameter", func->Start());
2271     }
2272 }
2273 
GetRelevantArgumentedTypeFromChild(ETSObjectType * const child,ETSObjectType * const target)2274 ETSObjectType *ETSChecker::GetRelevantArgumentedTypeFromChild(ETSObjectType *const child, ETSObjectType *const target)
2275 {
2276     if (child->GetDeclNode() == target->GetDeclNode()) {
2277         auto *relevantType = CreateNewETSObjectType(child->Name(), child->GetDeclNode(), child->ObjectFlags());
2278 
2279         ArenaVector<Type *> params = child->TypeArguments();
2280 
2281         relevantType->SetTypeArguments(std::move(params));
2282         relevantType->SetEnclosingType(child->EnclosingType());
2283         relevantType->SetSuperType(child->SuperType());
2284 
2285         return relevantType;
2286     }
2287 
2288     ASSERT(child->SuperType() != nullptr);
2289 
2290     return GetRelevantArgumentedTypeFromChild(child->SuperType(), target);
2291 }
2292 
TypeToString(std::stringstream & ss,Type * tp)2293 static void TypeToString(std::stringstream &ss, Type *tp)
2294 {
2295     if (tp->IsETSTypeParameter()) {
2296         ss << tp->AsETSTypeParameter()->GetDeclNode()->Start().index;
2297         ss << ".";
2298     }
2299     if (!tp->IsETSObjectType()) {
2300         tp->ToString(ss);
2301         return;
2302     }
2303     auto *const objType = tp->AsETSObjectType();
2304     ss << objType->Name();
2305 
2306     if (!objType->TypeArguments().empty()) {
2307         auto typeArgs = objType->TypeArguments();
2308         ss << "<";
2309         for (auto *ta : typeArgs) {
2310             TypeToString(ss, ta);
2311             ss << ";";
2312         }
2313         ss << ">";
2314     }
2315 
2316     if (tp->ContainsNull()) {
2317         ss << "|null";
2318     }
2319 
2320     if (tp->ContainsUndefined()) {
2321         ss << "|undefined";
2322     }
2323 }
2324 
EmplaceSubstituted(Substitution * substitution,ETSTypeParameter * tparam,Type * typeArg)2325 void ETSChecker::EmplaceSubstituted(Substitution *substitution, ETSTypeParameter *tparam, Type *typeArg)
2326 {
2327     substitution->emplace(tparam, typeArg);
2328 }
2329 
GetHashFromTypeArguments(const ArenaVector<Type * > & typeArgTypes)2330 util::StringView ETSChecker::GetHashFromTypeArguments(const ArenaVector<Type *> &typeArgTypes)
2331 {
2332     std::stringstream ss;
2333 
2334     for (auto *it : typeArgTypes) {
2335         TypeToString(ss, it);
2336         ss << compiler::Signatures::MANGLE_SEPARATOR;
2337     }
2338 
2339     return util::UString(ss.str(), Allocator()).View();
2340 }
2341 
GetHashFromSubstitution(const Substitution * substitution)2342 util::StringView ETSChecker::GetHashFromSubstitution(const Substitution *substitution)
2343 {
2344     std::vector<std::string> fields;
2345     for (auto [k, v] : *substitution) {
2346         std::stringstream ss;
2347         TypeToString(ss, k);
2348         ss << ":";
2349         TypeToString(ss, v);
2350         fields.push_back(ss.str());
2351     }
2352     std::sort(fields.begin(), fields.end());
2353 
2354     std::stringstream ss;
2355     for (auto &fstr : fields) {
2356         ss << fstr;
2357         ss << ";";
2358     }
2359     return util::UString(ss.str(), Allocator()).View();
2360 }
2361 
GetOriginalBaseType(Type * const object)2362 ETSObjectType *ETSChecker::GetOriginalBaseType(Type *const object)
2363 {
2364     if (object == nullptr || !object->IsETSObjectType()) {
2365         return nullptr;
2366     }
2367 
2368     return object->AsETSObjectType()->GetOriginalBaseType();
2369 }
2370 
GetTypeFromTypeAnnotation(ir::TypeNode * const typeAnnotation)2371 Type *ETSChecker::GetTypeFromTypeAnnotation(ir::TypeNode *const typeAnnotation)
2372 {
2373     auto *type = typeAnnotation->GetType(this);
2374 
2375     if (!typeAnnotation->IsNullAssignable() && !typeAnnotation->IsUndefinedAssignable()) {
2376         return type;
2377     }
2378 
2379     if (!IsReferenceType(type)) {
2380         ThrowTypeError("Non reference types cannot be nullish.", typeAnnotation->Start());
2381     }
2382 
2383     if (type->IsNullish()) {
2384         return type;
2385     }
2386 
2387     TypeFlag nullishFlags {0};
2388     if (typeAnnotation->IsNullAssignable()) {
2389         nullishFlags |= TypeFlag::NULL_TYPE;
2390     }
2391     if (typeAnnotation->IsUndefinedAssignable()) {
2392         nullishFlags |= TypeFlag::UNDEFINED;
2393     }
2394     return CreateNullishType(type, nullishFlags, Allocator(), Relation(), GetGlobalTypesHolder());
2395 }
2396 
CheckValidGenericTypeParameter(Type * const argType,const lexer::SourcePosition & pos)2397 void ETSChecker::CheckValidGenericTypeParameter(Type *const argType, const lexer::SourcePosition &pos)
2398 {
2399     if (!argType->IsETSEnumType() && !argType->IsETSStringEnumType()) {
2400         return;
2401     }
2402     std::stringstream ss;
2403     argType->ToString(ss);
2404     ThrowTypeError("Type '" + ss.str() + "' is not valid for generic type arguments", pos);
2405 }
2406 
CheckNumberOfTypeArguments(ETSObjectType * const type,ir::TSTypeParameterInstantiation * const typeArgs,const lexer::SourcePosition & pos)2407 void ETSChecker::CheckNumberOfTypeArguments(ETSObjectType *const type, ir::TSTypeParameterInstantiation *const typeArgs,
2408                                             const lexer::SourcePosition &pos)
2409 {
2410     auto const &typeParams = type->TypeArguments();
2411     if (typeParams.empty()) {
2412         if (typeArgs != nullptr) {
2413             ThrowTypeError({"Type '", type, "' is not generic."}, pos);
2414         }
2415         return;
2416     }
2417 
2418     size_t minimumTypeArgs = std::count_if(typeParams.begin(), typeParams.end(), [](Type *param) {
2419         return param->AsETSTypeParameter()->GetDefaultType() == nullptr;
2420     });
2421     if (typeArgs == nullptr && minimumTypeArgs > 0) {
2422         ThrowTypeError({"Type '", type, "' is generic but type argument were not provided."}, pos);
2423     }
2424 
2425     if (typeArgs != nullptr &&
2426         ((minimumTypeArgs > typeArgs->Params().size()) || (typeParams.size() < typeArgs->Params().size()))) {
2427         ThrowTypeError({"Type '", type, "' has ", minimumTypeArgs, " number of type parameters, but ",
2428                         typeArgs->Params().size(), " type arguments were provided."},
2429                        pos);
2430     }
2431 }
2432 
NeedTypeInference(const ir::ScriptFunction * lambda)2433 bool ETSChecker::NeedTypeInference(const ir::ScriptFunction *lambda)
2434 {
2435     if (lambda->ReturnTypeAnnotation() == nullptr) {
2436         return true;
2437     }
2438     for (auto *const param : lambda->Params()) {
2439         const auto *const lambdaParam = param->AsETSParameterExpression()->Ident();
2440         if (lambdaParam->TypeAnnotation() == nullptr) {
2441             return true;
2442         }
2443     }
2444     return false;
2445 }
2446 
FindTypeInferenceArguments(const ArenaVector<ir::Expression * > & arguments)2447 std::vector<bool> ETSChecker::FindTypeInferenceArguments(const ArenaVector<ir::Expression *> &arguments)
2448 {
2449     std::vector<bool> argTypeInferenceRequired(arguments.size());
2450     size_t index = 0;
2451     for (ir::Expression *arg : arguments) {
2452         if (arg->IsArrowFunctionExpression()) {
2453             ir::ScriptFunction *const lambda = arg->AsArrowFunctionExpression()->Function();
2454             if (NeedTypeInference(lambda)) {
2455                 argTypeInferenceRequired[index] = true;
2456             }
2457         }
2458         ++index;
2459     }
2460     return argTypeInferenceRequired;
2461 }
2462 
DerefETSTypeReference(ir::AstNode * node)2463 static ir::AstNode *DerefETSTypeReference(ir::AstNode *node)
2464 {
2465     ASSERT(node->IsETSTypeReference());
2466     do {
2467         auto *name = node->AsETSTypeReference()->Part()->Name();
2468         ASSERT(name->IsIdentifier());
2469         auto *var = name->AsIdentifier()->Variable();
2470         ASSERT(var != nullptr);
2471         auto *declNode = var->Declaration()->Node();
2472         if (!declNode->IsTSTypeAliasDeclaration()) {
2473             return declNode;
2474         }
2475         node = declNode->AsTSTypeAliasDeclaration()->TypeAnnotation();
2476     } while (node->IsETSTypeReference());
2477     return node;
2478 }
2479 
CheckLambdaAssignable(ir::Expression * param,ir::ScriptFunction * lambda)2480 bool ETSChecker::CheckLambdaAssignable(ir::Expression *param, ir::ScriptFunction *lambda)
2481 {
2482     ASSERT(param->IsETSParameterExpression());
2483     ir::AstNode *typeAnn = param->AsETSParameterExpression()->Ident()->TypeAnnotation();
2484     if (typeAnn->IsETSTypeReference()) {
2485         typeAnn = DerefETSTypeReference(typeAnn);
2486     }
2487     if (!typeAnn->IsETSFunctionType()) {
2488         return false;
2489     }
2490     ir::ETSFunctionType *calleeType = typeAnn->AsETSFunctionType();
2491     return lambda->Params().size() == calleeType->Params().size();
2492 }
2493 
InferTypesForLambda(ir::ScriptFunction * lambda,ir::ETSFunctionType * calleeType)2494 void ETSChecker::InferTypesForLambda(ir::ScriptFunction *lambda, ir::ETSFunctionType *calleeType)
2495 {
2496     for (size_t i = 0; i < calleeType->Params().size(); ++i) {
2497         const auto *const calleeParam = calleeType->Params()[i]->AsETSParameterExpression()->Ident();
2498         auto *const lambdaParam = lambda->Params()[i]->AsETSParameterExpression()->Ident();
2499         if (lambdaParam->TypeAnnotation() == nullptr) {
2500             lambdaParam->SetTsTypeAnnotation(calleeParam->TypeAnnotation());
2501         }
2502     }
2503     if (lambda->ReturnTypeAnnotation() == nullptr) {
2504         lambda->SetReturnTypeAnnotation(calleeType->ReturnType());
2505     }
2506 }
2507 
TypeInference(Signature * signature,const ArenaVector<ir::Expression * > & arguments,TypeRelationFlag flags)2508 bool ETSChecker::TypeInference(Signature *signature, const ArenaVector<ir::Expression *> &arguments,
2509                                TypeRelationFlag flags)
2510 {
2511     bool invocable = true;
2512     auto const argumentCount = arguments.size();
2513     auto const parameterCount = signature->Params().size();
2514     auto const count = std::min(parameterCount, argumentCount);
2515 
2516     for (size_t index = 0U; index < count; ++index) {
2517         auto const &argument = arguments[index];
2518         if (!argument->IsArrowFunctionExpression()) {
2519             continue;
2520         }
2521 
2522         if (index == arguments.size() - 1 && (flags & TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA) != 0) {
2523             continue;
2524         }
2525 
2526         auto *const arrowFuncExpr = argument->AsArrowFunctionExpression();
2527         ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
2528         if (!NeedTypeInference(lambda)) {
2529             continue;
2530         }
2531 
2532         auto const *const param = signature->Function()->Params()[index]->AsETSParameterExpression()->Ident();
2533         ir::AstNode *typeAnn = param->TypeAnnotation();
2534 
2535         if (typeAnn->IsETSTypeReference()) {
2536             typeAnn = DerefETSTypeReference(typeAnn);
2537         }
2538 
2539         ASSERT(typeAnn->IsETSFunctionType());
2540         InferTypesForLambda(lambda, typeAnn->AsETSFunctionType());
2541         Type *const argType = arrowFuncExpr->Check(this);
2542 
2543         checker::InvocationContext invokationCtx(
2544             Relation(), arguments[index], argType, signature->Params()[index]->TsType(), arrowFuncExpr->Start(),
2545             {"Call argument at index ", index, " is not compatible with the signature's type at that index"}, flags);
2546 
2547         invocable &= invokationCtx.IsInvocable();
2548     }
2549     return invocable;
2550 }
2551 
AddUndefinedParamsForDefaultParams(const Signature * const signature,ArenaVector<panda::es2panda::ir::Expression * > & arguments,ETSChecker * checker)2552 void ETSChecker::AddUndefinedParamsForDefaultParams(const Signature *const signature,
2553                                                     ArenaVector<panda::es2panda::ir::Expression *> &arguments,
2554                                                     ETSChecker *checker)
2555 {
2556     if (!signature->Function()->IsDefaultParamProxy() || signature->Function()->Params().size() <= arguments.size()) {
2557         return;
2558     }
2559 
2560     uint32_t num = 0;
2561     for (size_t i = arguments.size(); i != signature->Function()->Params().size() - 1; i++) {
2562         if (auto const *const param = signature->Function()->Params()[i]->AsETSParameterExpression();
2563             !param->IsRestParameter()) {
2564             auto const *const typeAnn = param->Ident()->TypeAnnotation();
2565             if (typeAnn->IsETSPrimitiveType()) {
2566                 if (typeAnn->AsETSPrimitiveType()->GetPrimitiveType() == ir::PrimitiveType::BOOLEAN) {
2567                     arguments.push_back(checker->Allocator()->New<ir::BooleanLiteral>(false));
2568                 } else {
2569                     arguments.push_back(checker->Allocator()->New<ir::NumberLiteral>(lexer::Number(0)));
2570                 }
2571             } else {
2572                 // A proxy-function is called, so default reference parameters
2573                 // are initialized with null instead of undefined
2574                 auto *const nullLiteral = checker->Allocator()->New<ir::NullLiteral>();
2575                 nullLiteral->SetTsType(checker->GlobalETSNullType());
2576                 arguments.push_back(nullLiteral);
2577             }
2578             num |= (1U << (arguments.size() - 1));
2579         }
2580     }
2581     arguments.push_back(checker->Allocator()->New<ir::NumberLiteral>(lexer::Number(num)));
2582 }
2583 
ExtensionETSFunctionType(checker::Type * type)2584 bool ETSChecker::ExtensionETSFunctionType(checker::Type *type)
2585 {
2586     if (!type->IsETSFunctionType()) {
2587         return false;
2588     }
2589 
2590     for (auto *signature : type->AsETSFunctionType()->CallSignatures()) {
2591         if (signature->Function()->IsExtensionMethod()) {
2592             return true;
2593         }
2594     }
2595 
2596     return false;
2597 }
2598 
ValidateTupleMinElementSize(ir::ArrayExpression * const arrayExpr,ETSTupleType * tuple)2599 void ETSChecker::ValidateTupleMinElementSize(ir::ArrayExpression *const arrayExpr, ETSTupleType *tuple)
2600 {
2601     if (arrayExpr->Elements().size() < static_cast<size_t>(tuple->GetMinTupleSize())) {
2602         ThrowTypeError({"Few elements in array initializer for tuple with size of ",
2603                         static_cast<size_t>(tuple->GetMinTupleSize())},
2604                        arrayExpr->Start());
2605     }
2606 }
2607 
ModifyPreferredType(ir::ArrayExpression * const arrayExpr,Type * const newPreferredType)2608 void ETSChecker::ModifyPreferredType(ir::ArrayExpression *const arrayExpr, Type *const newPreferredType)
2609 {
2610     // After modifying the preferred type of an array expression, it needs to be rechecked at the call site
2611     arrayExpr->SetPreferredType(newPreferredType);
2612     arrayExpr->SetTsType(nullptr);
2613 
2614     for (auto *const element : arrayExpr->Elements()) {
2615         if (element->IsArrayExpression()) {
2616             ModifyPreferredType(element->AsArrayExpression(), nullptr);
2617         }
2618     }
2619 }
2620 
GenerateImplicitInstantiateArg(varbinder::LocalVariable * instantiateMethod,const std::string & className)2621 std::string GenerateImplicitInstantiateArg(varbinder::LocalVariable *instantiateMethod, const std::string &className)
2622 {
2623     auto callSignatures = instantiateMethod->TsType()->AsETSFunctionType()->CallSignatures();
2624     ASSERT(!callSignatures.empty());
2625     auto methodOwner = std::string(callSignatures[0]->Owner()->Name());
2626     std::string implicitInstantiateArgument = "()=>{return new " + className + "()";
2627     if (methodOwner != className) {
2628         implicitInstantiateArgument.append(" as " + methodOwner);
2629     }
2630     implicitInstantiateArgument.append("}");
2631     return implicitInstantiateArgument;
2632 }
2633 
TryTransformingToStaticInvoke(ir::Identifier * const ident,const Type * resolvedType)2634 bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, const Type *resolvedType)
2635 {
2636     ASSERT(ident->Parent()->IsCallExpression());
2637     ASSERT(ident->Parent()->AsCallExpression()->Callee() == ident);
2638 
2639     if (!resolvedType->IsETSObjectType()) {
2640         return false;
2641     }
2642 
2643     auto className = ident->Name();
2644     std::string_view propertyName;
2645 
2646     PropertySearchFlags searchFlag = PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::SEARCH_IN_BASE |
2647                                      PropertySearchFlags::SEARCH_STATIC_METHOD;
2648     // clang-format off
2649     auto *instantiateMethod =
2650         resolvedType->AsETSObjectType()->GetProperty(compiler::Signatures::STATIC_INSTANTIATE_METHOD, searchFlag);
2651     if (instantiateMethod != nullptr) {
2652         propertyName = compiler::Signatures::STATIC_INSTANTIATE_METHOD;
2653     } else if (auto *invokeMethod =
2654                     resolvedType->AsETSObjectType()->GetProperty(compiler::Signatures::STATIC_INVOKE_METHOD, searchFlag);
2655                 invokeMethod != nullptr) {
2656         propertyName = compiler::Signatures::STATIC_INVOKE_METHOD;
2657     } else {
2658         ThrowTypeError({"No static ", compiler::Signatures::STATIC_INVOKE_METHOD, " method and static ",
2659                         compiler::Signatures::STATIC_INSTANTIATE_METHOD, " method in ", className, ". ", className,
2660                         "() is not allowed."},
2661                        ident->Start());
2662     }
2663     // clang-format on
2664 
2665     auto *classId = AllocNode<ir::Identifier>(className, Allocator());
2666     auto *methodId = AllocNode<ir::Identifier>(propertyName, Allocator());
2667     auto *transformedCallee =
2668         AllocNode<ir::MemberExpression>(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
2669 
2670     classId->SetRange(ident->Range());
2671     methodId->SetRange(ident->Range());
2672     transformedCallee->SetRange(ident->Range());
2673 
2674     auto *callExpr = ident->Parent()->AsCallExpression();
2675     transformedCallee->SetParent(callExpr);
2676     callExpr->SetCallee(transformedCallee);
2677 
2678     if (instantiateMethod != nullptr) {
2679         std::string implicitInstantiateArgument =
2680             GenerateImplicitInstantiateArg(instantiateMethod, std::string(className));
2681 
2682         parser::Program program(Allocator(), VarBinder());
2683         es2panda::CompilerOptions options;
2684         auto parser = parser::ETSParser(&program, options, parser::ParserStatus::NO_OPTS);
2685         auto *argExpr = parser.CreateExpression(implicitInstantiateArgument);
2686         compiler::InitScopesPhaseETS::RunExternalNode(argExpr, &program);
2687 
2688         argExpr->SetParent(callExpr);
2689         argExpr->SetRange(ident->Range());
2690 
2691         VarBinder()->AsETSBinder()->HandleCustomNodes(argExpr);
2692 
2693         auto &arguments = callExpr->Arguments();
2694         arguments.insert(arguments.begin(), argExpr);
2695     }
2696 
2697     return true;
2698 }
2699 }  // namespace panda::es2panda::checker
2700