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, ¶meterType, 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