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 "ir/astNode.h"
21 #include "ir/base/catchClause.h"
22 #include "ir/expression.h"
23 #include "ir/typeNode.h"
24 #include "ir/base/scriptFunction.h"
25 #include "ir/base/classProperty.h"
26 #include "ir/base/methodDefinition.h"
27 #include "ir/statements/variableDeclarator.h"
28 #include "ir/statements/switchCaseStatement.h"
29 #include "ir/expressions/identifier.h"
30 #include "ir/expressions/callExpression.h"
31 #include "ir/expressions/memberExpression.h"
32 #include "ir/expressions/arrowFunctionExpression.h"
33 #include "ir/statements/labelledStatement.h"
34 #include "ir/statements/tryStatement.h"
35 #include "ir/ets/etsNewClassInstanceExpression.h"
36 #include "ir/ets/etsParameterExpression.h"
37 #include "ir/ts/tsTypeAliasDeclaration.h"
38 #include "ir/ts/tsEnumMember.h"
39 #include "ir/ts/tsTypeParameter.h"
40 #include "ir/ets/etsUnionType.h"
41 #include "ir/ets/etsTypeReference.h"
42 #include "ir/ets/etsTypeReferencePart.h"
43 #include "varbinder/variable.h"
44 #include "varbinder/scope.h"
45 #include "varbinder/declaration.h"
46 #include "parser/program/program.h"
47 #include "checker/ETSchecker.h"
48 #include "varbinder/ETSBinder.h"
49 #include "checker/ets/typeRelationContext.h"
50 #include "checker/ets/boxingConverter.h"
51 #include "checker/ets/unboxingConverter.h"
52 #include "util/helpers.h"
53
54 namespace ark::es2panda::checker {
CheckTruthinessOfType(ir::Expression * expr)55 void ETSChecker::CheckTruthinessOfType(ir::Expression *expr)
56 {
57 auto *const testType = expr->Check(this);
58 auto *const conditionType = ETSBuiltinTypeAsConditionalType(testType);
59
60 expr->SetTsType(conditionType);
61
62 if (conditionType == nullptr || (!conditionType->IsTypeError() && !conditionType->IsConditionalExprType())) {
63 LogTypeError("Condition must be of possible condition type", expr->Start());
64 return;
65 }
66
67 if (conditionType->IsETSVoidType()) {
68 LogTypeError("An expression of type 'void' cannot be tested for truthiness", expr->Start());
69 return;
70 }
71
72 if (conditionType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
73 FlagExpressionWithUnboxing(testType, conditionType, expr);
74 }
75
76 if (conditionType->IsETSEnumType()) {
77 expr->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
78 }
79 }
80
CheckNonNullish(ir::Expression const * expr)81 void ETSChecker::CheckNonNullish(ir::Expression const *expr)
82 {
83 if (expr->TsTypeOrError()->PossiblyETSNullish()) {
84 ThrowTypeError("Value is possibly nullish.", expr->Start());
85 }
86 }
87
GetNonNullishType(Type * type)88 Type *ETSChecker::GetNonNullishType(Type *type)
89 {
90 if (type->DefinitelyNotETSNullish()) {
91 return type;
92 }
93 if (type->IsETSTypeParameter()) {
94 return Allocator()->New<ETSNonNullishType>(type->AsETSTypeParameter());
95 }
96
97 if (type->IsETSNullType() || type->IsETSUndefinedType()) {
98 return GetGlobalTypesHolder()->GlobalBuiltinNeverType();
99 }
100
101 ArenaVector<Type *> copied(Allocator()->Adapter());
102 for (auto const &t : type->AsETSUnionType()->ConstituentTypes()) {
103 if (t->IsETSNullType() || t->IsETSUndefinedType()) {
104 continue;
105 }
106 copied.push_back(GetNonNullishType(t));
107 }
108 return copied.empty() ? GetGlobalTypesHolder()->GlobalBuiltinNeverType() : CreateETSUnionType(std::move(copied));
109 }
110
RemoveNullType(Type * const type)111 Type *ETSChecker::RemoveNullType(Type *const type)
112 {
113 if (type->DefinitelyNotETSNullish() || type->IsETSUndefinedType()) {
114 return type;
115 }
116
117 if (type->IsETSTypeParameter()) {
118 return Allocator()->New<ETSNonNullishType>(type->AsETSTypeParameter());
119 }
120
121 if (type->IsETSNullType()) {
122 return GetGlobalTypesHolder()->GlobalBuiltinNeverType();
123 }
124
125 ASSERT(type->IsETSUnionType());
126 ArenaVector<Type *> copiedTypes(Allocator()->Adapter());
127
128 for (auto *constituentType : type->AsETSUnionType()->ConstituentTypes()) {
129 if (!constituentType->IsETSNullType()) {
130 copiedTypes.push_back(RemoveNullType(constituentType));
131 }
132 }
133
134 return copiedTypes.empty() ? GetGlobalTypesHolder()->GlobalBuiltinNeverType()
135 : CreateETSUnionType(std::move(copiedTypes));
136 }
137
RemoveUndefinedType(Type * const type)138 Type *ETSChecker::RemoveUndefinedType(Type *const type)
139 {
140 if (type->DefinitelyNotETSNullish() || type->IsETSNullType()) {
141 return type;
142 }
143
144 if (type->IsETSTypeParameter()) {
145 return Allocator()->New<ETSNonNullishType>(type->AsETSTypeParameter());
146 }
147
148 if (type->IsETSUndefinedType()) {
149 return GetGlobalTypesHolder()->GlobalBuiltinNeverType();
150 }
151
152 ASSERT(type->IsETSUnionType());
153 ArenaVector<Type *> copiedTypes(Allocator()->Adapter());
154
155 for (auto *constituentType : type->AsETSUnionType()->ConstituentTypes()) {
156 if (!constituentType->IsETSUndefinedType()) {
157 copiedTypes.push_back(RemoveUndefinedType(constituentType));
158 }
159 }
160
161 return copiedTypes.empty() ? GetGlobalTypesHolder()->GlobalBuiltinNeverType()
162 : CreateETSUnionType(std::move(copiedTypes));
163 }
164
RemoveNullishTypes(Type * type)165 std::pair<Type *, Type *> ETSChecker::RemoveNullishTypes(Type *type)
166 {
167 if (type->DefinitelyNotETSNullish()) {
168 return {GetGlobalTypesHolder()->GlobalBuiltinNeverType(), type};
169 }
170
171 if (type->IsETSTypeParameter()) {
172 return {GetGlobalTypesHolder()->GlobalETSNullishType(),
173 Allocator()->New<ETSNonNullishType>(type->AsETSTypeParameter())};
174 }
175
176 if (type->IsETSUndefinedType() || type->IsETSNullType()) {
177 return {type, GetGlobalTypesHolder()->GlobalBuiltinNeverType()};
178 }
179
180 ASSERT(type->IsETSUnionType());
181 ArenaVector<Type *> nullishTypes(Allocator()->Adapter());
182 ArenaVector<Type *> notNullishTypes(Allocator()->Adapter());
183
184 for (auto *constituentType : type->AsETSUnionType()->ConstituentTypes()) {
185 if (constituentType->IsETSUndefinedType() || constituentType->IsETSNullType()) {
186 nullishTypes.push_back(constituentType);
187 } else {
188 notNullishTypes.push_back(!constituentType->IsETSTypeParameter()
189 ? constituentType
190 : Allocator()->New<ETSNonNullishType>(constituentType->AsETSTypeParameter()));
191 }
192 }
193
194 Type *nullishType = nullishTypes.empty() ? GetGlobalTypesHolder()->GlobalBuiltinNeverType()
195 : CreateETSUnionType(std::move(nullishTypes));
196 Type *notNullishType = notNullishTypes.empty() ? GetGlobalTypesHolder()->GlobalBuiltinNeverType()
197 : CreateETSUnionType(std::move(notNullishTypes));
198 return {nullishType, notNullishType};
199 }
200
201 // NOTE(vpukhov): can be implemented with relation if etscompiler will support it
202 template <typename Pred, typename Trv>
MatchConstituentOrConstraint(const Type * type,Pred const & pred,Trv const & trv)203 static bool MatchConstituentOrConstraint(const Type *type, Pred const &pred, Trv const &trv)
204 {
205 auto const traverse = [&pred, &trv](const Type *ttype) {
206 return MatchConstituentOrConstraint<Pred, Trv>(ttype, pred, trv);
207 };
208 if (pred(type)) {
209 return true;
210 }
211 if (!trv(type)) {
212 return false;
213 }
214 if (type->IsETSUnionType()) {
215 for (auto const &ctype : type->AsETSUnionType()->ConstituentTypes()) {
216 if (traverse(ctype)) {
217 return true;
218 }
219 }
220 return false;
221 }
222 if (type->IsETSTypeParameter()) {
223 return traverse(type->AsETSTypeParameter()->GetConstraintType());
224 }
225 if (type->IsETSNonNullishType()) {
226 auto tparam = type->AsETSNonNullishType()->GetUnderlying();
227 return traverse(tparam->GetConstraintType());
228 }
229 return false;
230 }
231
232 template <typename Pred>
MatchConstituentOrConstraint(const Type * type,Pred const & pred)233 static bool MatchConstituentOrConstraint(const Type *type, Pred const &pred)
234 {
235 return MatchConstituentOrConstraint(type, pred, []([[maybe_unused]] const Type *t) { return true; });
236 }
237
PossiblyETSNull() const238 bool Type::PossiblyETSNull() const
239 {
240 return MatchConstituentOrConstraint(
241 this, [](const Type *t) { return t->IsETSNullType(); },
242 [](const Type *t) { return !t->IsETSNonNullishType(); });
243 }
244
PossiblyETSUndefined() const245 bool Type::PossiblyETSUndefined() const
246 {
247 return MatchConstituentOrConstraint(
248 this, [](const Type *t) { return t->IsETSUndefinedType(); },
249 [](const Type *t) { return !t->IsETSNonNullishType(); });
250 }
251
PossiblyETSNullish() const252 bool Type::PossiblyETSNullish() const
253 {
254 return MatchConstituentOrConstraint(
255 this, [](const Type *t) { return t->IsETSNullType() || t->IsETSUndefinedType(); },
256 [](const Type *t) { return !t->IsETSNonNullishType(); });
257 }
258
DefinitelyETSNullish() const259 bool Type::DefinitelyETSNullish() const
260 {
261 return !MatchConstituentOrConstraint(
262 this,
263 [](const Type *t) {
264 return !(t->IsTypeParameter() || t->IsETSUnionType() || t->IsETSNullType() || t->IsETSUndefinedType());
265 },
266 [](const Type *t) { return !t->IsETSNonNullishType(); });
267 }
268
DefinitelyNotETSNullish() const269 bool Type::DefinitelyNotETSNullish() const
270 {
271 return !PossiblyETSNullish();
272 }
273
PossiblyETSString() const274 bool Type::PossiblyETSString() const
275 {
276 return MatchConstituentOrConstraint(this, [](const Type *t) {
277 return t->IsETSStringType() || (t->IsETSObjectType() && t->AsETSObjectType()->IsGlobalETSObjectType());
278 });
279 }
280
IsValueTypedObjectType(ETSObjectType const * t)281 static bool IsValueTypedObjectType(ETSObjectType const *t)
282 {
283 return t->IsGlobalETSObjectType() || t->HasObjectFlag(ETSObjectFlags::VALUE_TYPED);
284 }
285
PossiblyETSValueTyped() const286 bool Type::PossiblyETSValueTyped() const
287 {
288 return MatchConstituentOrConstraint(this, [](const Type *t) {
289 return t->IsNullType() || t->IsUndefinedType() ||
290 (t->IsETSObjectType() && IsValueTypedObjectType(t->AsETSObjectType()));
291 });
292 }
293
PossiblyETSValueTypedExceptNullish() const294 bool Type::PossiblyETSValueTypedExceptNullish() const
295 {
296 return MatchConstituentOrConstraint(
297 this, [](const Type *t) { return t->IsETSObjectType() && IsValueTypedObjectType(t->AsETSObjectType()); });
298 }
299
IsETSReferenceType() const300 bool Type::IsETSReferenceType() const
301 {
302 return IsETSObjectType() || IsETSArrayType() || IsETSNullType() || IsETSUndefinedType() || IsETSStringType() ||
303 IsETSTypeParameter() || IsETSUnionType() || IsETSNonNullishType() || IsETSBigIntType() ||
304 IsETSFunctionType();
305 }
306
IsETSUnboxableObject() const307 bool Type::IsETSUnboxableObject() const
308 {
309 return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE);
310 }
311
IsConstantExpression(ir::Expression * expr,Type * type)312 bool ETSChecker::IsConstantExpression(ir::Expression *expr, Type *type)
313 {
314 return (type->HasTypeFlag(TypeFlag::CONSTANT) && (expr->IsIdentifier() || expr->IsMemberExpression()));
315 }
316
GetNonConstantTypeFromPrimitiveType(Type * type) const317 Type *ETSChecker::GetNonConstantTypeFromPrimitiveType(Type *type) const
318 {
319 if (type->IsETSStringType()) {
320 return GlobalBuiltinETSStringType();
321 }
322
323 if (!type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
324 return type;
325 }
326
327 if (type->HasTypeFlag(TypeFlag::LONG)) {
328 return GlobalLongType();
329 }
330
331 if (type->HasTypeFlag(TypeFlag::BYTE)) {
332 return GlobalByteType();
333 }
334
335 if (type->HasTypeFlag(TypeFlag::SHORT)) {
336 return GlobalShortType();
337 }
338
339 if (type->HasTypeFlag(TypeFlag::CHAR)) {
340 return GlobalCharType();
341 }
342
343 if (type->HasTypeFlag(TypeFlag::INT)) {
344 return GlobalIntType();
345 }
346
347 if (type->HasTypeFlag(TypeFlag::FLOAT)) {
348 return GlobalFloatType();
349 }
350
351 if (type->HasTypeFlag(TypeFlag::DOUBLE)) {
352 return GlobalDoubleType();
353 }
354
355 if (type->IsETSBooleanType()) {
356 return GlobalETSBooleanType();
357 }
358 return type;
359 }
360
GetTypeOfSetterGetter(varbinder::Variable * const var)361 Type *ETSChecker::GetTypeOfSetterGetter(varbinder::Variable *const var)
362 {
363 auto *propType = var->TsType()->AsETSFunctionType();
364 if (propType->HasTypeFlag(checker::TypeFlag::GETTER)) {
365 return propType->FindGetter()->ReturnType();
366 }
367 return propType->FindSetter()->Params()[0]->TsType();
368 }
369
IterateInVariableContext(varbinder::Variable * const var)370 void ETSChecker::IterateInVariableContext(varbinder::Variable *const var)
371 {
372 // Before computing the given variables type, we have to make a new checker context frame so that the checking is
373 // done in the proper context, and have to enter the scope where the given variable is declared, so reference
374 // resolution works properly
375 auto *iter = var->Declaration()->Node()->Parent();
376 while (iter != nullptr) {
377 if (iter->IsMethodDefinition()) {
378 auto *methodDef = iter->AsMethodDefinition();
379 ASSERT(methodDef->TsType());
380 Context().SetContainingSignature(methodDef->Function()->Signature());
381 }
382
383 if (iter->IsClassDefinition()) {
384 auto *classDef = iter->AsClassDefinition();
385 ETSObjectType *containingClass {};
386
387 if (classDef->TsType() == nullptr) {
388 containingClass = BuildBasicClassProperties(classDef);
389 ResolveDeclaredMembersOfObject(containingClass);
390 } else {
391 containingClass = classDef->TsType()->AsETSObjectType();
392 }
393
394 ASSERT(classDef->TsType());
395 Context().SetContainingClass(containingClass);
396 }
397
398 iter = iter->Parent();
399 }
400 }
401
GetTypeOfVariable(varbinder::Variable * const var)402 Type *ETSChecker::GetTypeOfVariable(varbinder::Variable *const var)
403 {
404 if (IsVariableGetterSetter(var)) {
405 return GetTypeOfSetterGetter(var);
406 }
407
408 if (var->TsTypeOrError() != nullptr) {
409 return var->TsTypeOrError();
410 }
411
412 // NOTE: kbaladurin. forbid usage of imported entities as types without declarations
413 if (VarBinder()->AsETSBinder()->IsDynamicModuleVariable(var)) {
414 auto *importData = VarBinder()->AsETSBinder()->DynamicImportDataForVar(var);
415 if (importData->import->IsPureDynamic()) {
416 return GlobalBuiltinDynamicType(importData->import->Language());
417 }
418 }
419
420 checker::SavedCheckerContext savedContext(this, CheckerStatus::NO_OPTS);
421 checker::ScopeContext scopeCtx(this, var->GetScope());
422 IterateInVariableContext(var);
423
424 switch (var->Declaration()->Type()) {
425 case varbinder::DeclType::CLASS: {
426 auto *classDef = var->Declaration()->Node()->AsClassDefinition();
427 BuildBasicClassProperties(classDef);
428 return classDef->TsType();
429 }
430 case varbinder::DeclType::ENUM_LITERAL:
431 case varbinder::DeclType::CONST:
432 case varbinder::DeclType::READONLY:
433 case varbinder::DeclType::LET:
434 case varbinder::DeclType::VAR: {
435 auto *declNode = var->Declaration()->Node();
436
437 if (var->Declaration()->Node()->IsIdentifier()) {
438 declNode = declNode->Parent();
439 }
440
441 return declNode->Check(this);
442 }
443 case varbinder::DeclType::FUNC:
444 case varbinder::DeclType::IMPORT: {
445 return var->Declaration()->Node()->Check(this);
446 }
447 case varbinder::DeclType::TYPE_ALIAS: {
448 return GetTypeFromTypeAliasReference(var);
449 }
450 case varbinder::DeclType::INTERFACE: {
451 return BuildBasicInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration());
452 }
453 default: {
454 UNREACHABLE();
455 }
456 }
457
458 return var->TsType();
459 }
460
461 // Determine if unchecked cast is needed and yield guaranteed source type
GuaranteedTypeForUncheckedCast(Type * base,Type * substituted)462 Type *ETSChecker::GuaranteedTypeForUncheckedCast(Type *base, Type *substituted)
463 {
464 // Apparent type acts as effective representation for type.
465 // For T extends SomeClass|undefined
466 // Apparent(Int|T|null) is Int|SomeClass|undefined|null
467 auto *appBase = GetApparentType(base);
468 auto *appSubst = GetApparentType(substituted);
469 // Base is supertype of Substituted AND Substituted is supertype of Base
470 return Relation()->IsIdenticalTo(appSubst, appBase) ? nullptr : appBase;
471 }
472
473 // Determine if substituted property access requires cast from erased type
GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable * const prop)474 Type *ETSChecker::GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable *const prop)
475 {
476 if (IsVariableStatic(prop)) {
477 return nullptr;
478 }
479 if (IsVariableGetterSetter(prop)) {
480 auto *method = prop->TsType()->AsETSFunctionType();
481 if (!method->HasTypeFlag(checker::TypeFlag::GETTER)) {
482 return nullptr;
483 }
484 return GuaranteedTypeForUncheckedCallReturn(method->FindGetter());
485 }
486 // NOTE(vpukhov): mark ETSDynamicType properties
487 if (prop->Declaration() == nullptr || prop->Declaration()->Node() == nullptr) {
488 return nullptr;
489 }
490
491 varbinder::Variable *baseProp = nullptr;
492 switch (auto node = prop->Declaration()->Node(); node->Type()) {
493 case ir::AstNodeType::CLASS_PROPERTY:
494 baseProp = node->AsClassProperty()->Id()->Variable();
495 break;
496 case ir::AstNodeType::METHOD_DEFINITION:
497 baseProp = node->AsMethodDefinition()->Variable();
498 break;
499 case ir::AstNodeType::CLASS_DEFINITION:
500 baseProp = node->AsClassDefinition()->Ident()->Variable();
501 break;
502 default:
503 UNREACHABLE();
504 }
505
506 if (baseProp == prop) {
507 return nullptr;
508 }
509 return GuaranteedTypeForUncheckedCast(GetTypeOfVariable(baseProp), GetTypeOfVariable(prop));
510 }
511
512 // Determine if substituted method cast requires cast from erased type
GuaranteedTypeForUncheckedCallReturn(Signature * sig)513 Type *ETSChecker::GuaranteedTypeForUncheckedCallReturn(Signature *sig)
514 {
515 if (sig->HasSignatureFlag(checker::SignatureFlags::THIS_RETURN_TYPE)) {
516 return sig->ReturnType();
517 }
518 auto *baseSig = sig->Function()->Signature();
519 if (baseSig == sig) {
520 return nullptr;
521 }
522 return GuaranteedTypeForUncheckedCast(baseSig->ReturnType(), sig->ReturnType());
523 }
524
CheckEtsFunctionType(ir::Identifier * const ident,ir::Identifier const * const id,ir::TypeNode const * const annotation)525 void ETSChecker::CheckEtsFunctionType(ir::Identifier *const ident, ir::Identifier const *const id,
526 ir::TypeNode const *const annotation)
527 {
528 if (annotation == nullptr) {
529 ThrowTypeError(
530 {"Cannot infer type for ", id->Name(), " because method reference needs an explicit target type"},
531 id->Start());
532 }
533
534 const auto *const targetType = GetTypeOfVariable(id->Variable());
535 ASSERT(targetType != nullptr);
536
537 if (!targetType->IsETSObjectType()) {
538 ThrowTypeError("Initializers type is not assignable to the target type", ident->Start());
539 }
540 }
541
GetTypeFromTypeAliasReference(varbinder::Variable * var)542 Type *ETSChecker::GetTypeFromTypeAliasReference(varbinder::Variable *var)
543 {
544 if (var->TsType() != nullptr) {
545 return var->TsType();
546 }
547
548 auto *const aliasTypeNode = var->Declaration()->Node()->AsTSTypeAliasDeclaration();
549 TypeStackElement tse(this, aliasTypeNode, "Circular type alias reference", aliasTypeNode->Start());
550 aliasTypeNode->Check(this);
551 auto *const aliasedType = aliasTypeNode->TypeAnnotation()->GetType(this);
552
553 var->SetTsType(aliasedType);
554 return aliasedType;
555 }
556
GetTypeFromInterfaceReference(varbinder::Variable * var)557 Type *ETSChecker::GetTypeFromInterfaceReference(varbinder::Variable *var)
558 {
559 if (var->TsType() != nullptr) {
560 return var->TsType();
561 }
562
563 auto *interfaceType = BuildBasicInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration());
564 var->SetTsType(interfaceType);
565 return interfaceType;
566 }
567
GetTypeFromClassReference(varbinder::Variable * var)568 Type *ETSChecker::GetTypeFromClassReference(varbinder::Variable *var)
569 {
570 if (var->TsType() != nullptr) {
571 return var->TsType();
572 }
573
574 auto *classType = BuildBasicClassProperties(var->Declaration()->Node()->AsClassDefinition());
575 var->SetTsType(classType);
576 return classType;
577 }
578
GetTypeFromEnumReference(varbinder::Variable * var)579 Type *ETSChecker::GetTypeFromEnumReference([[maybe_unused]] varbinder::Variable *var)
580 {
581 if (var->TsType() != nullptr) {
582 return var->TsType();
583 }
584
585 auto *const enumDecl = var->Declaration()->Node()->AsTSEnumDeclaration();
586 if (auto *const itemInit = enumDecl->Members().front()->AsTSEnumMember()->Init(); itemInit->IsNumberLiteral()) {
587 return CreateEnumIntTypeFromEnumDeclaration(enumDecl);
588 } else if (itemInit->IsStringLiteral()) { // NOLINT(readability-else-after-return)
589 return CreateEnumStringTypeFromEnumDeclaration(enumDecl);
590 } else { // NOLINT(readability-else-after-return)
591 ThrowTypeError("Invalid enumeration value type.", enumDecl->Start());
592 }
593 }
594
GetTypeFromTypeParameterReference(varbinder::LocalVariable * var,const lexer::SourcePosition & pos)595 Type *ETSChecker::GetTypeFromTypeParameterReference(varbinder::LocalVariable *var, const lexer::SourcePosition &pos)
596 {
597 ASSERT(var->Declaration()->Node()->IsTSTypeParameter());
598 if ((var->Declaration()->Node()->AsTSTypeParameter()->Parent()->Parent()->IsClassDefinition() ||
599 var->Declaration()->Node()->AsTSTypeParameter()->Parent()->Parent()->IsTSInterfaceDeclaration()) &&
600 HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) {
601 ThrowTypeError({"Cannot make a static reference to the non-static type ", var->Name()}, pos);
602 }
603
604 return var->TsType();
605 }
606
IsTypeBuiltinType(const Type * type) const607 bool ETSChecker::IsTypeBuiltinType(const Type *type) const
608 {
609 if (!type->IsETSObjectType()) {
610 return false;
611 }
612
613 switch (type->AsETSObjectType()->BuiltInKind()) {
614 case ETSObjectFlags::BUILTIN_BOOLEAN:
615 case ETSObjectFlags::BUILTIN_BYTE:
616 case ETSObjectFlags::BUILTIN_SHORT:
617 case ETSObjectFlags::BUILTIN_CHAR:
618 case ETSObjectFlags::BUILTIN_INT:
619 case ETSObjectFlags::BUILTIN_LONG:
620 case ETSObjectFlags::BUILTIN_FLOAT:
621 case ETSObjectFlags::BUILTIN_DOUBLE: {
622 return true;
623 }
624 default:
625 return false;
626 }
627 }
628
ETSBuiltinTypeAsPrimitiveType(Type * objectType)629 Type *ETSChecker::ETSBuiltinTypeAsPrimitiveType(Type *objectType)
630 {
631 if (objectType == nullptr) {
632 return nullptr;
633 }
634
635 if (objectType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) || objectType->IsETSEnumType()) {
636 return objectType;
637 }
638
639 if (!objectType->IsETSObjectType() ||
640 !objectType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) {
641 return nullptr;
642 }
643
644 auto savedResult = Relation()->IsTrue();
645 Relation()->Result(false);
646
647 UnboxingConverter converter = UnboxingConverter(AsETSChecker(), Relation(), objectType, objectType);
648 Relation()->Result(savedResult);
649 return converter.Result();
650 }
651
ETSBuiltinTypeAsConditionalType(Type * const objectType)652 Type *ETSChecker::ETSBuiltinTypeAsConditionalType(Type *const objectType)
653 {
654 if (objectType->IsTypeError()) {
655 return objectType;
656 }
657
658 if ((objectType == nullptr) || !objectType->IsConditionalExprType()) {
659 return nullptr;
660 }
661
662 if (auto *unboxed = ETSBuiltinTypeAsPrimitiveType(objectType); unboxed != nullptr) {
663 return unboxed;
664 }
665
666 return objectType;
667 }
668
PrimitiveTypeAsETSBuiltinType(Type * objectType)669 Type *ETSChecker::PrimitiveTypeAsETSBuiltinType(Type *objectType)
670 {
671 if (objectType == nullptr) {
672 return nullptr;
673 }
674
675 if (objectType->IsETSObjectType() && objectType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) {
676 return objectType;
677 }
678
679 if (!objectType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
680 return nullptr;
681 }
682
683 auto savedResult = Relation()->IsTrue();
684 Relation()->Result(false);
685
686 BoxingConverter converter = BoxingConverter(AsETSChecker(), Relation(), objectType,
687 Checker::GetGlobalTypesHolder()->GlobalIntegerBuiltinType());
688 Relation()->Result(savedResult);
689 return converter.Result();
690 }
691
MaybePromotedBuiltinType(Type * type) const692 Type *ETSChecker::MaybePromotedBuiltinType(Type *type) const
693 {
694 return type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) && !type->IsETSVoidType()
695 ? checker::BoxingConverter::ETSTypeFromSource(this, type)
696 : type;
697 }
698
MaybePromotedBuiltinType(Type const * type) const699 Type const *ETSChecker::MaybePromotedBuiltinType(Type const *type) const
700 {
701 return type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) ? checker::BoxingConverter::ETSTypeFromSource(this, type) : type;
702 }
703
MaybePrimitiveBuiltinType(Type * type) const704 Type *ETSChecker::MaybePrimitiveBuiltinType(Type *type) const
705 {
706 return type->IsETSObjectType() ? UnboxingConverter::GlobalTypeFromSource(this, type->AsETSObjectType()) : type;
707 }
708
GetBoxingFlag(Type * const boxingType)709 ir::BoxingUnboxingFlags ETSChecker::GetBoxingFlag(Type *const boxingType)
710 {
711 auto typeKind = TypeKind(ETSBuiltinTypeAsPrimitiveType(boxingType));
712 switch (typeKind) {
713 case TypeFlag::ETS_BOOLEAN: {
714 return ir::BoxingUnboxingFlags::BOX_TO_BOOLEAN;
715 }
716 case TypeFlag::BYTE: {
717 return ir::BoxingUnboxingFlags::BOX_TO_BYTE;
718 }
719 case TypeFlag::CHAR: {
720 return ir::BoxingUnboxingFlags::BOX_TO_CHAR;
721 }
722 case TypeFlag::SHORT: {
723 return ir::BoxingUnboxingFlags::BOX_TO_SHORT;
724 }
725 case TypeFlag::INT: {
726 return ir::BoxingUnboxingFlags::BOX_TO_INT;
727 }
728 case TypeFlag::LONG: {
729 return ir::BoxingUnboxingFlags::BOX_TO_LONG;
730 }
731 case TypeFlag::FLOAT: {
732 return ir::BoxingUnboxingFlags::BOX_TO_FLOAT;
733 }
734 case TypeFlag::DOUBLE: {
735 return ir::BoxingUnboxingFlags::BOX_TO_DOUBLE;
736 }
737 default:
738 UNREACHABLE();
739 }
740 }
741
GetUnboxingFlag(Type const * const unboxingType) const742 ir::BoxingUnboxingFlags ETSChecker::GetUnboxingFlag(Type const *const unboxingType) const
743 {
744 auto typeKind = TypeKind(unboxingType);
745 switch (typeKind) {
746 case TypeFlag::ETS_BOOLEAN: {
747 return ir::BoxingUnboxingFlags::UNBOX_TO_BOOLEAN;
748 }
749 case TypeFlag::BYTE: {
750 return ir::BoxingUnboxingFlags::UNBOX_TO_BYTE;
751 }
752 case TypeFlag::CHAR: {
753 return ir::BoxingUnboxingFlags::UNBOX_TO_CHAR;
754 }
755 case TypeFlag::SHORT: {
756 return ir::BoxingUnboxingFlags::UNBOX_TO_SHORT;
757 }
758 case TypeFlag::INT: {
759 return ir::BoxingUnboxingFlags::UNBOX_TO_INT;
760 }
761 case TypeFlag::LONG: {
762 return ir::BoxingUnboxingFlags::UNBOX_TO_LONG;
763 }
764 case TypeFlag::FLOAT: {
765 return ir::BoxingUnboxingFlags::UNBOX_TO_FLOAT;
766 }
767 case TypeFlag::DOUBLE: {
768 return ir::BoxingUnboxingFlags::UNBOX_TO_DOUBLE;
769 }
770 default:
771 UNREACHABLE();
772 }
773 }
774
AddBoxingFlagToPrimitiveType(TypeRelation * relation,Type * target)775 void ETSChecker::AddBoxingFlagToPrimitiveType(TypeRelation *relation, Type *target)
776 {
777 auto boxingResult = PrimitiveTypeAsETSBuiltinType(target);
778 if ((boxingResult != nullptr) && !relation->OnlyCheckBoxingUnboxing()) {
779 relation->GetNode()->AddBoxingUnboxingFlags(GetBoxingFlag(boxingResult));
780 relation->Result(true);
781 }
782 }
783
AddUnboxingFlagToPrimitiveType(TypeRelation * relation,Type * source,Type * self)784 void ETSChecker::AddUnboxingFlagToPrimitiveType(TypeRelation *relation, Type *source, Type *self)
785 {
786 auto unboxingResult = UnboxingConverter(this, relation, source, self).Result();
787 if ((unboxingResult != nullptr) && relation->IsTrue() && !relation->OnlyCheckBoxingUnboxing()) {
788 relation->GetNode()->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxingResult));
789 }
790 }
791
CheckUnboxedTypeWidenable(TypeRelation * relation,Type * target,Type * self)792 void ETSChecker::CheckUnboxedTypeWidenable(TypeRelation *relation, Type *target, Type *self)
793 {
794 checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(
795 relation, TypeRelationFlag::ONLY_CHECK_WIDENING |
796 (relation->ApplyNarrowing() ? TypeRelationFlag::NARROWING : TypeRelationFlag::NONE));
797 // NOTE: vpukhov. handle union type
798 auto unboxedType = ETSBuiltinTypeAsPrimitiveType(target);
799 if (unboxedType == nullptr) {
800 return;
801 }
802 NarrowingWideningConverter(this, relation, unboxedType, self);
803 if (!relation->IsTrue()) {
804 relation->Result(relation->IsAssignableTo(self, unboxedType));
805 }
806 }
807
CheckUnboxedTypesAssignable(TypeRelation * relation,Type * source,Type * target)808 void ETSChecker::CheckUnboxedTypesAssignable(TypeRelation *relation, Type *source, Type *target)
809 {
810 auto *unboxedSourceType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(source);
811 auto *unboxedTargetType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(target);
812 if (unboxedSourceType == nullptr || unboxedTargetType == nullptr) {
813 return;
814 }
815 relation->IsAssignableTo(unboxedSourceType, unboxedTargetType);
816 if (relation->IsTrue()) {
817 relation->GetNode()->AddBoxingUnboxingFlags(
818 relation->GetChecker()->AsETSChecker()->GetUnboxingFlag(unboxedSourceType));
819 }
820 }
821
CheckBoxedSourceTypeAssignable(TypeRelation * relation,Type * source,Type * target)822 void ETSChecker::CheckBoxedSourceTypeAssignable(TypeRelation *relation, Type *source, Type *target)
823 {
824 ASSERT(relation != nullptr);
825 checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(
826 relation, (relation->ApplyWidening() ? TypeRelationFlag::WIDENING : TypeRelationFlag::NONE) |
827 (relation->ApplyNarrowing() ? TypeRelationFlag::NARROWING : TypeRelationFlag::NONE) |
828 (relation->OnlyCheckBoxingUnboxing() ? TypeRelationFlag::ONLY_CHECK_BOXING_UNBOXING
829 : TypeRelationFlag::NONE));
830
831 if (source->IsETSEnumType()) {
832 if (target->IsETSObjectType() && target->AsETSObjectType()->IsGlobalETSObjectType()) {
833 relation->Result(true);
834 return;
835 }
836 }
837
838 auto *boxedSourceType = relation->GetChecker()->AsETSChecker()->PrimitiveTypeAsETSBuiltinType(source);
839 if (boxedSourceType == nullptr) {
840 return;
841 }
842 ASSERT(target != nullptr);
843 // Do not box primitive in case of cast to dynamic types
844 if (target->IsETSDynamicType()) {
845 return;
846 }
847 relation->IsAssignableTo(boxedSourceType, target);
848 if (relation->IsTrue()) {
849 AddBoxingFlagToPrimitiveType(relation, boxedSourceType);
850 } else {
851 auto unboxedTargetType = ETSBuiltinTypeAsPrimitiveType(target);
852 if (unboxedTargetType == nullptr) {
853 return;
854 }
855 NarrowingWideningConverter(this, relation, unboxedTargetType, source);
856 if (relation->IsTrue()) {
857 AddBoxingFlagToPrimitiveType(relation, target);
858 }
859 }
860 }
861
CheckUnboxedSourceTypeWithWideningAssignable(TypeRelation * relation,Type * source,Type * target)862 void ETSChecker::CheckUnboxedSourceTypeWithWideningAssignable(TypeRelation *relation, Type *source, Type *target)
863 {
864 auto *unboxedSourceType = relation->GetChecker()->AsETSChecker()->ETSBuiltinTypeAsPrimitiveType(source);
865 if (unboxedSourceType == nullptr) {
866 return;
867 }
868 relation->IsAssignableTo(unboxedSourceType, target);
869 if (!relation->IsTrue() && relation->ApplyWidening()) {
870 relation->GetChecker()->AsETSChecker()->CheckUnboxedTypeWidenable(relation, target, unboxedSourceType);
871 }
872 if (!relation->OnlyCheckBoxingUnboxing()) {
873 relation->GetNode()->AddBoxingUnboxingFlags(
874 relation->GetChecker()->AsETSChecker()->GetUnboxingFlag(unboxedSourceType));
875 }
876 }
877
DerefETSTypeReference(ir::AstNode * node)878 static ir::AstNode *DerefETSTypeReference(ir::AstNode *node)
879 {
880 ASSERT(node->IsETSTypeReference());
881 do {
882 auto *name = node->AsETSTypeReference()->Part()->Name();
883 ASSERT(name->IsIdentifier());
884 auto *var = name->AsIdentifier()->Variable();
885 ASSERT(var != nullptr);
886 auto *declNode = var->Declaration()->Node();
887 if (!declNode->IsTSTypeAliasDeclaration()) {
888 return declNode;
889 }
890 node = declNode->AsTSTypeAliasDeclaration()->TypeAnnotation();
891 } while (node->IsETSTypeReference());
892 return node;
893 }
894
CheckLambdaAssignable(ir::Expression * param,ir::ScriptFunction * lambda)895 bool ETSChecker::CheckLambdaAssignable(ir::Expression *param, ir::ScriptFunction *lambda)
896 {
897 ASSERT(param->IsETSParameterExpression());
898 ir::AstNode *typeAnn = param->AsETSParameterExpression()->Ident()->TypeAnnotation();
899 if (typeAnn->IsETSTypeReference()) {
900 typeAnn = DerefETSTypeReference(typeAnn);
901 }
902 if (!typeAnn->IsETSFunctionType()) {
903 if (typeAnn->IsETSUnionType()) {
904 return CheckLambdaAssignableUnion(typeAnn, lambda);
905 }
906
907 return false;
908 }
909 ir::ETSFunctionType *calleeType = typeAnn->AsETSFunctionType();
910 return lambda->Params().size() == calleeType->Params().size();
911 }
912
CheckLambdaInvocable(ir::AstNode * typeAnnotation,ir::ArrowFunctionExpression * const arrowFuncExpr,Type * const parameterType,TypeRelationFlag flags)913 bool ETSChecker::CheckLambdaInvocable(ir::AstNode *typeAnnotation, ir::ArrowFunctionExpression *const arrowFuncExpr,
914 Type *const parameterType, TypeRelationFlag flags)
915 {
916 if (typeAnnotation->IsETSTypeReference()) {
917 typeAnnotation = DerefETSTypeReference(typeAnnotation);
918 }
919
920 if (!typeAnnotation->IsETSFunctionType()) {
921 return false;
922 }
923
924 flags |= TypeRelationFlag::NO_THROW;
925 ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
926
927 InferTypesForLambda(lambda, typeAnnotation->AsETSFunctionType());
928 Type *const argumentType = arrowFuncExpr->Check(this);
929
930 checker::InvocationContext invocationCtx(Relation(), arrowFuncExpr, argumentType, parameterType,
931 arrowFuncExpr->Start(), {}, flags);
932 return invocationCtx.IsInvocable();
933 }
934
CheckLambdaTypeAnnotation(ir::AstNode * typeAnnotation,ir::ArrowFunctionExpression * const arrowFuncExpr,Type * const parameterType,TypeRelationFlag flags)935 bool ETSChecker::CheckLambdaTypeAnnotation(ir::AstNode *typeAnnotation,
936 ir::ArrowFunctionExpression *const arrowFuncExpr, Type *const parameterType,
937 TypeRelationFlag flags)
938 {
939 // process `single` type as usual.
940 if (!typeAnnotation->IsETSUnionType()) {
941 return CheckLambdaInvocable(typeAnnotation, arrowFuncExpr, parameterType, flags);
942 }
943
944 // Preserve actual lambda types
945 ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
946 ArenaVector<ir::TypeNode *> lambdaParamTypes {Allocator()->Adapter()};
947 for (auto *const lambdaParam : lambda->Params()) {
948 lambdaParamTypes.emplace_back(lambdaParam->AsETSParameterExpression()->Ident()->TypeAnnotation());
949 }
950 auto *const lambdaReturnTypeAnnotation = lambda->ReturnTypeAnnotation();
951
952 for (ir::AstNode *typeNode : typeAnnotation->AsETSUnionType()->Types()) {
953 if (CheckLambdaInvocable(typeNode, arrowFuncExpr, parameterType, flags)) {
954 return true;
955 }
956
957 // Restore inferring lambda types:
958 for (std::size_t i = 0U; i < lambda->Params().size(); ++i) {
959 auto *const lambdaParamTypeAnnotation = lambdaParamTypes[i];
960 if (lambdaParamTypeAnnotation == nullptr) {
961 lambda->Params()[i]->AsETSParameterExpression()->Ident()->SetTsTypeAnnotation(nullptr);
962 }
963 }
964 if (lambdaReturnTypeAnnotation == nullptr) {
965 lambda->SetReturnTypeAnnotation(nullptr);
966 }
967 }
968
969 return false;
970 }
971
TypeInference(Signature * signature,const ArenaVector<ir::Expression * > & arguments,TypeRelationFlag flags)972 bool ETSChecker::TypeInference(Signature *signature, const ArenaVector<ir::Expression *> &arguments,
973 TypeRelationFlag flags)
974 {
975 bool invocable = true;
976 auto const argumentCount = arguments.size();
977 auto const parameterCount = signature->Params().size();
978 auto const count = std::min(parameterCount, argumentCount);
979
980 for (size_t index = 0U; index < count; ++index) {
981 auto const &argument = arguments[index];
982 if (!argument->IsArrowFunctionExpression()) {
983 continue;
984 }
985
986 if (index == arguments.size() - 1 && (flags & TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA) != 0) {
987 continue;
988 }
989
990 auto *const arrowFuncExpr = argument->AsArrowFunctionExpression();
991 ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
992 if (!NeedTypeInference(lambda)) {
993 continue;
994 }
995
996 auto const *const param = signature->Function()->Params()[index]->AsETSParameterExpression()->Ident();
997 ir::AstNode *typeAnn = param->TypeAnnotation();
998 Type *const parameterType = signature->Params()[index]->TsType();
999
1000 bool const rc = CheckLambdaTypeAnnotation(typeAnn, arrowFuncExpr, parameterType, flags);
1001 if (!rc && (flags & TypeRelationFlag::NO_THROW) == 0) {
1002 Type *const argumentType = arrowFuncExpr->Check(this);
1003 const Type *targetType = TryGettingFunctionTypeFromInvokeFunction(parameterType);
1004 const std::initializer_list<TypeErrorMessageElement> list = {
1005 "Type '", argumentType, "' is not compatible with type '", targetType, "' at index ", index + 1};
1006 ThrowTypeError(list, arrowFuncExpr->Start());
1007 }
1008
1009 invocable &= rc;
1010 }
1011
1012 return invocable;
1013 }
1014
ExtensionETSFunctionType(checker::Type * type)1015 bool ETSChecker::ExtensionETSFunctionType(checker::Type *type)
1016 {
1017 if (!type->IsETSFunctionType()) {
1018 return false;
1019 }
1020
1021 for (auto *signature : type->AsETSFunctionType()->CallSignatures()) {
1022 if (signature->Function()->IsExtensionMethod()) {
1023 return true;
1024 }
1025 }
1026
1027 return false;
1028 }
1029
CheckExceptionClauseType(const std::vector<checker::ETSObjectType * > & exceptions,ir::CatchClause * catchClause,checker::Type * clauseType)1030 void ETSChecker::CheckExceptionClauseType(const std::vector<checker::ETSObjectType *> &exceptions,
1031 ir::CatchClause *catchClause, checker::Type *clauseType)
1032 {
1033 for (auto *exception : exceptions) {
1034 this->Relation()->IsIdenticalTo(clauseType, exception);
1035 if (this->Relation()->IsTrue()) {
1036 this->ThrowTypeError("Redeclaration of exception type", catchClause->Start());
1037 }
1038 }
1039 }
1040 } // namespace ark::es2panda::checker
1041