• 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 "checker/checker.h"
17 #include "checker/ets/narrowingWideningConverter.h"
18 #include "checker/types/globalTypesHolder.h"
19 #include "checker/types/ets/etsObjectType.h"
20 #include "checker/types/ets/etsPartialTypeParameter.h"
21 #include "checker/types/typeFlag.h"
22 #include "ir/astNode.h"
23 #include "ir/base/catchClause.h"
24 #include "ir/expression.h"
25 #include "ir/typeNode.h"
26 #include "ir/base/scriptFunction.h"
27 #include "ir/base/classProperty.h"
28 #include "ir/base/methodDefinition.h"
29 #include "ir/statements/variableDeclarator.h"
30 #include "ir/statements/switchCaseStatement.h"
31 #include "ir/expressions/identifier.h"
32 #include "ir/expressions/callExpression.h"
33 #include "ir/expressions/memberExpression.h"
34 #include "ir/expressions/arrowFunctionExpression.h"
35 #include "ir/statements/labelledStatement.h"
36 #include "ir/statements/tryStatement.h"
37 #include "ir/ets/etsNewClassInstanceExpression.h"
38 #include "ir/ets/etsParameterExpression.h"
39 #include "ir/ts/tsTypeAliasDeclaration.h"
40 #include "ir/ts/tsEnumMember.h"
41 #include "ir/ts/tsTypeParameter.h"
42 #include "ir/ets/etsUnionType.h"
43 #include "ir/ets/etsTypeReference.h"
44 #include "ir/ets/etsTypeReferencePart.h"
45 #include "utils/arena_containers.h"
46 #include "varbinder/variable.h"
47 #include "varbinder/scope.h"
48 #include "varbinder/declaration.h"
49 #include "parser/program/program.h"
50 #include "checker/ETSchecker.h"
51 #include "varbinder/ETSBinder.h"
52 #include "checker/ets/typeRelationContext.h"
53 #include "checker/ets/boxingConverter.h"
54 #include "checker/ets/unboxingConverter.h"
55 #include "util/helpers.h"
56 
57 namespace ark::es2panda::checker {
CheckTruthinessOfType(ir::Expression * expr)58 void ETSChecker::CheckTruthinessOfType(ir::Expression *expr)
59 {
60     auto *const testType = expr->Check(this);
61     auto *const conditionType = MaybeUnboxConditionalInRelation(testType);
62 
63     expr->SetTsType(conditionType);
64 
65     if (conditionType == nullptr || (!conditionType->IsTypeError() && !conditionType->IsConditionalExprType())) {
66         LogTypeError("Condition must be of possible condition type", expr->Start());
67         return;
68     }
69 
70     if (conditionType->IsETSVoidType()) {
71         LogTypeError("An expression of type 'void' cannot be tested for truthiness", expr->Start());
72         return;
73     }
74 
75     if (conditionType->IsETSPrimitiveType()) {
76         FlagExpressionWithUnboxing(testType, conditionType, expr);
77     }
78 }
79 
CheckNonNullish(ir::Expression const * expr)80 bool ETSChecker::CheckNonNullish(ir::Expression const *expr)
81 {
82     if (expr->TsType()->PossiblyETSNullish()) {
83         LogTypeError("Value is possibly nullish.", expr->Start());
84         return false;
85     }
86     return true;
87 }
88 
GetNonNullishType(Type * type)89 Type *ETSChecker::GetNonNullishType(Type *type)
90 {
91     if (type->DefinitelyNotETSNullish()) {
92         return type;
93     }
94     if (type->IsETSTypeParameter()) {
95         return Allocator()->New<ETSNonNullishType>(type->AsETSTypeParameter());
96     }
97 
98     if (type->IsETSNullType() || type->IsETSUndefinedType()) {
99         return GetGlobalTypesHolder()->GlobalETSNeverType();
100     }
101 
102     ArenaVector<Type *> copied(Allocator()->Adapter());
103     for (auto const &t : type->AsETSUnionType()->ConstituentTypes()) {
104         if (t->IsETSNullType() || t->IsETSUndefinedType()) {
105             continue;
106         }
107         copied.push_back(GetNonNullishType(t));
108     }
109     return copied.empty() ? GetGlobalTypesHolder()->GlobalETSNeverType() : CreateETSUnionType(std::move(copied));
110 }
111 
RemoveNullType(Type * const type)112 Type *ETSChecker::RemoveNullType(Type *const type)
113 {
114     if (type->DefinitelyNotETSNullish() || type->IsETSUndefinedType()) {
115         return type;
116     }
117 
118     if (type->IsETSTypeParameter()) {
119         return Allocator()->New<ETSNonNullishType>(type->AsETSTypeParameter());
120     }
121 
122     if (type->IsETSNullType()) {
123         return GetGlobalTypesHolder()->GlobalETSNeverType();
124     }
125 
126     ASSERT(type->IsETSUnionType());
127     ArenaVector<Type *> copiedTypes(Allocator()->Adapter());
128 
129     for (auto *constituentType : type->AsETSUnionType()->ConstituentTypes()) {
130         if (!constituentType->IsETSNullType()) {
131             copiedTypes.push_back(RemoveNullType(constituentType));
132         }
133     }
134 
135     return copiedTypes.empty() ? GetGlobalTypesHolder()->GlobalETSNeverType()
136                                : CreateETSUnionType(std::move(copiedTypes));
137 }
138 
RemoveUndefinedType(Type * const type)139 Type *ETSChecker::RemoveUndefinedType(Type *const type)
140 {
141     if (type->DefinitelyNotETSNullish() || type->IsETSNullType()) {
142         return type;
143     }
144 
145     if (type->IsETSTypeParameter()) {
146         return Allocator()->New<ETSNonNullishType>(type->AsETSTypeParameter());
147     }
148 
149     if (type->IsETSUndefinedType()) {
150         return GetGlobalTypesHolder()->GlobalETSNeverType();
151     }
152 
153     ASSERT(type->IsETSUnionType());
154     ArenaVector<Type *> copiedTypes(Allocator()->Adapter());
155 
156     for (auto *constituentType : type->AsETSUnionType()->ConstituentTypes()) {
157         if (!constituentType->IsETSUndefinedType()) {
158             copiedTypes.push_back(RemoveUndefinedType(constituentType));
159         }
160     }
161 
162     return copiedTypes.empty() ? GetGlobalTypesHolder()->GlobalETSNeverType()
163                                : CreateETSUnionType(std::move(copiedTypes));
164 }
165 
RemoveNullishTypes(Type * type)166 std::pair<Type *, Type *> ETSChecker::RemoveNullishTypes(Type *type)
167 {
168     if (type->DefinitelyNotETSNullish()) {
169         return {GetGlobalTypesHolder()->GlobalETSNeverType(), type};
170     }
171 
172     if (type->IsETSTypeParameter()) {
173         return {GetGlobalTypesHolder()->GlobalETSNullishType(),
174                 Allocator()->New<ETSNonNullishType>(type->AsETSTypeParameter())};
175     }
176 
177     if (type->IsETSUndefinedType() || type->IsETSNullType()) {
178         return {type, GetGlobalTypesHolder()->GlobalETSNeverType()};
179     }
180 
181     ASSERT(type->IsETSUnionType());
182     ArenaVector<Type *> nullishTypes(Allocator()->Adapter());
183     ArenaVector<Type *> notNullishTypes(Allocator()->Adapter());
184 
185     for (auto *constituentType : type->AsETSUnionType()->ConstituentTypes()) {
186         if (constituentType->IsETSUndefinedType() || constituentType->IsETSNullType()) {
187             nullishTypes.push_back(constituentType);
188         } else {
189             notNullishTypes.push_back(!constituentType->IsETSTypeParameter()
190                                           ? constituentType
191                                           : Allocator()->New<ETSNonNullishType>(constituentType->AsETSTypeParameter()));
192         }
193     }
194 
195     Type *nullishType = nullishTypes.empty() ? GetGlobalTypesHolder()->GlobalETSNeverType()
196                                              : CreateETSUnionType(std::move(nullishTypes));
197     Type *notNullishType = notNullishTypes.empty() ? GetGlobalTypesHolder()->GlobalETSNeverType()
198                                                    : CreateETSUnionType(std::move(notNullishTypes));
199     return {nullishType, notNullishType};
200 }
201 
202 // NOTE(vpukhov): can be implemented with relation if etscompiler will support it
203 template <typename Pred, typename Trv>
MatchConstituentOrConstraint(const Type * type,Pred const & pred,Trv const & trv)204 static bool MatchConstituentOrConstraint(const Type *type, Pred const &pred, Trv const &trv)
205 {
206     auto const traverse = [&pred, &trv](const Type *ttype) {
207         return MatchConstituentOrConstraint<Pred, Trv>(ttype, pred, trv);
208     };
209     if (pred(type)) {
210         return true;
211     }
212     if (!trv(type)) {
213         return false;
214     }
215     if (type->IsETSUnionType()) {
216         for (auto const &ctype : type->AsETSUnionType()->ConstituentTypes()) {
217             if (traverse(ctype)) {
218                 return true;
219             }
220         }
221         return false;
222     }
223     if (type->IsETSTypeParameter()) {
224         return traverse(type->AsETSTypeParameter()->GetConstraintType());
225     }
226     if (type->IsETSNonNullishType()) {
227         auto tparam = type->AsETSNonNullishType()->GetUnderlying();
228         return traverse(tparam->GetConstraintType());
229     }
230     if (type->IsETSPartialTypeParameter()) {
231         auto tparam = type->AsETSPartialTypeParameter()->GetUnderlying();
232         return traverse(tparam->GetConstraintType());
233     }
234     return false;
235 }
236 
237 template <typename Pred>
MatchConstituentOrConstraint(const Type * type,Pred const & pred)238 static bool MatchConstituentOrConstraint(const Type *type, Pred const &pred)
239 {
240     return MatchConstituentOrConstraint(type, pred, []([[maybe_unused]] const Type *t) { return true; });
241 }
242 
PossiblyETSNull() const243 bool Type::PossiblyETSNull() const
244 {
245     return MatchConstituentOrConstraint(
246         this, [](const Type *t) { return t->IsETSNullType(); },
247         [](const Type *t) { return !t->IsETSNonNullishType(); });
248 }
249 
PossiblyETSUndefined() const250 bool Type::PossiblyETSUndefined() const
251 {
252     return MatchConstituentOrConstraint(
253         this, [](const Type *t) { return t->IsETSUndefinedType(); },
254         [](const Type *t) { return !t->IsETSNonNullishType(); });
255 }
256 
PossiblyETSNullish() const257 bool Type::PossiblyETSNullish() const
258 {
259     return MatchConstituentOrConstraint(
260         this, [](const Type *t) { return t->IsETSNullType() || t->IsETSUndefinedType(); },
261         [](const Type *t) { return !t->IsETSNonNullishType(); });
262 }
263 
DefinitelyETSNullish() const264 bool Type::DefinitelyETSNullish() const
265 {
266     return !MatchConstituentOrConstraint(
267         this,
268         [](const Type *t) {
269             return !(t->IsTypeParameter() || t->IsETSUnionType() || t->IsETSNullType() || t->IsETSUndefinedType());
270         },
271         [](const Type *t) { return !t->IsETSNonNullishType(); });
272 }
273 
DefinitelyNotETSNullish() const274 bool Type::DefinitelyNotETSNullish() const
275 {
276     return !PossiblyETSNullish();
277 }
278 
PossiblyETSString() const279 bool Type::PossiblyETSString() const
280 {
281     return MatchConstituentOrConstraint(this, [](const Type *t) {
282         return t->IsETSStringType() || (t->IsETSObjectType() && t->AsETSObjectType()->IsGlobalETSObjectType());
283     });
284 }
285 
IsValueTypedObjectType(ETSObjectType const * t)286 static bool IsValueTypedObjectType(ETSObjectType const *t)
287 {
288     return t->IsGlobalETSObjectType() || t->HasObjectFlag(ETSObjectFlags::VALUE_TYPED);
289 }
290 
PossiblyETSValueTyped() const291 bool Type::PossiblyETSValueTyped() const
292 {
293     return MatchConstituentOrConstraint(this, [](const Type *t) {
294         return t->IsNullType() || t->IsUndefinedType() ||
295                (t->IsETSObjectType() && IsValueTypedObjectType(t->AsETSObjectType()));
296     });
297 }
298 
PossiblyETSValueTypedExceptNullish() const299 bool Type::PossiblyETSValueTypedExceptNullish() const
300 {
301     return MatchConstituentOrConstraint(
302         this, [](const Type *t) { return t->IsETSObjectType() && IsValueTypedObjectType(t->AsETSObjectType()); });
303 }
304 
IsETSArrowType() const305 bool Type::IsETSArrowType() const
306 {
307     return IsETSFunctionType() && AsETSFunctionType()->CallSignatures().size() == 1;
308 }
309 
IsSaneETSReferenceType(Type const * type)310 [[maybe_unused]] static bool IsSaneETSReferenceType(Type const *type)
311 {
312     static constexpr TypeFlag ETS_SANE_REFERENCE_TYPE =
313         TypeFlag::TYPE_ERROR | TypeFlag::ETS_NULL | TypeFlag::ETS_UNDEFINED | TypeFlag::ETS_OBJECT |
314         TypeFlag::ETS_TYPE_PARAMETER | TypeFlag::WILDCARD | TypeFlag::ETS_NONNULLISH |
315         TypeFlag::ETS_REQUIRED_TYPE_PARAMETER | TypeFlag::ETS_NEVER | TypeFlag::ETS_UNION | TypeFlag::ETS_ARRAY |
316         TypeFlag::FUNCTION | TypeFlag::ETS_PARTIAL_TYPE_PARAMETER;
317 
318     // Issues
319     if (type->IsETSVoidType()) {  // NOTE(vpukhov): #19701 void refactoring
320         return true;
321     }
322     if (type->IsETSTypeAliasType()) {  // NOTE(vpukhov): #20561
323         return true;
324     }
325     if (type->IsNeverType()) {  // NOTE(vpukhov): #20562 We use ets/never and ts/never simultaneously
326         return true;
327     }
328     return type->HasTypeFlag(ETS_SANE_REFERENCE_TYPE);
329 }
330 
IsETSPrimitiveType() const331 bool Type::IsETSPrimitiveType() const
332 {
333     static constexpr TypeFlag ETS_PRIMITIVE =
334         TypeFlag::ETS_NUMERIC | TypeFlag::CHAR | TypeFlag::ETS_BOOLEAN | TypeFlag::ETS_ENUM;
335 
336     // Do not modify
337     ASSERT(!HasTypeFlag(ETS_PRIMITIVE) == IsSaneETSReferenceType(this));
338     return HasTypeFlag(ETS_PRIMITIVE);
339 }
340 
IsETSReferenceType() const341 bool Type::IsETSReferenceType() const
342 {
343     // Do not modify
344     return !IsETSPrimitiveType();
345 }
346 
IsETSUnboxableObject() const347 bool Type::IsETSUnboxableObject() const
348 {
349     return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE);
350 }
351 
IsConstantExpression(ir::Expression * expr,Type * type)352 bool ETSChecker::IsConstantExpression(ir::Expression *expr, Type *type)
353 {
354     return (type->HasTypeFlag(TypeFlag::CONSTANT) && (expr->IsIdentifier() || expr->IsMemberExpression()));
355 }
356 
GetNonConstantType(Type * type)357 Type *ETSChecker::GetNonConstantType(Type *type)
358 {
359     if (type->IsETSStringType()) {
360         return GlobalBuiltinETSStringType();
361     }
362 
363     if (type->IsETSBigIntType()) {
364         return GlobalETSBigIntType();
365     }
366 
367     if (type->IsETSUnionType()) {
368         return CreateETSUnionType(ETSUnionType::GetNonConstantTypes(this, type->AsETSUnionType()->ConstituentTypes()));
369     }
370 
371     if (!type->IsETSPrimitiveType()) {
372         return type;
373     }
374 
375     if (type->HasTypeFlag(TypeFlag::LONG)) {
376         return GlobalLongType();
377     }
378 
379     if (type->HasTypeFlag(TypeFlag::BYTE)) {
380         return GlobalByteType();
381     }
382 
383     if (type->HasTypeFlag(TypeFlag::SHORT)) {
384         return GlobalShortType();
385     }
386 
387     if (type->HasTypeFlag(TypeFlag::CHAR)) {
388         return GlobalCharType();
389     }
390 
391     if (type->HasTypeFlag(TypeFlag::INT)) {
392         return GlobalIntType();
393     }
394 
395     if (type->HasTypeFlag(TypeFlag::FLOAT)) {
396         return GlobalFloatType();
397     }
398 
399     if (type->HasTypeFlag(TypeFlag::DOUBLE)) {
400         return GlobalDoubleType();
401     }
402 
403     if (type->IsETSBooleanType()) {
404         return GlobalETSBooleanType();
405     }
406     return type;
407 }
408 
GetTypeOfSetterGetter(varbinder::Variable * const var)409 Type *ETSChecker::GetTypeOfSetterGetter(varbinder::Variable *const var)
410 {
411     auto *propType = var->TsType()->AsETSFunctionType();
412     if (propType->HasTypeFlag(checker::TypeFlag::GETTER)) {
413         return propType->FindGetter()->ReturnType();
414     }
415     return propType->FindSetter()->Params()[0]->TsType();
416 }
417 
IterateInVariableContext(varbinder::Variable * const var)418 void ETSChecker::IterateInVariableContext(varbinder::Variable *const var)
419 {
420     // Before computing the given variables type, we have to make a new checker context frame so that the checking is
421     // done in the proper context, and have to enter the scope where the given variable is declared, so reference
422     // resolution works properly
423     auto *iter = var->Declaration()->Node()->Parent();
424     while (iter != nullptr) {
425         if (iter->IsMethodDefinition()) {
426             auto *methodDef = iter->AsMethodDefinition();
427             ASSERT(methodDef->TsType());
428             Context().SetContainingSignature(methodDef->Function()->Signature());
429         }
430 
431         if (iter->IsClassDefinition()) {
432             auto *classDef = iter->AsClassDefinition();
433             ETSObjectType *containingClass {};
434 
435             if (classDef->TsType() == nullptr) {
436                 containingClass = BuildBasicClassProperties(classDef);
437                 ResolveDeclaredMembersOfObject(containingClass);
438             } else {
439                 containingClass = classDef->TsType()->AsETSObjectType();
440             }
441 
442             ASSERT(classDef->TsType());
443             Context().SetContainingClass(containingClass);
444         }
445 
446         iter = iter->Parent();
447     }
448 }
449 
GetTypeFromVariableDeclaration(varbinder::Variable * const var)450 Type *ETSChecker::GetTypeFromVariableDeclaration(varbinder::Variable *const var)
451 {
452     switch (var->Declaration()->Type()) {
453         case varbinder::DeclType::CLASS: {
454             auto *classDef = var->Declaration()->Node()->AsClassDefinition();
455             BuildBasicClassProperties(classDef);
456             return classDef->TsType();
457         }
458         case varbinder::DeclType::ENUM_LITERAL:
459         case varbinder::DeclType::CONST:
460         case varbinder::DeclType::READONLY:
461         case varbinder::DeclType::LET:
462         case varbinder::DeclType::VAR: {
463             auto *declNode = var->Declaration()->Node();
464             if (var->Declaration()->Node()->IsIdentifier()) {
465                 declNode = declNode->Parent();
466             }
467             return declNode->Check(this);
468         }
469         case varbinder::DeclType::FUNC:
470         case varbinder::DeclType::IMPORT: {
471             return var->Declaration()->Node()->Check(this);
472         }
473         case varbinder::DeclType::TYPE_ALIAS: {
474             return GetTypeFromTypeAliasReference(var);
475         }
476         case varbinder::DeclType::INTERFACE: {
477             return BuildBasicInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration());
478         }
479         case varbinder::DeclType::ANNOTATIONUSAGE: {
480             return GlobalTypeError();
481         }
482         case varbinder::DeclType::ANNOTATIONDECL: {
483             return GlobalTypeError();
484         }
485         default: {
486             UNREACHABLE();
487         }
488     }
489 }
490 
GetTypeOfVariable(varbinder::Variable * const var)491 Type *ETSChecker::GetTypeOfVariable(varbinder::Variable *const var)
492 {
493     if (IsVariableGetterSetter(var)) {
494         return GetTypeOfSetterGetter(var);
495     }
496 
497     if (var->TsType() != nullptr) {
498         return var->TsType();
499     }
500 
501     // NOTE: kbaladurin. forbid usage of imported entities as types without declarations
502     if (VarBinder()->AsETSBinder()->IsDynamicModuleVariable(var)) {
503         auto *importData = VarBinder()->AsETSBinder()->DynamicImportDataForVar(var);
504         if (importData->import->IsPureDynamic()) {
505             return GlobalBuiltinDynamicType(importData->import->Language());
506         }
507     }
508 
509     checker::SavedCheckerContext savedContext(this, CheckerStatus::NO_OPTS);
510     checker::ScopeContext scopeCtx(this, var->GetScope());
511     IterateInVariableContext(var);
512 
513     return GetTypeFromVariableDeclaration(var);
514 }
515 
516 // Determine if unchecked cast is needed and yield guaranteed source type
GuaranteedTypeForUncheckedCast(Type * base,Type * substituted)517 Type *ETSChecker::GuaranteedTypeForUncheckedCast(Type *base, Type *substituted)
518 {
519     // Apparent type acts as effective representation for type.
520     //  For T extends SomeClass|undefined
521     //  Apparent(Int|T|null) is Int|SomeClass|undefined|null
522     auto *appBase = GetApparentType(base);
523     auto *appSubst = GetApparentType(substituted);
524     // Base is supertype of Substituted AND Substituted is supertype of Base
525     return Relation()->IsIdenticalTo(appSubst, appBase) ? nullptr : appBase;
526 }
527 
528 // Determine if substituted property access requires cast from erased type
GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable * const prop)529 Type *ETSChecker::GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable *const prop)
530 {
531     if (IsVariableStatic(prop)) {
532         return nullptr;
533     }
534     if (IsVariableGetterSetter(prop)) {
535         auto *method = prop->TsType()->AsETSFunctionType();
536         if (!method->HasTypeFlag(checker::TypeFlag::GETTER)) {
537             return nullptr;
538         }
539         return GuaranteedTypeForUncheckedCallReturn(method->FindGetter());
540     }
541     // NOTE(vpukhov): mark ETSDynamicType properties
542     if (prop->Declaration() == nullptr || prop->Declaration()->Node() == nullptr) {
543         return nullptr;
544     }
545 
546     varbinder::Variable *baseProp = nullptr;
547     switch (auto node = prop->Declaration()->Node(); node->Type()) {
548         case ir::AstNodeType::CLASS_PROPERTY:
549             baseProp = node->AsClassProperty()->Id()->Variable();
550             break;
551         case ir::AstNodeType::METHOD_DEFINITION:
552             baseProp = node->AsMethodDefinition()->Variable();
553             break;
554             // NOTE(vpukhov): should not be a case of unchecked access
555         case ir::AstNodeType::CLASS_DEFINITION:
556             baseProp = node->AsClassDefinition()->Ident()->Variable();
557             break;
558         default:
559             UNREACHABLE();
560     }
561 
562     if (baseProp == prop) {
563         return nullptr;
564     }
565     return GuaranteedTypeForUncheckedCast(GetTypeOfVariable(baseProp), GetTypeOfVariable(prop));
566 }
567 
568 // Determine if substituted method cast requires cast from erased type
GuaranteedTypeForUncheckedCallReturn(Signature * sig)569 Type *ETSChecker::GuaranteedTypeForUncheckedCallReturn(Signature *sig)
570 {
571     if (sig->HasSignatureFlag(checker::SignatureFlags::THIS_RETURN_TYPE)) {
572         return sig->ReturnType();
573     }
574     auto *baseSig = sig->Function()->Signature();
575     if (baseSig == sig) {
576         return nullptr;
577     }
578     return GuaranteedTypeForUncheckedCast(baseSig->ReturnType(), sig->ReturnType());
579 }
580 
CheckEtsFunctionType(ir::Identifier * const ident,ir::Identifier const * const id)581 void ETSChecker::CheckEtsFunctionType(ir::Identifier *const ident, ir::Identifier const *const id)
582 {
583     const auto *const targetType = GetTypeOfVariable(id->Variable());
584     ASSERT(targetType != nullptr);
585 
586     if (!targetType->IsETSObjectType() && !targetType->IsETSUnionType()) {
587         LogTypeError("Initializers type is not assignable to the target type", ident->Start());
588     }
589 }
590 
IsAllowedTypeAliasRecursion(const ir::TSTypeAliasDeclaration * typeAliasNode,std::unordered_set<const ir::TSTypeAliasDeclaration * > & typeAliases)591 bool ETSChecker::IsAllowedTypeAliasRecursion(const ir::TSTypeAliasDeclaration *typeAliasNode,
592                                              std::unordered_set<const ir::TSTypeAliasDeclaration *> &typeAliases)
593 {
594     bool isAllowedRerursiveType = true;
595 
596     RecursionPreserver<const ir::TSTypeAliasDeclaration> recursionPreserver(typeAliases, typeAliasNode);
597 
598     if (*recursionPreserver) {
599         return false;
600     }
601 
602     auto typeAliasDeclarationCheck = [this, &typeAliases](ir::ETSTypeReferencePart *part) {
603         if (!part->Name()->IsIdentifier()) {
604             return false;
605         }
606         if (part->Name()->AsIdentifier()->Variable() != nullptr &&
607             part->Name()->AsIdentifier()->Variable()->Declaration() != nullptr &&
608             part->Name()->AsIdentifier()->Variable()->Declaration()->Node() != nullptr &&
609             part->Name()->AsIdentifier()->Variable()->Declaration()->Node()->IsTSTypeAliasDeclaration()) {
610             auto *aliasTypeNode =
611                 part->Name()->AsIdentifier()->Variable()->Declaration()->Node()->AsTSTypeAliasDeclaration();
612             return IsAllowedTypeAliasRecursion(aliasTypeNode, typeAliases);
613         }
614 
615         return true;
616     };
617 
618     if (typeAliasNode->TypeAnnotation()->IsETSTypeReference()) {
619         isAllowedRerursiveType &=
620             typeAliasDeclarationCheck(typeAliasNode->TypeAnnotation()->AsETSTypeReference()->Part());
621     }
622 
623     if (isAllowedRerursiveType && typeAliasNode->TypeAnnotation()->IsETSUnionType()) {
624         for (auto &type : typeAliasNode->TypeAnnotation()->AsETSUnionType()->Types()) {
625             if (type->IsETSTypeReference()) {
626                 isAllowedRerursiveType &= typeAliasDeclarationCheck(type->AsETSTypeReference()->Part());
627             }
628         }
629     }
630 
631     return isAllowedRerursiveType;
632 }
633 
GetTypeFromTypeAliasReference(varbinder::Variable * var)634 Type *ETSChecker::GetTypeFromTypeAliasReference(varbinder::Variable *var)
635 {
636     if (var->TsType() != nullptr) {
637         return var->TsType();
638     }
639 
640     auto *const aliasTypeNode = var->Declaration()->Node()->AsTSTypeAliasDeclaration();
641     std::unordered_set<const ir::TSTypeAliasDeclaration *> typeAliases;
642     auto isAllowedRecursion = IsAllowedTypeAliasRecursion(aliasTypeNode, typeAliases);
643 
644     TypeStackElement tse(this, aliasTypeNode, "Circular type alias reference", aliasTypeNode->Start(),
645                          isAllowedRecursion);
646 
647     if (tse.HasTypeError()) {
648         var->SetTsType(GlobalTypeError());
649         return GlobalTypeError();
650     }
651 
652     auto *typeAliasType = tse.GetElementType();
653 
654     if (typeAliasType != nullptr) {
655         typeAliasType->AsETSTypeAliasType()->SetRecursive();
656         return typeAliasType;
657     }
658 
659     typeAliasType = CreateETSTypeAliasType(aliasTypeNode->Id()->Name(), aliasTypeNode);
660     if (aliasTypeNode->TypeParams() != nullptr) {
661         auto [typeParamTypes, ok] = CreateUnconstrainedTypeParameters(aliasTypeNode->TypeParams());
662         typeAliasType->AsETSTypeAliasType()->SetTypeArguments(std::move(typeParamTypes));
663         if (ok) {
664             AssignTypeParameterConstraints(aliasTypeNode->TypeParams());
665         }
666     }
667     tse.SetElementType(typeAliasType);
668 
669     aliasTypeNode->Check(this);
670     Type *targetType = aliasTypeNode->TypeAnnotation()->GetType(this);
671     typeAliasType->AsETSTypeAliasType()->SetTargetType(targetType);
672     typeAliasType->AsETSTypeAliasType()->ApplySubstitution(Relation());
673 
674     var->SetTsType(targetType);
675     return targetType;
676 }
677 
GetTypeFromInterfaceReference(varbinder::Variable * var)678 Type *ETSChecker::GetTypeFromInterfaceReference(varbinder::Variable *var)
679 {
680     if (var->TsType() != nullptr) {
681         return var->TsType();
682     }
683 
684     auto *interfaceType = BuildBasicInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration());
685     var->SetTsType(interfaceType);
686     return interfaceType;
687 }
688 
GetTypeFromClassReference(varbinder::Variable * var)689 Type *ETSChecker::GetTypeFromClassReference(varbinder::Variable *var)
690 {
691     if (var->TsType() != nullptr) {
692         return var->TsType();
693     }
694 
695     auto *classType = BuildBasicClassProperties(var->Declaration()->Node()->AsClassDefinition());
696     var->SetTsType(classType);
697     return classType;
698 }
699 
GetTypeFromEnumReference(varbinder::Variable * var)700 Type *ETSChecker::GetTypeFromEnumReference([[maybe_unused]] varbinder::Variable *var)
701 {
702     if (var->TsType() != nullptr) {
703         return var->TsType();
704     }
705 
706     auto *const enumDecl = var->Declaration()->Node()->AsTSEnumDeclaration();
707     if (enumDecl->BoxedClass()->TsType() == nullptr) {
708         BuildBasicClassProperties(enumDecl->BoxedClass());
709     }
710     if (auto *const itemInit = enumDecl->Members().front()->AsTSEnumMember()->Init(); itemInit->IsNumberLiteral()) {
711         return CreateEnumIntTypeFromEnumDeclaration(enumDecl);
712     } else if (itemInit->IsStringLiteral()) {  // NOLINT(readability-else-after-return)
713         return CreateEnumStringTypeFromEnumDeclaration(enumDecl);
714     } else {  // NOLINT(readability-else-after-return)
715         return TypeError(var, "Invalid enumeration value type.", enumDecl->Start());
716     }
717 }
718 
GetTypeFromTypeParameterReference(varbinder::LocalVariable * var,const lexer::SourcePosition & pos)719 Type *ETSChecker::GetTypeFromTypeParameterReference(varbinder::LocalVariable *var, const lexer::SourcePosition &pos)
720 {
721     ASSERT(var->Declaration()->Node()->IsTSTypeParameter());
722     if ((var->Declaration()->Node()->AsTSTypeParameter()->Parent()->Parent()->IsClassDefinition() ||
723          var->Declaration()->Node()->AsTSTypeParameter()->Parent()->Parent()->IsTSInterfaceDeclaration()) &&
724         HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) {
725         return TypeError(var, FormatMsg({"Cannot make a static reference to the non-static type ", var->Name()}), pos);
726     }
727 
728     return var->TsType();
729 }
730 
CheckAmbientAnnotationFieldInitializer(ir::Expression * init,ir::Expression * expected)731 bool ETSChecker::CheckAmbientAnnotationFieldInitializer(ir::Expression *init, ir::Expression *expected)
732 {
733     if (init->Type() != expected->Type()) {
734         return false;
735     }
736 
737     switch (init->Type()) {
738         case ir::AstNodeType::NUMBER_LITERAL:
739         case ir::AstNodeType::BOOLEAN_LITERAL:
740         case ir::AstNodeType::STRING_LITERAL:
741         case ir::AstNodeType::ARRAY_EXPRESSION:
742         case ir::AstNodeType::MEMBER_EXPRESSION:
743         case ir::AstNodeType::UNARY_EXPRESSION: {
744             if (CheckAmbientAnnotationFieldInitializerValue(init, expected)) {
745                 break;
746             }
747             LogTypeError({"The initial value does not match the expected value."}, init->Start());
748             return false;
749         }
750         default:
751             UNREACHABLE();
752     }
753 
754     return true;
755 }
756 
IsValidateUnaryExpression(lexer::TokenType operatorType)757 static bool IsValidateUnaryExpression(lexer::TokenType operatorType)
758 {
759     return operatorType == lexer::TokenType::PUNCTUATOR_PLUS || operatorType == lexer::TokenType::PUNCTUATOR_MINUS;
760 }
761 
CheckAmbientAnnotationFieldInitializerValue(ir::Expression * init,ir::Expression * expected)762 bool ETSChecker::CheckAmbientAnnotationFieldInitializerValue(ir::Expression *init, ir::Expression *expected)
763 {
764     switch (init->Type()) {
765         case ir::AstNodeType::NUMBER_LITERAL: {
766             return init->AsNumberLiteral()->Number().GetDouble() == expected->AsNumberLiteral()->Number().GetDouble();
767         }
768         case ir::AstNodeType::BOOLEAN_LITERAL: {
769             return init->AsBooleanLiteral()->Value() == expected->AsBooleanLiteral()->Value();
770         }
771         case ir::AstNodeType::STRING_LITERAL: {
772             return init->AsStringLiteral()->Str() == expected->AsStringLiteral()->Str();
773         }
774         case ir::AstNodeType::ARRAY_EXPRESSION: {
775             const auto &elements = init->AsArrayExpression()->Elements();
776             const auto &expectedElements = expected->AsArrayExpression()->Elements();
777             if (elements.size() != expectedElements.size()) {
778                 return false;
779             }
780             for (size_t i = 0; i < elements.size(); ++i) {
781                 if (!CheckAmbientAnnotationFieldInitializer(elements[i], expectedElements[i])) {
782                     return false;
783                 }
784             }
785             return true;
786         }
787         case ir::AstNodeType::MEMBER_EXPRESSION: {
788             if (!Relation()->IsIdenticalTo(init->TsType(), expected->TsType())) {
789                 return false;
790             }
791             auto elem = init->AsMemberExpression()->Property()->AsIdentifier()->Name();
792             auto expectedElem = expected->AsMemberExpression()->Property()->AsIdentifier()->Name();
793             return elem == expectedElem;
794         }
795         case ir::AstNodeType::UNARY_EXPRESSION: {
796             if (!IsValidateUnaryExpression(init->AsUnaryExpression()->OperatorType()) ||
797                 !IsValidateUnaryExpression(expected->AsUnaryExpression()->OperatorType())) {
798                 LogTypeError("Illegal unary operator.", init->Start());
799                 return false;
800             }
801             if (init->AsUnaryExpression()->OperatorType() != expected->AsUnaryExpression()->OperatorType()) {
802                 return false;
803             }
804             return CheckAmbientAnnotationFieldInitializer(init->AsUnaryExpression()->Argument(),
805                                                           expected->AsUnaryExpression()->Argument());
806         }
807         default:
808             UNREACHABLE();
809     }
810 }
811 
CheckAmbientAnnotation(ir::AnnotationDeclaration * annoImpl,ir::AnnotationDeclaration * annoDecl)812 void ETSChecker::CheckAmbientAnnotation(ir::AnnotationDeclaration *annoImpl, ir::AnnotationDeclaration *annoDecl)
813 {
814     std::unordered_map<util::StringView, ir::ClassProperty *> fieldMap;
815 
816     for (auto *prop : annoDecl->Properties()) {
817         auto *field = prop->AsClassProperty();
818         fieldMap[field->Id()->Name()] = field;
819     }
820 
821     for (auto *prop : annoImpl->Properties()) {
822         auto *field = prop->AsClassProperty();
823         auto fieldName = field->Id()->Name();
824         auto fieldDeclIter = fieldMap.find(fieldName);
825         if (fieldDeclIter == fieldMap.end()) {
826             LogTypeError({"Field '", fieldName, "' is not defined in the ambient annotation '",
827                           annoDecl->GetBaseName()->Name(), "'."},
828                          field->Start());
829             continue;
830         }
831 
832         auto *fieldDecl = fieldDeclIter->second;
833         if (field->TsType() != fieldDecl->TsType()) {
834             LogTypeError({"Field '", fieldName, "' has a type mismatch with the ambient annotation '",
835                           annoDecl->GetBaseName()->Name(), "'."},
836                          field->TypeAnnotation()->Start());
837         }
838 
839         bool hasValueMismatch = (field->Value() == nullptr) != (fieldDecl->Value() == nullptr);
840         bool initializerInvalid = field->Value() != nullptr && fieldDecl->Value() != nullptr &&
841                                   !CheckAmbientAnnotationFieldInitializer(field->Value(), fieldDecl->Value());
842         if (hasValueMismatch || initializerInvalid) {
843             LogTypeError({"Initializer for field '", fieldName,
844                           "' does not match the expected definition in the ambient annotation '",
845                           annoDecl->GetBaseName()->Name(), "'."},
846                          field->Start());
847         }
848         fieldMap.erase(fieldDeclIter);
849     }
850 
851     for (auto it : fieldMap) {
852         LogTypeError({"Field '", it.second->Key()->AsIdentifier()->Name(), "' in annotation '",
853                       annoDecl->GetBaseName()->Name(),
854                       "' is declared in the ambient declaration but missing in the implementation."},
855                      annoImpl->Start());
856     }
857 }
858 
CheckDuplicateAnnotations(const ArenaVector<ir::AnnotationUsage * > & annotations)859 bool ETSChecker::CheckDuplicateAnnotations(const ArenaVector<ir::AnnotationUsage *> &annotations)
860 {
861     std::unordered_set<util::StringView> seenAnnotations;
862     for (const auto &anno : annotations) {
863         auto annoName = anno->GetBaseName()->Name();
864         if (seenAnnotations.find(annoName) != seenAnnotations.end()) {
865             LogTypeError({"Duplicate annotations are not allowed. The annotation '", annoName,
866                           "' has already been applied to this element."},
867                          anno->Start());
868             return false;
869         }
870         seenAnnotations.insert(annoName);
871     }
872     return true;
873 }
874 
CheckAnnotationPropertyType(ir::ClassProperty * property)875 void ETSChecker::CheckAnnotationPropertyType(ir::ClassProperty *property)
876 {
877     // typeAnnotation check
878     if (!ValidateAnnotationPropertyType(property->TsType())) {
879         LogTypeError({"Invalid annotation field type. Only numeric, boolean, string, enum, or "
880                       "arrays of these types are permitted for annotation fields."},
881                      property->Start());
882     }
883 
884     // The type of the Initializer has been check in the parser,
885     // except for the enumeration type, because it is a member expression,
886     // so here is an additional check to the enumeration type.
887     if (property->Value() != nullptr && property->Value()->IsMemberExpression() &&
888         !property->TsType()->IsETSEnumType()) {
889         LogTypeError("Invalid value for annotation field, expected a constant literal.", property->Value()->Start());
890     }
891 }
892 
CheckSinglePropertyAnnotation(ir::AnnotationUsage * st,ir::AnnotationDeclaration * annoDecl)893 void ETSChecker::CheckSinglePropertyAnnotation(ir::AnnotationUsage *st, ir::AnnotationDeclaration *annoDecl)
894 {
895     auto *param = st->Properties().at(0)->AsClassProperty();
896     if (annoDecl->Properties().size() > 1) {
897         LogTypeError({"Annotation '", st->GetBaseName()->Name(), "' requires multiple fields to be specified."},
898                      st->Start());
899     }
900     auto singleField = annoDecl->Properties().at(0)->AsClassProperty();
901     auto ctx = checker::AssignmentContext(Relation(), param->Value(), param->TsType(), singleField->TsType(),
902                                           param->Start(), {}, TypeRelationFlag::NO_THROW);
903     if (!ctx.IsAssignable()) {
904         LogTypeError({"The value provided for annotation '", st->GetBaseName()->Name(), "' field '",
905                       param->Id()->Name(), "' is of type '", param->TsType(), "', but expected type is '",
906                       singleField->TsType(), "'."},
907                      param->Start());
908     }
909 }
910 
ProcessRequiredFields(ArenaUnorderedMap<util::StringView,ir::ClassProperty * > & fieldMap,ir::AnnotationUsage * st,ETSChecker * checker) const911 void ETSChecker::ProcessRequiredFields(ArenaUnorderedMap<util::StringView, ir::ClassProperty *> &fieldMap,
912                                        ir::AnnotationUsage *st, ETSChecker *checker) const
913 {
914     for (const auto &entry : fieldMap) {
915         if (entry.second->Value() == nullptr) {
916             checker->LogTypeError({"The required field '", entry.first,
917                                    "' must be specified. Fields without default values cannot be omitted."},
918                                   st->Start());
919             continue;
920         }
921         auto *clone = entry.second->Clone(checker->Allocator(), st);
922         clone->Check(checker);
923         st->AddProperty(clone);
924     }
925 }
926 
CheckMultiplePropertiesAnnotation(ir::AnnotationUsage * st,ir::AnnotationDeclaration * annoDecl,ArenaUnorderedMap<util::StringView,ir::ClassProperty * > & fieldMap)927 void ETSChecker::CheckMultiplePropertiesAnnotation(ir::AnnotationUsage *st, ir::AnnotationDeclaration *annoDecl,
928                                                    ArenaUnorderedMap<util::StringView, ir::ClassProperty *> &fieldMap)
929 {
930     for (auto *it : st->Properties()) {
931         auto *param = it->AsClassProperty();
932         auto result = fieldMap.find(param->Id()->Name());
933         if (result == fieldMap.end()) {
934             LogTypeError({"The parameter '", param->Id()->Name(),
935                           "' does not match any declared property in the annotation '", annoDecl->GetBaseName()->Name(),
936                           "'."},
937                          param->Start());
938             continue;
939         }
940         auto ctx = checker::AssignmentContext(Relation(), param->Value(), param->TsType(), result->second->TsType(),
941                                               param->Start(), {}, TypeRelationFlag::NO_THROW);
942         if (!ctx.IsAssignable()) {
943             LogTypeError({"The value provided for annotation '", st->GetBaseName()->Name(), "' field '",
944                           param->Id()->Name(), "' is of type '", param->TsType(), "', but expected type is '",
945                           result->second->TsType(), "'."},
946                          param->Start());
947         }
948         fieldMap.erase(result);
949     }
950 }
951 
MaybeUnboxInRelation(Type * type)952 Type *ETSChecker::MaybeUnboxInRelation(Type *type)
953 {
954     if (type == nullptr) {
955         return nullptr;
956     }
957 
958     if (type->IsETSPrimitiveType()) {
959         return type;
960     }
961 
962     if (!type->IsETSUnboxableObject()) {
963         return nullptr;
964     }
965 
966     auto savedResult = Relation()->IsTrue();
967     Relation()->Result(false);
968 
969     UnboxingConverter converter = UnboxingConverter(AsETSChecker(), Relation(), type, type);
970     Relation()->Result(savedResult);
971     return converter.Result();
972 }
973 
MaybeUnboxConditionalInRelation(Type * const objectType)974 Type *ETSChecker::MaybeUnboxConditionalInRelation(Type *const objectType)
975 {
976     if (objectType->IsTypeError()) {
977         return objectType;
978     }
979 
980     if ((objectType == nullptr) || !objectType->IsConditionalExprType()) {
981         return nullptr;
982     }
983 
984     if (auto *unboxed = MaybeUnboxInRelation(objectType); unboxed != nullptr) {
985         return unboxed;
986     }
987 
988     return objectType;
989 }
990 
MaybeBoxInRelation(Type * objectType)991 Type *ETSChecker::MaybeBoxInRelation(Type *objectType)
992 {
993     if (objectType == nullptr) {
994         return nullptr;
995     }
996 
997     if (objectType->IsETSUnboxableObject()) {
998         return objectType;
999     }
1000 
1001     if (!objectType->IsETSPrimitiveType()) {
1002         return nullptr;
1003     }
1004 
1005     auto savedResult = Relation()->IsTrue();
1006     Relation()->Result(false);
1007 
1008     BoxingConverter converter = BoxingConverter(AsETSChecker(), Relation(), objectType,
1009                                                 Checker::GetGlobalTypesHolder()->GlobalIntegerBuiltinType());
1010     Relation()->Result(savedResult);
1011     return converter.Result();
1012 }
1013 
MaybeBoxType(Type * type) const1014 Type *ETSChecker::MaybeBoxType(Type *type) const
1015 {
1016     return type->IsETSPrimitiveType() ? BoxingConverter::Convert(this, type) : type;
1017 }
1018 
MaybeUnboxType(Type * type) const1019 Type *ETSChecker::MaybeUnboxType(Type *type) const
1020 {
1021     return type->IsETSUnboxableObject() ? UnboxingConverter::Convert(this, type->AsETSObjectType()) : type;
1022 }
1023 
MaybeBoxType(Type const * type) const1024 Type const *ETSChecker::MaybeBoxType(Type const *type) const
1025 {
1026     return MaybeBoxType(const_cast<Type *>(type));
1027 }
1028 
MaybeUnboxType(Type const * type) const1029 Type const *ETSChecker::MaybeUnboxType(Type const *type) const
1030 {
1031     return MaybeUnboxType(const_cast<Type *>(type));
1032 }
1033 
GetBoxingFlag(Type * const boxingType)1034 ir::BoxingUnboxingFlags ETSChecker::GetBoxingFlag(Type *const boxingType)
1035 {
1036     auto typeKind = TypeKind(MaybeUnboxInRelation(boxingType));
1037     switch (typeKind) {
1038         case TypeFlag::ETS_BOOLEAN:
1039             return ir::BoxingUnboxingFlags::BOX_TO_BOOLEAN;
1040         case TypeFlag::BYTE:
1041             return ir::BoxingUnboxingFlags::BOX_TO_BYTE;
1042         case TypeFlag::CHAR:
1043             return ir::BoxingUnboxingFlags::BOX_TO_CHAR;
1044         case TypeFlag::SHORT:
1045             return ir::BoxingUnboxingFlags::BOX_TO_SHORT;
1046         case TypeFlag::INT:
1047             return ir::BoxingUnboxingFlags::BOX_TO_INT;
1048         case TypeFlag::LONG:
1049             return ir::BoxingUnboxingFlags::BOX_TO_LONG;
1050         case TypeFlag::FLOAT:
1051             return ir::BoxingUnboxingFlags::BOX_TO_FLOAT;
1052         case TypeFlag::DOUBLE:
1053             return ir::BoxingUnboxingFlags::BOX_TO_DOUBLE;
1054         case TypeFlag::ETS_INT_ENUM:
1055         case TypeFlag::ETS_STRING_ENUM:
1056             return ir::BoxingUnboxingFlags::BOX_TO_ENUM;
1057         default:
1058             UNREACHABLE();
1059     }
1060 }
1061 
GetUnboxingFlag(Type const * const unboxingType) const1062 ir::BoxingUnboxingFlags ETSChecker::GetUnboxingFlag(Type const *const unboxingType) const
1063 {
1064     auto typeKind = TypeKind(unboxingType);
1065     switch (typeKind) {
1066         case TypeFlag::ETS_BOOLEAN:
1067             return ir::BoxingUnboxingFlags::UNBOX_TO_BOOLEAN;
1068         case TypeFlag::BYTE:
1069             return ir::BoxingUnboxingFlags::UNBOX_TO_BYTE;
1070         case TypeFlag::CHAR:
1071             return ir::BoxingUnboxingFlags::UNBOX_TO_CHAR;
1072         case TypeFlag::SHORT:
1073             return ir::BoxingUnboxingFlags::UNBOX_TO_SHORT;
1074         case TypeFlag::INT:
1075             return ir::BoxingUnboxingFlags::UNBOX_TO_INT;
1076         case TypeFlag::LONG:
1077             return ir::BoxingUnboxingFlags::UNBOX_TO_LONG;
1078         case TypeFlag::FLOAT:
1079             return ir::BoxingUnboxingFlags::UNBOX_TO_FLOAT;
1080         case TypeFlag::DOUBLE:
1081             return ir::BoxingUnboxingFlags::UNBOX_TO_DOUBLE;
1082         case TypeFlag::ETS_INT_ENUM:
1083         case TypeFlag::ETS_STRING_ENUM:
1084             return ir::BoxingUnboxingFlags::UNBOX_TO_ENUM;
1085         default:
1086             UNREACHABLE();
1087     }
1088 }
1089 
MaybeAddBoxingFlagInRelation(TypeRelation * relation,Type * target)1090 void ETSChecker::MaybeAddBoxingFlagInRelation(TypeRelation *relation, Type *target)
1091 {
1092     auto boxingResult = MaybeBoxInRelation(target);
1093     if ((boxingResult != nullptr) && !relation->OnlyCheckBoxingUnboxing()) {
1094         relation->GetNode()->AddBoxingUnboxingFlags(GetBoxingFlag(boxingResult));
1095         relation->Result(true);
1096     }
1097 }
1098 
MaybeAddUnboxingFlagInRelation(TypeRelation * relation,Type * source,Type * self)1099 void ETSChecker::MaybeAddUnboxingFlagInRelation(TypeRelation *relation, Type *source, Type *self)
1100 {
1101     auto unboxingResult = UnboxingConverter(this, relation, source, self).Result();
1102     if ((unboxingResult != nullptr) && relation->IsTrue() && !relation->OnlyCheckBoxingUnboxing()) {
1103         relation->GetNode()->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxingResult));
1104     }
1105 }
1106 
CheckUnboxedTypeWidenable(TypeRelation * relation,Type * target,Type * self)1107 void ETSChecker::CheckUnboxedTypeWidenable(TypeRelation *relation, Type *target, Type *self)
1108 {
1109     checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(
1110         relation, TypeRelationFlag::ONLY_CHECK_WIDENING |
1111                       (relation->ApplyNarrowing() ? TypeRelationFlag::NARROWING : TypeRelationFlag::NONE));
1112     // NOTE: vpukhov. handle union type
1113     auto unboxedType = MaybeUnboxInRelation(target);
1114     if (unboxedType == nullptr) {
1115         return;
1116     }
1117     NarrowingWideningConverter(this, relation, unboxedType, self);
1118     if (!relation->IsTrue()) {
1119         relation->Result(relation->IsAssignableTo(self, unboxedType));
1120     }
1121 }
1122 
CheckUnboxedTypesAssignable(TypeRelation * relation,Type * source,Type * target)1123 void ETSChecker::CheckUnboxedTypesAssignable(TypeRelation *relation, Type *source, Type *target)
1124 {
1125     auto *unboxedSourceType = relation->GetChecker()->AsETSChecker()->MaybeUnboxInRelation(source);
1126     auto *unboxedTargetType = relation->GetChecker()->AsETSChecker()->MaybeUnboxInRelation(target);
1127     if (unboxedSourceType == nullptr || unboxedTargetType == nullptr) {
1128         return;
1129     }
1130     relation->IsAssignableTo(unboxedSourceType, unboxedTargetType);
1131     if (relation->IsTrue()) {
1132         relation->GetNode()->AddBoxingUnboxingFlags(
1133             relation->GetChecker()->AsETSChecker()->GetUnboxingFlag(unboxedSourceType));
1134     }
1135 }
1136 
CheckBoxedSourceTypeAssignable(TypeRelation * relation,Type * source,Type * target)1137 void ETSChecker::CheckBoxedSourceTypeAssignable(TypeRelation *relation, Type *source, Type *target)
1138 {
1139     ASSERT(relation != nullptr);
1140     checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(
1141         relation, (relation->ApplyWidening() ? TypeRelationFlag::WIDENING : TypeRelationFlag::NONE) |
1142                       (relation->ApplyNarrowing() ? TypeRelationFlag::NARROWING : TypeRelationFlag::NONE) |
1143                       (relation->OnlyCheckBoxingUnboxing() ? TypeRelationFlag::ONLY_CHECK_BOXING_UNBOXING
1144                                                            : TypeRelationFlag::NONE));
1145 
1146     auto *boxedSourceType = relation->GetChecker()->AsETSChecker()->MaybeBoxInRelation(source);
1147     if (boxedSourceType == nullptr) {
1148         return;
1149     }
1150     ASSERT(target != nullptr);
1151     // Do not box primitive in case of cast to dynamic types
1152     if (target->IsETSDynamicType()) {
1153         return;
1154     }
1155     relation->IsAssignableTo(boxedSourceType, target);
1156     if (relation->IsTrue()) {
1157         MaybeAddBoxingFlagInRelation(relation, boxedSourceType);
1158     } else {
1159         auto unboxedTargetType = MaybeUnboxInRelation(target);
1160         if (unboxedTargetType == nullptr) {
1161             return;
1162         }
1163         NarrowingWideningConverter(this, relation, unboxedTargetType, source);
1164         if (relation->IsTrue()) {
1165             MaybeAddBoxingFlagInRelation(relation, target);
1166         }
1167     }
1168 }
1169 
CheckUnboxedSourceTypeWithWideningAssignable(TypeRelation * relation,Type * source,Type * target)1170 void ETSChecker::CheckUnboxedSourceTypeWithWideningAssignable(TypeRelation *relation, Type *source, Type *target)
1171 {
1172     auto *unboxedSourceType = relation->GetChecker()->AsETSChecker()->MaybeUnboxInRelation(source);
1173     if (unboxedSourceType == nullptr) {
1174         return;
1175     }
1176     relation->IsAssignableTo(unboxedSourceType, target);
1177     if (!relation->IsTrue() && relation->ApplyWidening()) {
1178         relation->GetChecker()->AsETSChecker()->CheckUnboxedTypeWidenable(relation, target, unboxedSourceType);
1179     }
1180     if (!relation->OnlyCheckBoxingUnboxing()) {
1181         relation->GetNode()->AddBoxingUnboxingFlags(
1182             relation->GetChecker()->AsETSChecker()->GetUnboxingFlag(unboxedSourceType));
1183     }
1184 }
1185 
DerefETSTypeReference(ir::AstNode * node)1186 static ir::AstNode *DerefETSTypeReference(ir::AstNode *node)
1187 {
1188     ASSERT(node->IsETSTypeReference());
1189     do {
1190         auto *name = node->AsETSTypeReference()->Part()->Name();
1191         ASSERT(name->IsIdentifier());
1192         auto *var = name->AsIdentifier()->Variable();
1193         ASSERT(var != nullptr);
1194         auto *declNode = var->Declaration()->Node();
1195         if (!declNode->IsTSTypeAliasDeclaration()) {
1196             return declNode;
1197         }
1198         node = declNode->AsTSTypeAliasDeclaration()->TypeAnnotation();
1199     } while (node->IsETSTypeReference());
1200     return node;
1201 }
1202 
CheckLambdaAssignable(ir::Expression * param,ir::ScriptFunction * lambda)1203 bool ETSChecker::CheckLambdaAssignable(ir::Expression *param, ir::ScriptFunction *lambda)
1204 {
1205     ASSERT(param->IsETSParameterExpression());
1206     ir::AstNode *typeAnn = param->AsETSParameterExpression()->Ident()->TypeAnnotation();
1207     if (typeAnn->IsETSTypeReference()) {
1208         typeAnn = DerefETSTypeReference(typeAnn);
1209     }
1210     if (!typeAnn->IsETSFunctionType()) {
1211         if (typeAnn->IsETSUnionType()) {
1212             return CheckLambdaAssignableUnion(typeAnn, lambda);
1213         }
1214 
1215         return false;
1216     }
1217     ir::ETSFunctionType *calleeType = typeAnn->AsETSFunctionType();
1218     return lambda->Params().size() == calleeType->Params().size();
1219 }
1220 
CheckLambdaInfer(ir::AstNode * typeAnnotation,ir::ArrowFunctionExpression * const arrowFuncExpr,Type * const subParameterType)1221 bool ETSChecker::CheckLambdaInfer(ir::AstNode *typeAnnotation, ir::ArrowFunctionExpression *const arrowFuncExpr,
1222                                   Type *const subParameterType)
1223 {
1224     if (typeAnnotation->IsETSTypeReference()) {
1225         typeAnnotation = DerefETSTypeReference(typeAnnotation);
1226     }
1227 
1228     if (!typeAnnotation->IsETSFunctionType()) {
1229         return false;
1230     }
1231 
1232     ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
1233     auto calleeType = typeAnnotation->AsETSFunctionType();
1234     // Lambda function will only have exactly one signature.
1235     auto functionSignature =
1236         TryGettingFunctionTypeFromInvokeFunction(subParameterType)->AsETSFunctionType()->CallSignatures()[0];
1237     InferTypesForLambda(lambda, calleeType, functionSignature);
1238 
1239     return true;
1240 }
1241 
CheckLambdaTypeAnnotation(ir::AstNode * typeAnnotation,ir::ArrowFunctionExpression * const arrowFuncExpr,Type * const parameterType,TypeRelationFlag flags)1242 bool ETSChecker::CheckLambdaTypeAnnotation(ir::AstNode *typeAnnotation,
1243                                            ir::ArrowFunctionExpression *const arrowFuncExpr, Type *const parameterType,
1244                                            TypeRelationFlag flags)
1245 {
1246     auto checkInvocable = [&arrowFuncExpr, &parameterType, this](TypeRelationFlag functionFlags) {
1247         Type *const argumentType = arrowFuncExpr->Check(this);
1248         functionFlags |= TypeRelationFlag::NO_THROW;
1249 
1250         checker::InvocationContext invocationCtx(Relation(), arrowFuncExpr, argumentType, parameterType,
1251                                                  arrowFuncExpr->Start(), {}, functionFlags);
1252         return invocationCtx.IsInvocable();
1253     };
1254 
1255     //  process `single` type as usual.
1256     if (!typeAnnotation->IsETSUnionType()) {
1257         ASSERT(!parameterType->IsETSUnionType());
1258         return CheckLambdaInfer(typeAnnotation, arrowFuncExpr, parameterType) && checkInvocable(flags);
1259     }
1260 
1261     // Preserve actual lambda types
1262     ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
1263     ArenaVector<ir::TypeNode *> lambdaParamTypes {Allocator()->Adapter()};
1264     for (auto *const lambdaParam : lambda->Params()) {
1265         lambdaParamTypes.emplace_back(lambdaParam->AsETSParameterExpression()->Ident()->TypeAnnotation());
1266     }
1267     auto *const lambdaReturnTypeAnnotation = lambda->ReturnTypeAnnotation();
1268 
1269     ASSERT(parameterType->AsETSUnionType()->ConstituentTypes().size() ==
1270            typeAnnotation->AsETSUnionType()->Types().size());
1271     const auto typeAnnsOfUnion = typeAnnotation->AsETSUnionType()->Types();
1272     const auto typeParamOfUnion = parameterType->AsETSUnionType()->ConstituentTypes();
1273     for (size_t ix = 0; ix < typeAnnsOfUnion.size(); ++ix) {
1274         auto *typeNode = typeAnnsOfUnion[ix];
1275         auto *paramNode = typeParamOfUnion[ix];
1276         if (CheckLambdaInfer(typeNode, arrowFuncExpr, paramNode) && checkInvocable(flags)) {
1277             return true;
1278         }
1279 
1280         //  Restore inferring lambda types:
1281         for (std::size_t i = 0U; i < lambda->Params().size(); ++i) {
1282             auto *const lambdaParamTypeAnnotation = lambdaParamTypes[i];
1283             if (lambdaParamTypeAnnotation == nullptr) {
1284                 lambda->Params()[i]->AsETSParameterExpression()->Ident()->SetTsTypeAnnotation(nullptr);
1285             }
1286         }
1287         if (lambdaReturnTypeAnnotation == nullptr) {
1288             lambda->SetReturnTypeAnnotation(nullptr);
1289         }
1290     }
1291 
1292     return false;
1293 }
1294 
TypeInference(Signature * signature,const ArenaVector<ir::Expression * > & arguments,TypeRelationFlag flags)1295 bool ETSChecker::TypeInference(Signature *signature, const ArenaVector<ir::Expression *> &arguments,
1296                                TypeRelationFlag flags)
1297 {
1298     bool invocable = true;
1299     auto const argumentCount = arguments.size();
1300     auto const parameterCount = signature->Params().size();
1301     auto const count = std::min(parameterCount, argumentCount);
1302 
1303     for (size_t index = 0U; index < count; ++index) {
1304         auto const &argument = arguments[index];
1305         if (!argument->IsArrowFunctionExpression()) {
1306             continue;
1307         }
1308 
1309         if (index == arguments.size() - 1 && (flags & TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA) != 0) {
1310             continue;
1311         }
1312 
1313         auto *const arrowFuncExpr = argument->AsArrowFunctionExpression();
1314         ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
1315         if (!NeedTypeInference(lambda)) {
1316             continue;
1317         }
1318 
1319         auto const *const param = signature->Function()->Params()[index]->AsETSParameterExpression()->Ident();
1320         ir::AstNode *typeAnn = param->TypeAnnotation();
1321         Type *const parameterType = signature->Params()[index]->TsType();
1322 
1323         bool const rc = CheckLambdaTypeAnnotation(typeAnn, arrowFuncExpr, parameterType, flags);
1324         if (!rc && (flags & TypeRelationFlag::NO_THROW) == 0) {
1325             Type *const argumentType = arrowFuncExpr->Check(this);
1326             const Type *targetType = TryGettingFunctionTypeFromInvokeFunction(parameterType);
1327             const std::initializer_list<TypeErrorMessageElement> list = {
1328                 "Type '", argumentType, "' is not compatible with type '", targetType, "' at index ", index + 1};
1329             LogTypeError(list, arrowFuncExpr->Start());
1330             return false;
1331         }
1332 
1333         invocable &= rc;
1334     }
1335 
1336     return invocable;
1337 }
1338 
ExtensionETSFunctionType(checker::Type * type)1339 bool ETSChecker::ExtensionETSFunctionType(checker::Type *type)
1340 {
1341     if (!type->IsETSFunctionType()) {
1342         return false;
1343     }
1344 
1345     for (auto *signature : type->AsETSFunctionType()->CallSignatures()) {
1346         if (signature->Function()->IsExtensionMethod()) {
1347             return true;
1348         }
1349     }
1350 
1351     return false;
1352 }
1353 
CheckExceptionClauseType(const std::vector<checker::ETSObjectType * > & exceptions,ir::CatchClause * catchClause,checker::Type * clauseType)1354 void ETSChecker::CheckExceptionClauseType(const std::vector<checker::ETSObjectType *> &exceptions,
1355                                           ir::CatchClause *catchClause, checker::Type *clauseType)
1356 {
1357     for (auto *exception : exceptions) {
1358         this->Relation()->IsIdenticalTo(clauseType, exception);
1359         if (this->Relation()->IsTrue()) {
1360             LogTypeError("Redeclaration of exception type", catchClause->Start());
1361         }
1362     }
1363 }
1364 }  // namespace ark::es2panda::checker
1365