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