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 "ETSAnalyzer.h"
17
18 #include "varbinder/ETSBinder.h"
19 #include "checker/ETSchecker.h"
20 #include "checker/ets/castingContext.h"
21 #include "checker/ets/typeRelationContext.h"
22 #include "util/helpers.h"
23
24 #include <memory>
25
26 namespace panda::es2panda::checker {
27
GetETSChecker() const28 ETSChecker *ETSAnalyzer::GetETSChecker() const
29 {
30 return static_cast<ETSChecker *>(GetChecker());
31 }
32
33 // from as folder
Check(ir::NamedType * node) const34 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::NamedType *node) const
35 {
36 UNREACHABLE();
37 }
38
Check(ir::PrefixAssertionExpression * expr) const39 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::PrefixAssertionExpression *expr) const
40 {
41 UNREACHABLE();
42 }
43 // from base folder
Check(ir::CatchClause * st) const44 checker::Type *ETSAnalyzer::Check(ir::CatchClause *st) const
45 {
46 ETSChecker *checker = GetETSChecker();
47 checker::ETSObjectType *exceptionType = checker->GlobalETSObjectType();
48
49 ir::Identifier *paramIdent = st->Param()->AsIdentifier();
50
51 if (paramIdent->TypeAnnotation() != nullptr) {
52 checker::Type *catchParamAnnotationType = paramIdent->TypeAnnotation()->GetType(checker);
53
54 exceptionType = checker->CheckExceptionOrErrorType(catchParamAnnotationType, st->Param()->Start());
55 }
56
57 paramIdent->Variable()->SetTsType(exceptionType);
58
59 st->Body()->Check(checker);
60
61 st->SetTsType(exceptionType);
62 return exceptionType;
63 }
64
Check(ir::ClassDefinition * node) const65 checker::Type *ETSAnalyzer::Check(ir::ClassDefinition *node) const
66 {
67 ETSChecker *checker = GetETSChecker();
68 if (node->TsType() == nullptr) {
69 checker->BuildClassProperties(node);
70 }
71
72 checker->CheckClassDefinition(node);
73 return nullptr;
74 }
75
Check(ir::ClassProperty * st) const76 checker::Type *ETSAnalyzer::Check(ir::ClassProperty *st) const
77 {
78 ASSERT(st->Id() != nullptr);
79 ETSChecker *checker = GetETSChecker();
80
81 if (st->TsType() != nullptr) {
82 return st->TsType();
83 }
84
85 checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
86 checker->Context().ContainingClass(),
87 checker->Context().ContainingSignature());
88
89 if (st->IsStatic()) {
90 checker->AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT);
91 }
92
93 st->SetTsType(checker->CheckVariableDeclaration(st->Id(), st->TypeAnnotation(), st->Value(), st->Modifiers()));
94
95 return st->TsType();
96 }
97
Check(ir::ClassStaticBlock * st) const98 checker::Type *ETSAnalyzer::Check(ir::ClassStaticBlock *st) const
99 {
100 ETSChecker *checker = GetETSChecker();
101
102 if (checker->HasStatus(checker::CheckerStatus::INNER_CLASS)) {
103 checker->ThrowTypeError("Static initializer is not allowed in inner class.", st->Start());
104 }
105
106 auto *func = st->Function();
107 st->SetTsType(checker->BuildFunctionSignature(func));
108 checker::ScopeContext scopeCtx(checker, func->Scope());
109 checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
110 checker->Context().ContainingClass());
111 checker->AddStatus(checker::CheckerStatus::IN_STATIC_BLOCK | checker::CheckerStatus::IN_STATIC_CONTEXT);
112 func->Body()->Check(checker);
113 return st->TsType();
114 }
115
Check(ir::Decorator * st) const116 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Decorator *st) const
117 {
118 UNREACHABLE();
119 }
120
Check(ir::MetaProperty * expr) const121 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::MetaProperty *expr) const
122 {
123 UNREACHABLE();
124 }
125
CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecker * checker,checker::ETSObjectType * objType,ir::ScriptFunction * extensionFunc,checker::Signature * signature)126 static void CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecker *checker,
127 checker::ETSObjectType *objType,
128 ir::ScriptFunction *extensionFunc,
129 checker::Signature *signature)
130 {
131 const auto methodName = extensionFunc->Id()->Name();
132 // Only check if there are class and interfaces' instance methods which would shadow instance extension method
133 auto *const variable = objType->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(methodName);
134 if (variable == nullptr) {
135 return;
136 }
137
138 const auto *const funcType = variable->TsType()->AsETSFunctionType();
139 for (auto *funcSignature : funcType->CallSignatures()) {
140 signature->SetReturnType(funcSignature->ReturnType());
141 if (!checker->Relation()->IsIdenticalTo(signature, funcSignature)) {
142 continue;
143 }
144
145 checker->ReportWarning({"extension is shadowed by a instance member function '", funcType->Name(),
146 funcSignature, "' in class ", objType->Name()},
147 extensionFunc->Body()->Start());
148 return;
149 }
150 }
151
CheckExtensionIsShadowedByMethod(checker::ETSChecker * checker,checker::ETSObjectType * objType,ir::ScriptFunction * extensionFunc,checker::Signature * signature)152 static void CheckExtensionIsShadowedByMethod(checker::ETSChecker *checker, checker::ETSObjectType *objType,
153 ir::ScriptFunction *extensionFunc, checker::Signature *signature)
154 {
155 if (objType == nullptr) {
156 return;
157 }
158
159 CheckExtensionIsShadowedInCurrentClassOrInterface(checker, objType, extensionFunc, signature);
160
161 for (auto *interface : objType->Interfaces()) {
162 CheckExtensionIsShadowedByMethod(checker, interface, extensionFunc, signature);
163 }
164
165 CheckExtensionIsShadowedByMethod(checker, objType->SuperType(), extensionFunc, signature);
166 }
167
CheckExtensionMethod(checker::ETSChecker * checker,ir::ScriptFunction * extensionFunc,ir::MethodDefinition * node)168 static void CheckExtensionMethod(checker::ETSChecker *checker, ir::ScriptFunction *extensionFunc,
169 ir::MethodDefinition *node)
170 {
171 auto *const classType = ETSChecker::GetApparentType(extensionFunc->Signature()->Params()[0]->TsType());
172 if (!classType->IsETSObjectType() ||
173 (!classType->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::CLASS) &&
174 !classType->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::INTERFACE))) {
175 checker->ThrowTypeError("Extension function can only defined for class and interface type.", node->Start());
176 }
177
178 checker->AddStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD);
179
180 checker::SignatureInfo *originalExtensionSigInfo = checker->Allocator()->New<checker::SignatureInfo>(
181 extensionFunc->Signature()->GetSignatureInfo(), checker->Allocator());
182 originalExtensionSigInfo->minArgCount -= 1;
183 originalExtensionSigInfo->params.erase(originalExtensionSigInfo->params.begin());
184 checker::Signature *originalExtensionSigature =
185 checker->CreateSignature(originalExtensionSigInfo, extensionFunc->Signature()->ReturnType(), extensionFunc);
186
187 CheckExtensionIsShadowedByMethod(checker, classType->AsETSObjectType(), extensionFunc, originalExtensionSigature);
188 }
189
DoBodyTypeChecking(ETSChecker * checker,ir::MethodDefinition * node,ir::ScriptFunction * scriptFunc)190 void DoBodyTypeChecking(ETSChecker *checker, ir::MethodDefinition *node, ir::ScriptFunction *scriptFunc)
191 {
192 if (scriptFunc->HasBody() && (node->IsNative() || node->IsAbstract() || node->IsDeclare())) {
193 checker->ThrowTypeError("Native, Abstract and Declare methods cannot have body.", scriptFunc->Body()->Start());
194 }
195
196 if (scriptFunc->IsAsyncFunc()) {
197 auto *retType = static_cast<checker::ETSObjectType *>(scriptFunc->Signature()->ReturnType());
198 if (retType->AssemblerName() != checker->GlobalBuiltinPromiseType()->AssemblerName()) {
199 checker->ThrowTypeError("Return type of async function must be 'Promise'.", scriptFunc->Start());
200 }
201 } else if (scriptFunc->HasBody() && !scriptFunc->IsExternal()) {
202 checker::ScopeContext scopeCtx(checker, scriptFunc->Scope());
203 checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
204 checker->Context().ContainingClass());
205 checker->Context().SetContainingSignature(checker->GetSignatureFromMethodDefinition(node));
206
207 if (node->IsStatic() && !node->IsConstructor() &&
208 !checker->Context().ContainingClass()->HasObjectFlag(checker::ETSObjectFlags::GLOBAL)) {
209 checker->AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT);
210 }
211
212 if (node->IsConstructor()) {
213 checker->AddStatus(checker::CheckerStatus::IN_CONSTRUCTOR);
214 }
215
216 if (node->IsExtensionMethod()) {
217 CheckExtensionMethod(checker, scriptFunc, node);
218 }
219
220 scriptFunc->Body()->Check(checker);
221
222 // In case of inferred function's return type set it forcedly to all return statements;
223 if (scriptFunc->Signature()->HasSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE) &&
224 scriptFunc->ReturnTypeAnnotation() == nullptr && scriptFunc->Body() != nullptr &&
225 scriptFunc->Body()->IsStatement()) {
226 scriptFunc->Body()->AsStatement()->SetReturnType(checker, scriptFunc->Signature()->ReturnType());
227 }
228
229 checker->Context().SetContainingSignature(nullptr);
230 }
231 }
232
CheckGetterSetterTypeConstrains(ETSChecker * checker,ir::ScriptFunction * scriptFunc)233 void CheckGetterSetterTypeConstrains(ETSChecker *checker, ir::ScriptFunction *scriptFunc)
234 {
235 if (scriptFunc->IsSetter() && (scriptFunc->Signature()->ReturnType() != checker->GlobalBuiltinVoidType())) {
236 checker->ThrowTypeError("Setter must have void return type", scriptFunc->Start());
237 }
238
239 if (scriptFunc->IsGetter() && (scriptFunc->Signature()->ReturnType() == checker->GlobalBuiltinVoidType())) {
240 checker->ThrowTypeError("Getter must return a value", scriptFunc->Start());
241 }
242
243 auto const name = scriptFunc->Id()->Name();
244 if (name.Is(compiler::Signatures::GET_INDEX_METHOD)) {
245 if (scriptFunc->Signature()->ReturnType() == checker->GlobalBuiltinVoidType()) {
246 checker->ThrowTypeError(std::string {ir::INDEX_ACCESS_ERROR_1} + std::string {name.Utf8()} +
247 std::string {"' shouldn't have void return type."},
248 scriptFunc->Start());
249 }
250 } else if (name.Is(compiler::Signatures::SET_INDEX_METHOD)) {
251 if (scriptFunc->Signature()->ReturnType() != checker->GlobalBuiltinVoidType()) {
252 checker->ThrowTypeError(std::string {ir::INDEX_ACCESS_ERROR_1} + std::string {name.Utf8()} +
253 std::string {"' should have void return type."},
254 scriptFunc->Start());
255 }
256 }
257 }
258
Check(ir::MethodDefinition * node) const259 checker::Type *ETSAnalyzer::Check(ir::MethodDefinition *node) const
260 {
261 ETSChecker *checker = GetETSChecker();
262 auto *scriptFunc = node->Function();
263 if (scriptFunc->IsProxy()) {
264 return nullptr;
265 }
266
267 // NOTE: aszilagyi. make it correctly check for open function not have body
268 if (!scriptFunc->HasBody() && !(node->IsAbstract() || node->IsNative() || node->IsDeclare() ||
269 checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) {
270 checker->ThrowTypeError("Only abstract or native methods can't have body.", scriptFunc->Start());
271 }
272
273 if (scriptFunc->ReturnTypeAnnotation() == nullptr &&
274 (node->IsNative() || (node->IsDeclare() && !node->IsConstructor()))) {
275 checker->ThrowTypeError("Native and Declare methods should have explicit return type.", scriptFunc->Start());
276 }
277
278 if (node->TsType() == nullptr) {
279 node->SetTsType(checker->BuildMethodSignature(node));
280 }
281
282 this->CheckMethodModifiers(node);
283
284 if (node->IsNative() && scriptFunc->ReturnTypeAnnotation() == nullptr) {
285 checker->ThrowTypeError("'Native' method should have explicit return type", scriptFunc->Start());
286 }
287
288 if (node->IsNative() && (scriptFunc->IsGetter() || scriptFunc->IsSetter())) {
289 checker->ThrowTypeError("'Native' modifier is invalid for Accessors", scriptFunc->Start());
290 }
291
292 DoBodyTypeChecking(checker, node, scriptFunc);
293 CheckGetterSetterTypeConstrains(checker, scriptFunc);
294
295 checker->CheckOverride(node->TsType()->AsETSFunctionType()->FindSignature(node->Function()));
296
297 for (auto *it : node->Overloads()) {
298 it->Check(checker);
299 }
300
301 if (scriptFunc->IsRethrowing()) {
302 checker->CheckRethrowingFunction(scriptFunc);
303 }
304
305 return node->TsType();
306 }
307
CheckMethodModifiers(ir::MethodDefinition * node) const308 void ETSAnalyzer::CheckMethodModifiers(ir::MethodDefinition *node) const
309 {
310 ETSChecker *checker = GetETSChecker();
311 auto const notValidInAbstract = ir::ModifierFlags::NATIVE | ir::ModifierFlags::PRIVATE |
312 ir::ModifierFlags::OVERRIDE | ir::ModifierFlags::FINAL | ir::ModifierFlags::STATIC;
313
314 if (node->IsAbstract() && (node->flags_ & notValidInAbstract) != 0U) {
315 checker->ThrowTypeError(
316 "Invalid method modifier(s): an abstract method can't have private, override, static, final or native "
317 "modifier.",
318 node->Start());
319 }
320
321 if ((node->IsAbstract() || (!node->Function()->HasBody() && !node->IsNative() && !node->IsDeclare())) &&
322 !(checker->HasStatus(checker::CheckerStatus::IN_ABSTRACT) ||
323 checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) {
324 checker->ThrowTypeError("Non abstract class has abstract method.", node->Start());
325 }
326
327 auto const notValidInFinal = ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::STATIC | ir::ModifierFlags::NATIVE;
328
329 if (node->IsFinal() && (node->flags_ & notValidInFinal) != 0U) {
330 checker->ThrowTypeError(
331 "Invalid method modifier(s): a final method can't have abstract, static or native modifier.",
332 node->Start());
333 }
334
335 auto const notValidInStatic = ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::FINAL | ir::ModifierFlags::OVERRIDE;
336
337 if (node->IsStatic() && (node->flags_ & notValidInStatic) != 0U) {
338 checker->ThrowTypeError(
339 "Invalid method modifier(s): a static method can't have abstract, final or override modifier.",
340 node->Start());
341 }
342 }
343
Check(ir::Property * expr) const344 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Property *expr) const
345 {
346 UNREACHABLE();
347 }
348
Check(ir::ScriptFunction * node) const349 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ScriptFunction *node) const
350 {
351 UNREACHABLE();
352 }
353
Check(ir::SpreadElement * expr) const354 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::SpreadElement *expr) const
355 {
356 UNREACHABLE();
357 }
358
Check(ir::TemplateElement * expr) const359 checker::Type *ETSAnalyzer::Check(ir::TemplateElement *expr) const
360 {
361 ETSChecker *checker = GetETSChecker();
362 expr->SetTsType(checker->CreateETSStringLiteralType(expr->Raw()));
363 return expr->TsType();
364 }
365
Check(ir::TSIndexSignature * node) const366 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSIndexSignature *node) const
367 {
368 UNREACHABLE();
369 }
370
Check(ir::TSMethodSignature * node) const371 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSMethodSignature *node) const
372 {
373 UNREACHABLE();
374 }
375
Check(ir::TSPropertySignature * node) const376 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSPropertySignature *node) const
377 {
378 UNREACHABLE();
379 }
380
Check(ir::TSSignatureDeclaration * node) const381 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSSignatureDeclaration *node) const
382 {
383 UNREACHABLE();
384 }
385 // from ets folder
Check(ir::ETSScript * node) const386 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSScript *node) const
387 {
388 UNREACHABLE();
389 }
390
Check(ir::ETSClassLiteral * expr) const391 checker::Type *ETSAnalyzer::Check(ir::ETSClassLiteral *expr) const
392 {
393 ETSChecker *checker = GetETSChecker();
394 checker->ThrowTypeError("Class literal is not yet supported.", expr->expr_->Start());
395
396 expr->expr_->Check(checker);
397 auto *exprType = expr->expr_->GetType(checker);
398
399 if (exprType->IsETSVoidType()) {
400 checker->ThrowTypeError("Invalid .class reference", expr->expr_->Start());
401 }
402
403 ArenaVector<checker::Type *> typeArgTypes(checker->Allocator()->Adapter());
404 typeArgTypes.push_back(exprType); // NOTE: Box it if it's a primitive type
405
406 checker::InstantiationContext ctx(checker, checker->GlobalBuiltinTypeType(), typeArgTypes, expr->range_.start);
407 expr->SetTsType(ctx.Result());
408 return expr->TsType();
409 }
410
Check(ir::ETSFunctionType * node) const411 checker::Type *ETSAnalyzer::Check(ir::ETSFunctionType *node) const
412 {
413 ETSChecker *checker = GetETSChecker();
414 checker->CreateFunctionalInterfaceForFunctionType(node);
415 auto *interfaceType =
416 checker->CreateETSObjectType(node->FunctionalInterface()->Id()->Name(), node->FunctionalInterface(),
417 checker::ETSObjectFlags::FUNCTIONAL_INTERFACE);
418 interfaceType->SetSuperType(checker->GlobalETSObjectType());
419
420 auto *invokeFunc = node->FunctionalInterface()->Body()->Body()[0]->AsMethodDefinition()->Function();
421 auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
422
423 for (auto *it : invokeFunc->Params()) {
424 auto *const param = it->AsETSParameterExpression();
425 if (param->IsRestParameter()) {
426 auto *restIdent = param->Ident();
427
428 ASSERT(restIdent->Variable());
429 signatureInfo->restVar = restIdent->Variable()->AsLocalVariable();
430
431 ASSERT(param->TypeAnnotation());
432 signatureInfo->restVar->SetTsType(checker->GetTypeFromTypeAnnotation(param->TypeAnnotation()));
433
434 auto arrayType = signatureInfo->restVar->TsType()->AsETSArrayType();
435 checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank());
436 } else {
437 auto *paramIdent = param->Ident();
438
439 ASSERT(paramIdent->Variable());
440 varbinder::Variable *paramVar = paramIdent->Variable();
441
442 ASSERT(param->TypeAnnotation());
443 paramVar->SetTsType(checker->GetTypeFromTypeAnnotation(param->TypeAnnotation()));
444 signatureInfo->params.push_back(paramVar->AsLocalVariable());
445 ++signatureInfo->minArgCount;
446 }
447 }
448
449 invokeFunc->ReturnTypeAnnotation()->Check(checker);
450 auto *signature =
451 checker->Allocator()->New<checker::Signature>(signatureInfo, node->ReturnType()->GetType(checker), invokeFunc);
452 signature->SetOwnerVar(invokeFunc->Id()->Variable()->AsLocalVariable());
453 signature->AddSignatureFlag(checker::SignatureFlags::FUNCTIONAL_INTERFACE_SIGNATURE);
454 signature->SetOwner(interfaceType);
455
456 auto *funcType = checker->CreateETSFunctionType(signature);
457 invokeFunc->SetSignature(signature);
458 invokeFunc->Id()->Variable()->SetTsType(funcType);
459 interfaceType->AddProperty<checker::PropertyType::INSTANCE_METHOD>(invokeFunc->Id()->Variable()->AsLocalVariable());
460 node->FunctionalInterface()->SetTsType(interfaceType);
461
462 auto *thisVar = invokeFunc->Scope()->ParamScope()->Params().front();
463 thisVar->SetTsType(interfaceType);
464 checker->BuildFunctionalInterfaceName(node);
465
466 node->SetTsType(interfaceType);
467 return interfaceType;
468 }
469
Check(ir::ETSImportDeclaration * node) const470 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSImportDeclaration *node) const
471 {
472 UNREACHABLE();
473 }
474
Check(ir::ETSLaunchExpression * expr) const475 checker::Type *ETSAnalyzer::Check(ir::ETSLaunchExpression *expr) const
476 {
477 ETSChecker *checker = GetETSChecker();
478 expr->expr_->Check(checker);
479 auto *const launchPromiseType =
480 checker->GlobalBuiltinPromiseType()
481 ->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder())
482 ->AsETSObjectType();
483 launchPromiseType->AddTypeFlag(checker::TypeFlag::GENERIC);
484
485 // Launch expression returns a Promise<T> type, so we need to insert the expression's type
486 // as type parameter for the Promise class.
487
488 auto *exprType =
489 expr->expr_->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) && !expr->expr_->TsType()->IsETSVoidType()
490 ? checker->PrimitiveTypeAsETSBuiltinType(expr->expr_->TsType())
491 : expr->expr_->TsType();
492 checker::Substitution *substitution = checker->NewSubstitution();
493 ASSERT(launchPromiseType->TypeArguments().size() == 1);
494 checker::ETSChecker::EmplaceSubstituted(
495 substitution, launchPromiseType->TypeArguments()[0]->AsETSTypeParameter()->GetOriginal(), exprType);
496
497 expr->SetTsType(launchPromiseType->Substitute(checker->Relation(), substitution));
498 return expr->TsType();
499 }
500
Check(ir::ETSNewArrayInstanceExpression * expr) const501 checker::Type *ETSAnalyzer::Check(ir::ETSNewArrayInstanceExpression *expr) const
502 {
503 ETSChecker *checker = GetETSChecker();
504
505 auto *elementType = expr->typeReference_->GetType(checker);
506 checker->ValidateArrayIndex(expr->dimension_, true);
507
508 if (!elementType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) && !elementType->IsNullish() &&
509 !elementType->HasTypeFlag(TypeFlag::GENERIC) && !elementType->HasTypeFlag(TypeFlag::ETS_ARRAY) &&
510 elementType->ToAssemblerName().str() != "Ball") {
511 // Check only valid for ETS_PRIMITIVE and IsNullish, GENERIC and ETS_ARRAY are workaround checks for stdlib
512 // Ball is workaround for koala ui lib
513 if (elementType->IsETSObjectType()) {
514 auto *calleeObj = elementType->AsETSObjectType();
515 if (!calleeObj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT)) {
516 // A workaround check for new Interface[...] in test cases
517 expr->defaultConstructorSignature_ =
518 checker->CollectParameterlessConstructor(calleeObj->ConstructSignatures(), expr->Start());
519 checker->ValidateSignatureAccessibility(calleeObj, nullptr, expr->defaultConstructorSignature_,
520 expr->Start());
521 }
522 }
523 }
524 expr->SetTsType(checker->CreateETSArrayType(elementType));
525 checker->CreateBuiltinArraySignature(expr->TsType()->AsETSArrayType(), 1);
526 return expr->TsType();
527 }
528
Check(ir::ETSNewClassInstanceExpression * expr) const529 checker::Type *ETSAnalyzer::Check(ir::ETSNewClassInstanceExpression *expr) const
530 {
531 ETSChecker *checker = GetETSChecker();
532 checker::Type *calleeType = expr->GetTypeRef()->Check(checker);
533
534 if (!calleeType->IsETSObjectType()) {
535 checker->ThrowTypeError("This expression is not constructible.", expr->Start());
536 }
537
538 auto *calleeObj = calleeType->AsETSObjectType();
539 expr->SetTsType(calleeObj);
540
541 if (expr->ClassDefinition() != nullptr) {
542 if (!calleeObj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT) && calleeObj->GetDeclNode()->IsFinal()) {
543 checker->ThrowTypeError({"Class ", calleeObj->Name(), " cannot be both 'abstract' and 'final'."},
544 calleeObj->GetDeclNode()->Start());
545 }
546
547 bool fromInterface = calleeObj->HasObjectFlag(checker::ETSObjectFlags::INTERFACE);
548 auto *classType = checker->BuildAnonymousClassProperties(
549 expr->ClassDefinition(), fromInterface ? checker->GlobalETSObjectType() : calleeObj);
550 if (fromInterface) {
551 classType->AddInterface(calleeObj);
552 calleeObj = checker->GlobalETSObjectType();
553 }
554 expr->ClassDefinition()->SetTsType(classType);
555 checker->CheckClassDefinition(expr->ClassDefinition());
556 checker->CheckInnerClassMembers(classType);
557 expr->SetTsType(classType);
558 } else if (calleeObj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT)) {
559 checker->ThrowTypeError({calleeObj->Name(), " is abstract therefore cannot be instantiated."}, expr->Start());
560 }
561
562 if (calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl()) {
563 auto lang = calleeType->AsETSDynamicType()->Language();
564 expr->SetSignature(checker->ResolveDynamicCallExpression(expr->GetTypeRef(), expr->GetArguments(), lang, true));
565 } else {
566 auto *signature = checker->ResolveConstructExpression(calleeObj, expr->GetArguments(), expr->Start());
567
568 checker->CheckObjectLiteralArguments(signature, expr->GetArguments());
569 checker->AddUndefinedParamsForDefaultParams(signature, expr->arguments_, checker);
570
571 checker->ValidateSignatureAccessibility(calleeObj, nullptr, signature, expr->Start());
572
573 ASSERT(signature->Function() != nullptr);
574
575 if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) {
576 checker->CheckThrowingStatements(expr);
577 }
578
579 if (calleeType->IsETSDynamicType()) {
580 ASSERT(signature->Function()->IsDynamic());
581 auto lang = calleeType->AsETSDynamicType()->Language();
582 expr->SetSignature(
583 checker->ResolveDynamicCallExpression(expr->GetTypeRef(), signature->Params(), lang, true));
584 } else {
585 ASSERT(!signature->Function()->IsDynamic());
586 expr->SetSignature(signature);
587 }
588 }
589
590 return expr->TsType();
591 }
592
Check(ir::ETSNewMultiDimArrayInstanceExpression * expr) const593 checker::Type *ETSAnalyzer::Check(ir::ETSNewMultiDimArrayInstanceExpression *expr) const
594 {
595 ETSChecker *checker = GetETSChecker();
596 auto *elementType = expr->typeReference_->GetType(checker);
597
598 for (auto *dim : expr->dimensions_) {
599 checker->ValidateArrayIndex(dim);
600 elementType = checker->CreateETSArrayType(elementType);
601 }
602
603 expr->SetTsType(elementType);
604 expr->signature_ = checker->CreateBuiltinArraySignature(elementType->AsETSArrayType(), expr->dimensions_.size());
605 return expr->TsType();
606 }
607
Check(ir::ETSPackageDeclaration * st) const608 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPackageDeclaration *st) const
609 {
610 return nullptr;
611 }
612
Check(ir::ETSParameterExpression * expr) const613 checker::Type *ETSAnalyzer::Check(ir::ETSParameterExpression *expr) const
614 {
615 ETSChecker *checker = GetETSChecker();
616 if (expr->TsType() == nullptr) {
617 checker::Type *paramType;
618
619 if (expr->Ident()->TsType() != nullptr) {
620 paramType = expr->Ident()->TsType();
621 } else {
622 paramType = !expr->IsRestParameter() ? expr->Ident()->Check(checker) : expr->spread_->Check(checker);
623 if (expr->IsDefault()) {
624 [[maybe_unused]] auto *const initType = expr->Initializer()->Check(checker);
625 }
626 }
627
628 expr->SetTsType(paramType);
629 }
630
631 return expr->TsType();
632 }
633
Check(ir::ETSPrimitiveType * node) const634 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPrimitiveType *node) const
635 {
636 return nullptr;
637 }
638
Check(ir::ETSStructDeclaration * node) const639 checker::Type *ETSAnalyzer::Check(ir::ETSStructDeclaration *node) const
640 {
641 ETSChecker *checker = GetETSChecker();
642 node->Definition()->Check(checker);
643 return nullptr;
644 }
645
Check(ir::ETSTuple * node) const646 checker::Type *ETSAnalyzer::Check(ir::ETSTuple *node) const
647 {
648 (void)node;
649 UNREACHABLE();
650 }
651
Check(ir::ETSTypeReference * node) const652 checker::Type *ETSAnalyzer::Check(ir::ETSTypeReference *node) const
653 {
654 ETSChecker *checker = GetETSChecker();
655 return node->GetType(checker);
656 }
657
Check(ir::ETSTypeReferencePart * node) const658 checker::Type *ETSAnalyzer::Check(ir::ETSTypeReferencePart *node) const
659 {
660 ETSChecker *checker = GetETSChecker();
661 return node->GetType(checker);
662 }
663
Check(ir::ETSUnionType * node) const664 checker::Type *ETSAnalyzer::Check(ir::ETSUnionType *node) const
665 {
666 (void)node;
667 UNREACHABLE();
668 }
669
Check(ir::ETSWildcardType * node) const670 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSWildcardType *node) const
671 {
672 UNREACHABLE();
673 }
674
675 // compile methods for EXPRESSIONS in alphabetical order
676
GetPreferredType(ir::ArrayExpression * expr) const677 checker::Type *ETSAnalyzer::GetPreferredType(ir::ArrayExpression *expr) const
678 {
679 return expr->preferredType_;
680 }
681
Check(ir::ArrayExpression * expr) const682 checker::Type *ETSAnalyzer::Check(ir::ArrayExpression *expr) const
683 {
684 ETSChecker *checker = GetETSChecker();
685 if (expr->TsType() != nullptr) {
686 return expr->TsType();
687 }
688
689 const bool isArray = (expr->preferredType_ != nullptr) && expr->preferredType_->IsETSArrayType() &&
690 !expr->preferredType_->IsETSTupleType();
691 if (isArray) {
692 expr->preferredType_ = expr->preferredType_->AsETSArrayType()->ElementType();
693 }
694
695 if (!expr->Elements().empty()) {
696 if (expr->preferredType_ == nullptr) {
697 expr->preferredType_ = expr->Elements()[0]->Check(checker);
698 }
699
700 const bool isPreferredTuple = expr->preferredType_->IsETSTupleType();
701 auto *const targetElementType =
702 isPreferredTuple && !isArray ? expr->preferredType_->AsETSTupleType()->ElementType() : expr->preferredType_;
703
704 for (std::size_t idx = 0; idx < expr->elements_.size(); ++idx) {
705 auto *const currentElement = expr->elements_[idx];
706
707 if (currentElement->IsArrayExpression()) {
708 expr->HandleNestedArrayExpression(checker, currentElement->AsArrayExpression(), isArray,
709 isPreferredTuple, idx);
710 }
711
712 if (currentElement->IsObjectExpression()) {
713 currentElement->AsObjectExpression()->SetPreferredType(expr->preferredType_);
714 }
715
716 checker::Type *elementType = currentElement->Check(checker);
717
718 if (!elementType->IsETSArrayType() && isPreferredTuple) {
719 auto *const compareType = expr->preferredType_->AsETSTupleType()->GetTypeAtIndex(idx);
720
721 if (compareType == nullptr) {
722 checker->ThrowTypeError(
723 {"Too many elements in array initializer for tuple with size of ",
724 static_cast<uint32_t>(expr->preferredType_->AsETSTupleType()->GetTupleSize())},
725 currentElement->Start());
726 }
727
728 const checker::CastingContext cast(
729 checker->Relation(), currentElement, elementType, compareType, currentElement->Start(),
730 {"Array initializer's type is not assignable to tuple type at index: ", idx});
731
732 elementType = compareType;
733 }
734
735 checker::AssignmentContext(checker->Relation(), currentElement, elementType, targetElementType,
736 currentElement->Start(),
737 {"Array element type '", elementType, "' is not assignable to explicit type '",
738 expr->GetPreferredType(), "'"});
739 }
740
741 expr->SetPreferredType(targetElementType);
742 }
743
744 if (expr->preferredType_ == nullptr) {
745 checker->ThrowTypeError("Can't resolve array type", expr->Start());
746 }
747
748 expr->SetTsType(checker->CreateETSArrayType(expr->preferredType_));
749 auto *const arrayType = expr->TsType()->AsETSArrayType();
750 checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank());
751 return expr->TsType();
752 }
753
Check(ir::ArrowFunctionExpression * expr) const754 checker::Type *ETSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const
755 {
756 ETSChecker *checker = GetETSChecker();
757 if (expr->TsType() != nullptr) {
758 return expr->TsType();
759 }
760
761 auto *funcType = checker->BuildFunctionSignature(expr->Function(), false);
762
763 if (expr->Function()->IsAsyncFunc()) {
764 auto *retType = static_cast<checker::ETSObjectType *>(expr->Function()->Signature()->ReturnType());
765 if (retType->AssemblerName() != checker->GlobalBuiltinPromiseType()->AssemblerName()) {
766 checker->ThrowTypeError("Return type of async lambda must be 'Promise'", expr->Function()->Start());
767 }
768 }
769
770 checker::ScopeContext scopeCtx(checker, expr->Function()->Scope());
771
772 if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) {
773 /*
774 example code:
775 ```
776 class A {
777 prop:number
778 }
779 function A.method() {
780 let a = () => {
781 console.println(this.prop)
782 }
783 }
784 ```
785 here the enclosing class of arrow function should be Class A
786 */
787 checker->Context().SetContainingClass(
788 checker->Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS).variable->TsType()->AsETSObjectType());
789 }
790
791 checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
792 checker->Context().ContainingClass());
793 checker->AddStatus(checker::CheckerStatus::IN_LAMBDA);
794 checker->Context().SetContainingSignature(funcType->CallSignatures()[0]);
795
796 expr->Function()->Body()->Check(checker);
797
798 checker->Context().SetContainingSignature(nullptr);
799 checker->CheckCapturedVariables();
800
801 for (auto [var, _] : checker->Context().CapturedVars()) {
802 (void)_;
803 expr->CapturedVars().push_back(var);
804 }
805
806 expr->SetTsType(funcType);
807 return expr->TsType();
808 }
809
Check(ir::AssignmentExpression * expr) const810 checker::Type *ETSAnalyzer::Check(ir::AssignmentExpression *expr) const
811 {
812 ETSChecker *checker = GetETSChecker();
813
814 if (expr->TsType() != nullptr) {
815 return expr->TsType();
816 }
817
818 auto *leftType = expr->Left()->Check(checker);
819 if (expr->Left()->IsMemberExpression() &&
820 expr->Left()->AsMemberExpression()->Object()->TsType()->IsETSArrayType() &&
821 expr->Left()->AsMemberExpression()->Property()->IsIdentifier() &&
822 expr->Left()->AsMemberExpression()->Property()->AsIdentifier()->Name().Is("length")) {
823 checker->ThrowTypeError("Setting the length of an array is not permitted", expr->Left()->Start());
824 }
825
826 if (expr->Left()->IsIdentifier()) {
827 expr->target_ = expr->Left()->AsIdentifier()->Variable();
828 } else {
829 expr->target_ = expr->Left()->AsMemberExpression()->PropVar();
830 }
831
832 if (expr->target_ != nullptr) {
833 checker->ValidateUnaryOperatorOperand(expr->target_);
834 }
835
836 checker::Type *sourceType {};
837 ir::Expression *relationNode = expr->Right();
838 switch (expr->OperatorType()) {
839 case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
840 case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
841 case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
842 case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
843 case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
844 case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
845 case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
846 case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
847 case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
848 case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
849 case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL:
850 case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
851 std::tie(std::ignore, expr->operationType_) = checker->CheckBinaryOperator(
852 expr->Left(), expr->Right(), expr, expr->OperatorType(), expr->Start(), true);
853
854 auto unboxedLeft = checker->ETSBuiltinTypeAsPrimitiveType(leftType);
855 sourceType = unboxedLeft == nullptr ? leftType : unboxedLeft;
856
857 relationNode = expr;
858 break;
859 }
860 case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
861 if (leftType->IsETSArrayType() && expr->Right()->IsArrayExpression()) {
862 checker->ModifyPreferredType(expr->Right()->AsArrayExpression(), leftType);
863 }
864
865 if (expr->Right()->IsObjectExpression()) {
866 expr->Right()->AsObjectExpression()->SetPreferredType(leftType);
867 }
868
869 sourceType = expr->Right()->Check(checker);
870 break;
871 }
872 default: {
873 UNREACHABLE();
874 break;
875 }
876 }
877
878 checker::AssignmentContext(checker->Relation(), relationNode, sourceType, leftType, expr->Right()->Start(),
879 {"Initializers type is not assignable to the target type"});
880
881 expr->SetTsType(expr->Left()->TsType());
882 return expr->TsType();
883 }
884
Check(ir::AwaitExpression * expr) const885 checker::Type *ETSAnalyzer::Check(ir::AwaitExpression *expr) const
886 {
887 ETSChecker *checker = GetETSChecker();
888 if (expr->TsType() != nullptr) {
889 return expr->TsType();
890 }
891
892 checker::Type *argType = ETSChecker::GetApparentType(expr->argument_->Check(checker));
893 // Check the argument type of await expression
894 if (!argType->IsETSObjectType() ||
895 (argType->AsETSObjectType()->AssemblerName() != compiler::Signatures::BUILTIN_PROMISE)) {
896 checker->ThrowTypeError("'await' expressions require Promise object as argument.", expr->Argument()->Start());
897 }
898
899 expr->SetTsType(argType->AsETSObjectType()->TypeArguments().at(0));
900 return expr->TsType();
901 }
902
Check(ir::BinaryExpression * expr) const903 checker::Type *ETSAnalyzer::Check(ir::BinaryExpression *expr) const
904 {
905 ETSChecker *checker = GetETSChecker();
906 if (expr->TsType() != nullptr) {
907 return expr->TsType();
908 }
909 checker::Type *newTsType {nullptr};
910 std::tie(newTsType, expr->operationType_) =
911 checker->CheckBinaryOperator(expr->Left(), expr->Right(), expr, expr->OperatorType(), expr->Start());
912 expr->SetTsType(newTsType);
913 return expr->TsType();
914 }
915
InitAnonymousLambdaCallee(checker::ETSChecker * checker,ir::Expression * callee,checker::Type * calleeType)916 static checker::Type *InitAnonymousLambdaCallee(checker::ETSChecker *checker, ir::Expression *callee,
917 checker::Type *calleeType)
918 {
919 auto *const arrowFunc = callee->AsArrowFunctionExpression()->Function();
920 auto origParams = arrowFunc->Params();
921 auto signature = ir::FunctionSignature(nullptr, std::move(origParams), arrowFunc->ReturnTypeAnnotation());
922 auto *funcType =
923 checker->Allocator()->New<ir::ETSFunctionType>(std::move(signature), ir::ScriptFunctionFlags::NONE);
924 funcType->SetScope(arrowFunc->Scope()->AsFunctionScope()->ParamScope());
925 auto *const funcIface = funcType->Check(checker);
926 checker->Relation()->SetNode(callee);
927 checker->Relation()->IsAssignableTo(calleeType, funcIface);
928 return funcIface;
929 }
930
ResolveCallExtensionFunction(checker::ETSFunctionType * functionType,checker::ETSChecker * checker,ir::CallExpression * expr)931 static checker::Signature *ResolveCallExtensionFunction(checker::ETSFunctionType *functionType,
932 checker::ETSChecker *checker, ir::CallExpression *expr)
933 {
934 auto *memberExpr = expr->Callee()->AsMemberExpression();
935 expr->Arguments().insert(expr->Arguments().begin(), memberExpr->Object());
936 auto *signature =
937 checker->ResolveCallExpressionAndTrailingLambda(functionType->CallSignatures(), expr, expr->Start());
938 if (!signature->Function()->IsExtensionMethod()) {
939 checker->ThrowTypeError({"Property '", memberExpr->Property()->AsIdentifier()->Name(),
940 "' does not exist on type '", memberExpr->ObjType()->Name(), "'"},
941 memberExpr->Property()->Start());
942 }
943 expr->SetSignature(signature);
944 expr->SetCallee(memberExpr->Property());
945 memberExpr->Property()->AsIdentifier()->SetParent(expr);
946 expr->Arguments()[0]->SetParent(expr);
947 checker->HandleUpdatedCallExpressionNode(expr);
948 // Set TsType for new Callee(original member expression's Object)
949 expr->Callee()->Check(checker);
950 return signature;
951 }
952
ResolveCallForETSExtensionFuncHelperType(checker::ETSExtensionFuncHelperType * type,checker::ETSChecker * checker,ir::CallExpression * expr)953 static checker::Signature *ResolveCallForETSExtensionFuncHelperType(checker::ETSExtensionFuncHelperType *type,
954 checker::ETSChecker *checker,
955 ir::CallExpression *expr)
956 {
957 checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda(
958 type->ClassMethodType()->CallSignatures(), expr, expr->Start(), checker::TypeRelationFlag::NO_THROW);
959
960 if (signature != nullptr) {
961 return signature;
962 }
963
964 return ResolveCallExtensionFunction(type->ExtensionMethodType(), checker, expr);
965 }
966
Check(ir::BlockExpression * st) const967 checker::Type *ETSAnalyzer::Check(ir::BlockExpression *st) const
968 {
969 (void)st;
970 UNREACHABLE();
971 }
972
GetUnionTypeSignatures(ETSChecker * checker,checker::ETSUnionType * etsUnionType)973 ArenaVector<checker::Signature *> GetUnionTypeSignatures(ETSChecker *checker, checker::ETSUnionType *etsUnionType)
974 {
975 ArenaVector<checker::Signature *> callSignatures(checker->Allocator()->Adapter());
976
977 for (auto *constituentType : etsUnionType->ConstituentTypes()) {
978 if (constituentType->IsETSObjectType()) {
979 ArenaVector<checker::Signature *> tmpCallSignatures(checker->Allocator()->Adapter());
980 tmpCallSignatures = constituentType->AsETSObjectType()
981 ->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>("invoke")
982 ->TsType()
983 ->AsETSFunctionType()
984 ->CallSignatures();
985 callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end());
986 }
987 if (constituentType->IsETSFunctionType()) {
988 ArenaVector<checker::Signature *> tmpCallSignatures(checker->Allocator()->Adapter());
989 tmpCallSignatures = constituentType->AsETSFunctionType()->CallSignatures();
990 callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end());
991 }
992 if (constituentType->IsETSUnionType()) {
993 ArenaVector<checker::Signature *> tmpCallSignatures(checker->Allocator()->Adapter());
994 tmpCallSignatures = GetUnionTypeSignatures(checker, constituentType->AsETSUnionType());
995 callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end());
996 }
997 }
998
999 return callSignatures;
1000 }
1001
ChooseSignatures(ETSChecker * checker,checker::Type * calleeType,bool isConstructorCall,bool isFunctionalInterface,bool isUnionTypeWithFunctionalInterface)1002 ArenaVector<checker::Signature *> &ChooseSignatures(ETSChecker *checker, checker::Type *calleeType,
1003 bool isConstructorCall, bool isFunctionalInterface,
1004 bool isUnionTypeWithFunctionalInterface)
1005 {
1006 static ArenaVector<checker::Signature *> unionSignatures(checker->Allocator()->Adapter());
1007 unionSignatures.clear();
1008 if (isConstructorCall) {
1009 return calleeType->AsETSObjectType()->ConstructSignatures();
1010 }
1011 if (isFunctionalInterface) {
1012 return calleeType->AsETSObjectType()
1013 ->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>("invoke")
1014 ->TsType()
1015 ->AsETSFunctionType()
1016 ->CallSignatures();
1017 }
1018 if (isUnionTypeWithFunctionalInterface) {
1019 unionSignatures = GetUnionTypeSignatures(checker, calleeType->AsETSUnionType());
1020 return unionSignatures;
1021 }
1022 return calleeType->AsETSFunctionType()->CallSignatures();
1023 }
1024
ChooseCalleeObj(ETSChecker * checker,ir::CallExpression * expr,checker::Type * calleeType,bool isConstructorCall)1025 checker::ETSObjectType *ChooseCalleeObj(ETSChecker *checker, ir::CallExpression *expr, checker::Type *calleeType,
1026 bool isConstructorCall)
1027 {
1028 if (isConstructorCall) {
1029 return calleeType->AsETSObjectType();
1030 }
1031 if (expr->Callee()->IsIdentifier()) {
1032 return checker->Context().ContainingClass();
1033 }
1034 ASSERT(expr->Callee()->IsMemberExpression());
1035 return expr->Callee()->AsMemberExpression()->ObjType();
1036 }
1037
ResolveSignature(ETSChecker * checker,ir::CallExpression * expr,checker::Type * calleeType,bool isFunctionalInterface,bool isUnionTypeWithFunctionalInterface) const1038 checker::Signature *ETSAnalyzer::ResolveSignature(ETSChecker *checker, ir::CallExpression *expr,
1039 checker::Type *calleeType, bool isFunctionalInterface,
1040 bool isUnionTypeWithFunctionalInterface) const
1041 {
1042 bool extensionFunctionType = expr->Callee()->IsMemberExpression() && checker->ExtensionETSFunctionType(calleeType);
1043
1044 if (calleeType->IsETSExtensionFuncHelperType()) {
1045 return ResolveCallForETSExtensionFuncHelperType(calleeType->AsETSExtensionFuncHelperType(), checker, expr);
1046 }
1047 if (extensionFunctionType) {
1048 return ResolveCallExtensionFunction(calleeType->AsETSFunctionType(), checker, expr);
1049 }
1050 auto &signatures = ChooseSignatures(checker, calleeType, expr->IsETSConstructorCall(), isFunctionalInterface,
1051 isUnionTypeWithFunctionalInterface);
1052 checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda(signatures, expr, expr->Start());
1053 if (signature->Function()->IsExtensionMethod()) {
1054 checker->ThrowTypeError({"No matching call signature"}, expr->Start());
1055 }
1056 return signature;
1057 }
1058
GetReturnType(ir::CallExpression * expr,checker::Type * calleeType) const1059 checker::Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, checker::Type *calleeType) const
1060 {
1061 ETSChecker *checker = GetETSChecker();
1062 bool isConstructorCall = expr->IsETSConstructorCall();
1063 bool isUnionTypeWithFunctionalInterface =
1064 calleeType->IsETSUnionType() &&
1065 calleeType->AsETSUnionType()->HasObjectType(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE);
1066 bool isFunctionalInterface = calleeType->IsETSObjectType() && calleeType->AsETSObjectType()->HasObjectFlag(
1067 checker::ETSObjectFlags::FUNCTIONAL_INTERFACE);
1068 bool etsExtensionFuncHelperType = calleeType->IsETSExtensionFuncHelperType();
1069
1070 if (expr->Callee()->IsArrowFunctionExpression()) {
1071 calleeType = InitAnonymousLambdaCallee(checker, expr->Callee(), calleeType);
1072 isFunctionalInterface = true;
1073 }
1074
1075 if (!isFunctionalInterface && !calleeType->IsETSFunctionType() && !isConstructorCall &&
1076 !etsExtensionFuncHelperType && !isUnionTypeWithFunctionalInterface) {
1077 checker->ThrowTypeError("This expression is not callable.", expr->Start());
1078 }
1079
1080 checker::Signature *signature =
1081 ResolveSignature(checker, expr, calleeType, isFunctionalInterface, isUnionTypeWithFunctionalInterface);
1082
1083 checker->CheckObjectLiteralArguments(signature, expr->Arguments());
1084 checker->AddUndefinedParamsForDefaultParams(signature, expr->Arguments(), checker);
1085
1086 if (!isFunctionalInterface) {
1087 checker::ETSObjectType *calleeObj = ChooseCalleeObj(checker, expr, calleeType, isConstructorCall);
1088 checker->ValidateSignatureAccessibility(calleeObj, expr, signature, expr->Start());
1089 }
1090
1091 ASSERT(signature->Function() != nullptr);
1092 if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) {
1093 checker->CheckThrowingStatements(expr);
1094 }
1095
1096 if (signature->Function()->IsDynamic()) {
1097 ASSERT(signature->Function()->IsDynamic());
1098 auto lang = signature->Function()->Language();
1099 expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), signature->Params(), lang, false));
1100 } else {
1101 ASSERT(!signature->Function()->IsDynamic());
1102 expr->SetSignature(signature);
1103 }
1104
1105 auto *returnType = signature->ReturnType();
1106
1107 if (signature->HasSignatureFlag(SignatureFlags::THIS_RETURN_TYPE)) {
1108 returnType = ChooseCalleeObj(checker, expr, calleeType, isConstructorCall);
1109 }
1110
1111 return returnType;
1112 }
1113
Check(ir::CallExpression * expr) const1114 checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const
1115 {
1116 ETSChecker *checker = GetETSChecker();
1117 if (expr->TsType() != nullptr) {
1118 return expr->TsType();
1119 }
1120 auto *oldCallee = expr->Callee();
1121 checker::Type *calleeType = ETSChecker::GetApparentType(expr->Callee()->Check(checker));
1122 if (expr->Callee() != oldCallee) {
1123 // If it is a static invoke, the callee will be transformed from an identifier to a member expression
1124 // Type check the callee again for member expression
1125 calleeType = expr->Callee()->Check(checker);
1126 }
1127 if (!expr->IsOptional()) {
1128 checker->CheckNonNullishType(calleeType, expr->Callee()->Start());
1129 }
1130 checker::Type *returnType;
1131 if (calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl()) {
1132 // Trailing lambda for js function call is not supported, check the correctness of `foo() {}`
1133 checker->EnsureValidCurlyBrace(expr);
1134 auto lang = calleeType->AsETSDynamicType()->Language();
1135 expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), expr->Arguments(), lang, false));
1136 returnType = expr->Signature()->ReturnType();
1137 } else {
1138 returnType = GetReturnType(expr, calleeType);
1139 }
1140
1141 if (expr->Signature()->RestVar() != nullptr) {
1142 auto *const elementType = expr->Signature()->RestVar()->TsType()->AsETSArrayType()->ElementType();
1143 auto *const arrayType = checker->CreateETSArrayType(elementType)->AsETSArrayType();
1144 checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank());
1145 }
1146
1147 if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) {
1148 expr->Signature()->OwnerVar()->Declaration()->Node()->Check(checker);
1149 returnType = expr->Signature()->ReturnType();
1150 // NOTE(vpukhov): #14902 substituted signature is not updated
1151 }
1152 expr->SetOptionalType(returnType);
1153 if (expr->IsOptional() && checker->MayHaveNulllikeValue(expr->Callee()->Check(checker))) {
1154 checker->Relation()->SetNode(expr);
1155 returnType = checker->CreateOptionalResultType(returnType);
1156 checker->Relation()->SetNode(nullptr);
1157 }
1158 expr->SetTsType(returnType);
1159 expr->SetUncheckedType(checker->GuaranteedTypeForUncheckedCallReturn(expr->Signature()));
1160 return expr->TsType();
1161 }
1162
Check(ir::ChainExpression * expr) const1163 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ChainExpression *expr) const
1164 {
1165 UNREACHABLE();
1166 }
1167
Check(ir::ClassExpression * expr) const1168 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ClassExpression *expr) const
1169 {
1170 UNREACHABLE();
1171 }
1172
Check(ir::ConditionalExpression * expr) const1173 checker::Type *ETSAnalyzer::Check(ir::ConditionalExpression *expr) const
1174 {
1175 ETSChecker *checker = GetETSChecker();
1176 if (expr->TsType() != nullptr) {
1177 return expr->TsType();
1178 }
1179
1180 checker->CheckTruthinessOfType(expr->Test());
1181
1182 checker::Type *consequentType = expr->consequent_->Check(checker);
1183 checker::Type *alternateType = expr->alternate_->Check(checker);
1184
1185 auto *primitiveConsequentType = checker->ETSBuiltinTypeAsPrimitiveType(consequentType);
1186 auto *primitiveAlterType = checker->ETSBuiltinTypeAsPrimitiveType(alternateType);
1187
1188 if (primitiveConsequentType != nullptr && primitiveAlterType != nullptr) {
1189 if (checker->IsTypeIdenticalTo(consequentType, alternateType)) {
1190 expr->SetTsType(checker->GetNonConstantTypeFromPrimitiveType(consequentType));
1191 } else if (checker->IsTypeIdenticalTo(primitiveConsequentType, primitiveAlterType)) {
1192 checker->FlagExpressionWithUnboxing(expr->consequent_->TsType(), primitiveConsequentType,
1193 expr->consequent_);
1194 checker->FlagExpressionWithUnboxing(expr->alternate_->TsType(), primitiveAlterType, expr->alternate_);
1195
1196 expr->SetTsType(primitiveConsequentType);
1197 } else if (primitiveConsequentType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC) &&
1198 primitiveAlterType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) {
1199 checker->FlagExpressionWithUnboxing(expr->consequent_->TsType(), primitiveConsequentType,
1200 expr->consequent_);
1201 checker->FlagExpressionWithUnboxing(expr->alternate_->TsType(), primitiveAlterType, expr->alternate_);
1202
1203 expr->SetTsType(
1204 checker->ApplyConditionalOperatorPromotion(checker, primitiveConsequentType, primitiveAlterType));
1205 } else {
1206 checker->ThrowTypeError("Type error", expr->Range().start);
1207 }
1208 } else {
1209 if (!(consequentType->IsETSArrayType() || alternateType->IsETSArrayType()) &&
1210 !(checker->IsReferenceType(consequentType) && checker->IsReferenceType(alternateType))) {
1211 checker->ThrowTypeError("Type error", expr->Range().start);
1212 } else {
1213 checker->Relation()->SetNode(expr->consequent_);
1214 auto builtinConseqType = checker->PrimitiveTypeAsETSBuiltinType(consequentType);
1215 auto builtinAlternateType = checker->PrimitiveTypeAsETSBuiltinType(alternateType);
1216
1217 if (builtinConseqType == nullptr) {
1218 builtinConseqType = consequentType;
1219 }
1220
1221 if (builtinAlternateType == nullptr) {
1222 builtinAlternateType = alternateType;
1223 }
1224
1225 expr->SetTsType(checker->CreateETSUnionType(builtinConseqType, builtinAlternateType));
1226 }
1227 }
1228
1229 return expr->TsType();
1230 }
1231
Check(ir::DirectEvalExpression * expr) const1232 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::DirectEvalExpression *expr) const
1233 {
1234 UNREACHABLE();
1235 }
1236
Check(ir::FunctionExpression * expr) const1237 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::FunctionExpression *expr) const
1238 {
1239 UNREACHABLE();
1240 }
1241
Check(ir::Identifier * expr) const1242 checker::Type *ETSAnalyzer::Check(ir::Identifier *expr) const
1243 {
1244 ETSChecker *checker = GetETSChecker();
1245 if (expr->TsType() != nullptr) {
1246 return expr->TsType();
1247 }
1248
1249 expr->SetTsType(checker->ResolveIdentifier(expr));
1250 return expr->TsType();
1251 }
1252
Check(ir::ImportExpression * expr) const1253 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportExpression *expr) const
1254 {
1255 UNREACHABLE();
1256 }
1257
Check(ir::MemberExpression * expr) const1258 checker::Type *ETSAnalyzer::Check(ir::MemberExpression *expr) const
1259 {
1260 ETSChecker *checker = GetETSChecker();
1261 if (expr->TsType() != nullptr) {
1262 return expr->TsType();
1263 }
1264
1265 auto *const leftType = checker->GetApparentType(expr->Object()->Check(checker));
1266
1267 if (expr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
1268 if (expr->IsOptional() && !leftType->IsNullish()) {
1269 checker->ThrowTypeError("The type of the object reference must be a nullish array or Record type",
1270 expr->Object()->Start());
1271 }
1272
1273 if (!expr->IsOptional() && leftType->IsNullish()) {
1274 checker->ThrowTypeError("The type of the object reference must be a non-nullish array or Record type",
1275 expr->Object()->Start());
1276 }
1277 }
1278
1279 auto *const baseType = expr->IsOptional() ? checker->GetNonNullishType(leftType) : leftType;
1280 if (!expr->IsOptional()) {
1281 checker->CheckNonNullishType(leftType, expr->Object()->Start());
1282 }
1283
1284 if (expr->IsComputed()) {
1285 return expr->AdjustType(checker, expr->CheckComputed(checker, baseType));
1286 }
1287
1288 if (baseType->IsETSArrayType() && expr->Property()->AsIdentifier()->Name().Is("length")) {
1289 return expr->AdjustType(checker, checker->GlobalIntType());
1290 }
1291
1292 if (baseType->IsETSObjectType()) {
1293 expr->SetObjectType(baseType->AsETSObjectType());
1294 auto [resType, resVar] = expr->ResolveObjectMember(checker);
1295 expr->SetPropVar(resVar);
1296 return expr->AdjustType(checker, resType);
1297 }
1298
1299 if (baseType->IsETSEnumType() || baseType->IsETSStringEnumType()) {
1300 auto [memberType, memberVar] = expr->ResolveEnumMember(checker, baseType);
1301 expr->SetPropVar(memberVar);
1302 return expr->AdjustType(checker, memberType);
1303 }
1304
1305 if (baseType->IsETSUnionType()) {
1306 return expr->AdjustType(checker, expr->CheckUnionMember(checker, baseType));
1307 }
1308
1309 if (baseType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
1310 checker->Relation()->SetNode(expr);
1311 expr->SetObjectType(checker->PrimitiveTypeAsETSBuiltinType(baseType)->AsETSObjectType());
1312 checker->AddBoxingUnboxingFlagsToNode(expr, expr->ObjType());
1313 auto [resType, resVar] = expr->ResolveObjectMember(checker);
1314 expr->SetPropVar(resVar);
1315 return expr->AdjustType(checker, resType);
1316 }
1317
1318 checker->ThrowTypeError({"Cannot access property of non-object or non-enum type"}, expr->Object()->Start());
1319 }
1320
Check(ir::NewExpression * expr) const1321 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::NewExpression *expr) const
1322 {
1323 UNREACHABLE();
1324 }
PreferredType(ir::ObjectExpression * expr) const1325 checker::Type *ETSAnalyzer::PreferredType(ir::ObjectExpression *expr) const
1326 {
1327 return expr->preferredType_;
1328 }
1329
Check(ir::ObjectExpression * expr) const1330 checker::Type *ETSAnalyzer::Check(ir::ObjectExpression *expr) const
1331 {
1332 ETSChecker *checker = GetETSChecker();
1333 if (expr->TsType() != nullptr) {
1334 return expr->TsType();
1335 }
1336
1337 if (expr->PreferredType() == nullptr) {
1338 checker->ThrowTypeError({"need to specify target type for class composite"}, expr->Start());
1339 }
1340 if (!expr->PreferredType()->IsETSObjectType()) {
1341 checker->ThrowTypeError({"target type for class composite needs to be an object type"}, expr->Start());
1342 }
1343
1344 if (expr->PreferredType()->IsETSDynamicType()) {
1345 for (ir::Expression *propExpr : expr->Properties()) {
1346 ASSERT(propExpr->IsProperty());
1347 ir::Property *prop = propExpr->AsProperty();
1348 ir::Expression *value = prop->Value();
1349 value->Check(checker);
1350 ASSERT(value->TsType());
1351 }
1352
1353 expr->SetTsType(expr->PreferredType());
1354 return expr->PreferredType();
1355 }
1356
1357 checker::ETSObjectType *objType = expr->PreferredType()->AsETSObjectType();
1358 if (objType->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT | checker::ETSObjectFlags::INTERFACE)) {
1359 checker->ThrowTypeError({"target type for class composite ", objType->Name(), " is not instantiable"},
1360 expr->Start());
1361 }
1362
1363 bool haveEmptyConstructor = false;
1364 for (checker::Signature *sig : objType->ConstructSignatures()) {
1365 if (sig->Params().empty()) {
1366 haveEmptyConstructor = true;
1367 checker->ValidateSignatureAccessibility(objType, nullptr, sig, expr->Start());
1368 break;
1369 }
1370 }
1371 if (!haveEmptyConstructor) {
1372 checker->ThrowTypeError({"type ", objType->Name(), " has no parameterless constructor"}, expr->Start());
1373 }
1374
1375 for (ir::Expression *propExpr : expr->Properties()) {
1376 ASSERT(propExpr->IsProperty());
1377 ir::Property *prop = propExpr->AsProperty();
1378 ir::Expression *key = prop->Key();
1379 ir::Expression *value = prop->Value();
1380
1381 util::StringView pname;
1382 if (key->IsStringLiteral()) {
1383 pname = key->AsStringLiteral()->Str();
1384 } else if (key->IsIdentifier()) {
1385 pname = key->AsIdentifier()->Name();
1386 } else {
1387 checker->ThrowTypeError({"key in class composite should be either identifier or string literal"},
1388 expr->Start());
1389 }
1390 varbinder::LocalVariable *lv = objType->GetProperty(pname, checker::PropertySearchFlags::SEARCH_INSTANCE_FIELD |
1391 checker::PropertySearchFlags::SEARCH_IN_BASE);
1392 if (lv == nullptr) {
1393 checker->ThrowTypeError({"type ", objType->Name(), " has no property named ", pname}, propExpr->Start());
1394 }
1395 checker->ValidatePropertyAccess(lv, objType, propExpr->Start());
1396 if (lv->HasFlag(varbinder::VariableFlags::READONLY)) {
1397 checker->ThrowTypeError({"cannot assign to readonly property ", pname}, propExpr->Start());
1398 }
1399
1400 auto *propType = checker->GetTypeOfVariable(lv);
1401 key->SetTsType(propType);
1402
1403 if (value->IsObjectExpression()) {
1404 value->AsObjectExpression()->SetPreferredType(propType);
1405 }
1406 value->SetTsType(value->Check(checker));
1407 checker::AssignmentContext(checker->Relation(), value, value->TsType(), propType, value->Start(),
1408 {"value type is not assignable to the property type"});
1409 }
1410
1411 expr->SetTsType(objType);
1412 return objType;
1413 }
1414
Check(ir::OmittedExpression * expr) const1415 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::OmittedExpression *expr) const
1416 {
1417 UNREACHABLE();
1418 }
1419
Check(ir::OpaqueTypeNode * expr) const1420 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::OpaqueTypeNode *expr) const
1421 {
1422 UNREACHABLE();
1423 }
1424
Check(ir::SequenceExpression * expr) const1425 checker::Type *ETSAnalyzer::Check(ir::SequenceExpression *expr) const
1426 {
1427 ETSChecker *checker = GetETSChecker();
1428 if (expr->TsType() != nullptr) {
1429 return expr->TsType();
1430 }
1431
1432 for (auto *it : expr->Sequence()) {
1433 it->Check(checker);
1434 }
1435 return nullptr;
1436 }
1437
Check(ir::SuperExpression * expr) const1438 checker::Type *ETSAnalyzer::Check(ir::SuperExpression *expr) const
1439 {
1440 ETSChecker *checker = GetETSChecker();
1441 if (expr->TsType() != nullptr) {
1442 return expr->TsType();
1443 }
1444
1445 expr->SetTsType(checker->CheckThisOrSuperAccess(expr, checker->Context().ContainingClass()->SuperType(), "super"));
1446 return expr->TsType();
1447 }
1448
Check(ir::TaggedTemplateExpression * expr) const1449 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TaggedTemplateExpression *expr) const
1450 {
1451 UNREACHABLE();
1452 }
1453
Check(ir::TemplateLiteral * expr) const1454 checker::Type *ETSAnalyzer::Check(ir::TemplateLiteral *expr) const
1455 {
1456 ETSChecker *checker = GetETSChecker();
1457 if (expr->TsType() != nullptr) {
1458 return expr->TsType();
1459 }
1460
1461 if (expr->Quasis().size() != expr->Expressions().size() + 1U) {
1462 checker->ThrowTypeError("Invalid string template expression", expr->Start());
1463 }
1464
1465 for (auto *it : expr->Expressions()) {
1466 it->Check(checker);
1467 }
1468
1469 for (auto *it : expr->Quasis()) {
1470 it->Check(checker);
1471 }
1472
1473 expr->SetTsType(checker->GlobalBuiltinETSStringType());
1474 return expr->TsType();
1475 }
1476
Check(ir::ThisExpression * expr) const1477 checker::Type *ETSAnalyzer::Check(ir::ThisExpression *expr) const
1478 {
1479 ETSChecker *checker = GetETSChecker();
1480 if (expr->TsType() != nullptr) {
1481 return expr->TsType();
1482 }
1483
1484 /*
1485 example code:
1486 ```
1487 class A {
1488 prop
1489 }
1490 function A.method() {
1491 let a = () => {
1492 console.println(this.prop)
1493 }
1494 }
1495 is identical to
1496 function method(this: A) {
1497 let a = () => {
1498 console.println(this.prop)
1499 }
1500 }
1501 ```
1502 here when "this" is used inside an extension function, we need to bind "this" to the first
1503 parameter(MANDATORY_PARAM_THIS), and capture the paramter's variable other than containing class's variable
1504 */
1505 auto *variable = checker->AsETSChecker()->Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS).variable;
1506 if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) {
1507 ASSERT(variable != nullptr);
1508 expr->SetTsType(variable->TsType());
1509 } else {
1510 expr->SetTsType(checker->CheckThisOrSuperAccess(expr, checker->Context().ContainingClass(), "this"));
1511 }
1512
1513 if (checker->HasStatus(checker::CheckerStatus::IN_LAMBDA)) {
1514 if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) {
1515 checker->Context().AddCapturedVar(variable, expr->Start());
1516 } else {
1517 checker->Context().AddCapturedVar(checker->Context().ContainingClass()->Variable(), expr->Start());
1518 }
1519 }
1520
1521 return expr->TsType();
1522 }
1523
ProcessExclamationMark(ETSChecker * checker,ir::UnaryExpression * expr,checker::Type * operandType)1524 void ProcessExclamationMark(ETSChecker *checker, ir::UnaryExpression *expr, checker::Type *operandType)
1525 {
1526 if (checker->IsNullLikeOrVoidExpression(expr->Argument())) {
1527 auto tsType = checker->CreateETSBooleanType(true);
1528 tsType->AddTypeFlag(checker::TypeFlag::CONSTANT);
1529 expr->SetTsType(tsType);
1530 return;
1531 }
1532
1533 if (operandType == nullptr || !operandType->IsConditionalExprType()) {
1534 checker->ThrowTypeError("Bad operand type, the type of the operand must be boolean type.",
1535 expr->Argument()->Start());
1536 }
1537
1538 auto exprRes = operandType->ResolveConditionExpr();
1539 if (std::get<0>(exprRes)) {
1540 auto tsType = checker->CreateETSBooleanType(!std::get<1>(exprRes));
1541 tsType->AddTypeFlag(checker::TypeFlag::CONSTANT);
1542 expr->SetTsType(tsType);
1543 return;
1544 }
1545
1546 expr->SetTsType(checker->GlobalETSBooleanType());
1547 }
1548
SetTsTypeForUnaryExpression(ETSChecker * checker,ir::UnaryExpression * expr,checker::Type * operandType,checker::Type * argType)1549 void SetTsTypeForUnaryExpression(ETSChecker *checker, ir::UnaryExpression *expr, checker::Type *operandType,
1550 checker::Type *argType)
1551 {
1552 switch (expr->OperatorType()) {
1553 case lexer::TokenType::PUNCTUATOR_MINUS:
1554 case lexer::TokenType::PUNCTUATOR_PLUS: {
1555 if (operandType == nullptr || !operandType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) {
1556 checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.",
1557 expr->Argument()->Start());
1558 }
1559
1560 if (operandType->HasTypeFlag(checker::TypeFlag::CONSTANT) &&
1561 expr->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS) {
1562 expr->SetTsType(checker->NegateNumericType(operandType, expr));
1563 break;
1564 }
1565
1566 expr->SetTsType(operandType);
1567 break;
1568 }
1569 case lexer::TokenType::PUNCTUATOR_TILDE: {
1570 if (operandType == nullptr || !operandType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) {
1571 checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.",
1572 expr->Argument()->Start());
1573 }
1574
1575 if (operandType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
1576 expr->SetTsType(checker->BitwiseNegateNumericType(operandType, expr));
1577 break;
1578 }
1579
1580 expr->SetTsType(checker->SelectGlobalIntegerTypeForNumeric(operandType));
1581 break;
1582 }
1583 case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
1584 ProcessExclamationMark(checker, expr, operandType);
1585 break;
1586 }
1587 case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: {
1588 expr->SetTsType(argType);
1589 break;
1590 }
1591 default: {
1592 UNREACHABLE();
1593 break;
1594 }
1595 }
1596 }
1597
Check(ir::UnaryExpression * expr) const1598 checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const
1599 {
1600 ETSChecker *checker = GetETSChecker();
1601
1602 if (expr->TsType() != nullptr) {
1603 return expr->TsType();
1604 }
1605
1606 auto argType = expr->argument_->Check(checker);
1607 const auto isCondExpr = expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK;
1608 checker::Type *operandType = checker->ApplyUnaryOperatorPromotion(argType, true, true, isCondExpr);
1609 auto unboxedOperandType = isCondExpr ? checker->ETSBuiltinTypeAsConditionalType(argType)
1610 : checker->ETSBuiltinTypeAsPrimitiveType(argType);
1611
1612 if (argType != nullptr && argType->IsETSBigIntType() && argType->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) {
1613 switch (expr->OperatorType()) {
1614 case lexer::TokenType::PUNCTUATOR_MINUS: {
1615 checker::Type *type = checker->CreateETSBigIntLiteralType(argType->AsETSBigIntType()->GetValue());
1616
1617 // We do not need this const anymore as we are negating the bigint object in runtime
1618 type->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
1619 expr->argument_->SetTsType(type);
1620 expr->SetTsType(type);
1621 return expr->TsType();
1622 }
1623 default:
1624 // Handled below
1625 // NOTE(kkonsw): handle other unary operators for bigint literals
1626 break;
1627 }
1628 }
1629
1630 if (argType != nullptr && argType->IsETSBigIntType()) {
1631 switch (expr->OperatorType()) {
1632 case lexer::TokenType::PUNCTUATOR_MINUS:
1633 case lexer::TokenType::PUNCTUATOR_PLUS:
1634 case lexer::TokenType::PUNCTUATOR_TILDE: {
1635 expr->SetTsType(argType);
1636 return expr->TsType();
1637 }
1638 default:
1639 break;
1640 }
1641 }
1642
1643 SetTsTypeForUnaryExpression(checker, expr, operandType, argType);
1644
1645 if ((argType != nullptr) && argType->IsETSObjectType() && (unboxedOperandType != nullptr) &&
1646 unboxedOperandType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
1647 expr->Argument()->AddBoxingUnboxingFlags(checker->GetUnboxingFlag(unboxedOperandType));
1648 }
1649
1650 return expr->TsType();
1651 }
1652
Check(ir::UpdateExpression * expr) const1653 checker::Type *ETSAnalyzer::Check(ir::UpdateExpression *expr) const
1654 {
1655 ETSChecker *checker = GetETSChecker();
1656 if (expr->TsType() != nullptr) {
1657 return expr->TsType();
1658 }
1659
1660 checker::Type *operandType = expr->argument_->Check(checker);
1661 if (expr->Argument()->IsIdentifier()) {
1662 checker->ValidateUnaryOperatorOperand(expr->Argument()->AsIdentifier()->Variable());
1663 } else if (expr->Argument()->IsTSAsExpression()) {
1664 if (auto *const asExprVar = expr->Argument()->AsTSAsExpression()->Variable(); asExprVar != nullptr) {
1665 checker->ValidateUnaryOperatorOperand(asExprVar);
1666 }
1667 } else {
1668 ASSERT(expr->Argument()->IsMemberExpression());
1669 varbinder::LocalVariable *propVar = expr->argument_->AsMemberExpression()->PropVar();
1670 if (propVar != nullptr) {
1671 checker->ValidateUnaryOperatorOperand(propVar);
1672 }
1673 }
1674
1675 if (operandType->IsETSBigIntType()) {
1676 expr->SetTsType(operandType);
1677 return expr->TsType();
1678 }
1679
1680 auto unboxedType = checker->ETSBuiltinTypeAsPrimitiveType(operandType);
1681 if (unboxedType == nullptr || !unboxedType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) {
1682 checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.",
1683 expr->Argument()->Start());
1684 }
1685
1686 if (operandType->IsETSObjectType()) {
1687 expr->Argument()->AddBoxingUnboxingFlags(checker->GetUnboxingFlag(unboxedType) |
1688 checker->GetBoxingFlag(unboxedType));
1689 }
1690
1691 expr->SetTsType(operandType);
1692 return expr->TsType();
1693 }
1694
Check(ir::YieldExpression * expr) const1695 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::YieldExpression *expr) const
1696 {
1697 UNREACHABLE();
1698 }
1699 // compile methods for LITERAL EXPRESSIONS in alphabetical order
Check(ir::BigIntLiteral * expr) const1700 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::BigIntLiteral *expr) const
1701 {
1702 ETSChecker *checker = GetETSChecker();
1703 expr->SetTsType(checker->CreateETSBigIntLiteralType(expr->Str()));
1704 return expr->TsType();
1705 }
1706
Check(ir::BooleanLiteral * expr) const1707 checker::Type *ETSAnalyzer::Check(ir::BooleanLiteral *expr) const
1708 {
1709 ETSChecker *checker = GetETSChecker();
1710 if (expr->TsType() == nullptr) {
1711 expr->SetTsType(checker->CreateETSBooleanType(expr->Value()));
1712 }
1713 return expr->TsType();
1714 }
1715
Check(ir::CharLiteral * expr) const1716 checker::Type *ETSAnalyzer::Check(ir::CharLiteral *expr) const
1717 {
1718 ETSChecker *checker = GetETSChecker();
1719 if (expr->TsType() == nullptr) {
1720 expr->SetTsType(checker->Allocator()->New<checker::CharType>(expr->Char()));
1721 }
1722 return expr->TsType();
1723 }
1724
Check(ir::NullLiteral * expr) const1725 checker::Type *ETSAnalyzer::Check(ir::NullLiteral *expr) const
1726 {
1727 ETSChecker *checker = GetETSChecker();
1728 if (expr->TsType() == nullptr) {
1729 expr->SetTsType(checker->GlobalETSNullType());
1730 }
1731 return expr->TsType();
1732 }
1733
Check(ir::NumberLiteral * expr) const1734 checker::Type *ETSAnalyzer::Check(ir::NumberLiteral *expr) const
1735 {
1736 ETSChecker *checker = GetETSChecker();
1737 if (expr->Number().IsInt()) {
1738 expr->SetTsType(checker->CreateIntType(expr->Number().GetInt()));
1739 return expr->TsType();
1740 }
1741
1742 if (expr->Number().IsLong()) {
1743 expr->SetTsType(checker->CreateLongType(expr->Number().GetLong()));
1744 return expr->TsType();
1745 }
1746
1747 if (expr->Number().IsFloat()) {
1748 expr->SetTsType(checker->CreateFloatType(expr->Number().GetFloat()));
1749 return expr->TsType();
1750 }
1751
1752 expr->SetTsType(checker->CreateDoubleType(expr->Number().GetDouble()));
1753 return expr->TsType();
1754 }
1755
Check(ir::RegExpLiteral * expr) const1756 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::RegExpLiteral *expr) const
1757 {
1758 UNREACHABLE();
1759 }
1760
Check(ir::StringLiteral * expr) const1761 checker::Type *ETSAnalyzer::Check(ir::StringLiteral *expr) const
1762 {
1763 ETSChecker *checker = GetETSChecker();
1764 if (expr->TsType() == nullptr) {
1765 expr->SetTsType(checker->CreateETSStringLiteralType(expr->Str()));
1766 }
1767 return expr->TsType();
1768 }
1769
Check(ir::UndefinedLiteral * expr) const1770 checker::Type *ETSAnalyzer::Check(ir::UndefinedLiteral *expr) const
1771 {
1772 (void)expr;
1773 UNREACHABLE();
1774 }
1775
1776 // compile methods for MODULE-related nodes in alphabetical order
Check(ir::ExportAllDeclaration * st) const1777 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportAllDeclaration *st) const
1778 {
1779 UNREACHABLE();
1780 }
1781
Check(ir::ExportDefaultDeclaration * st) const1782 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportDefaultDeclaration *st) const
1783 {
1784 UNREACHABLE();
1785 }
1786
Check(ir::ExportNamedDeclaration * st) const1787 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportNamedDeclaration *st) const
1788 {
1789 UNREACHABLE();
1790 }
1791
Check(ir::ExportSpecifier * st) const1792 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportSpecifier *st) const
1793 {
1794 UNREACHABLE();
1795 }
1796
Check(ir::ImportDeclaration * st) const1797 checker::Type *ETSAnalyzer::Check(ir::ImportDeclaration *st) const
1798 {
1799 ETSChecker *checker = GetETSChecker();
1800 checker::Type *type = nullptr;
1801 for (auto *spec : st->Specifiers()) {
1802 if (spec->IsImportNamespaceSpecifier()) {
1803 type = spec->AsImportNamespaceSpecifier()->Check(checker);
1804 }
1805 }
1806
1807 return type;
1808 }
1809
Check(ir::ImportDefaultSpecifier * st) const1810 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportDefaultSpecifier *st) const
1811 {
1812 UNREACHABLE();
1813 }
1814
CreateSyntheticType(ETSChecker * checker,util::StringView const & syntheticName,checker::ETSObjectType * lastObjectType,ir::Identifier * id)1815 checker::ETSObjectType *CreateSyntheticType(ETSChecker *checker, util::StringView const &syntheticName,
1816 checker::ETSObjectType *lastObjectType, ir::Identifier *id)
1817 {
1818 auto *syntheticObjType = checker->Allocator()->New<checker::ETSObjectType>(
1819 checker->Allocator(), syntheticName, syntheticName, id, checker::ETSObjectFlags::NO_OPTS);
1820
1821 auto *classDecl = checker->Allocator()->New<varbinder::ClassDecl>(syntheticName);
1822 varbinder::LocalVariable *var =
1823 checker->Allocator()->New<varbinder::LocalVariable>(classDecl, varbinder::VariableFlags::CLASS);
1824 var->SetTsType(syntheticObjType);
1825 lastObjectType->AddProperty<checker::PropertyType::STATIC_FIELD>(var);
1826 syntheticObjType->SetEnclosingType(lastObjectType);
1827 return syntheticObjType;
1828 }
1829
Check(ir::ImportNamespaceSpecifier * st) const1830 checker::Type *ETSAnalyzer::Check(ir::ImportNamespaceSpecifier *st) const
1831 {
1832 ETSChecker *checker = GetETSChecker();
1833 if (st->Local()->Name().Empty()) {
1834 return nullptr;
1835 }
1836
1837 if (st->Local()->AsIdentifier()->TsType() != nullptr) {
1838 return st->Local()->TsType();
1839 }
1840
1841 auto *importDecl = st->Parent()->AsETSImportDeclaration();
1842 auto importPath = importDecl->Source()->Str();
1843
1844 if (importDecl->IsPureDynamic()) {
1845 auto *type = checker->GlobalBuiltinDynamicType(importDecl->Language());
1846 checker->SetrModuleObjectTsType(st->Local(), type);
1847 return type;
1848 }
1849
1850 std::string packageName =
1851 (importDecl->Module() == nullptr) ? importPath.Mutf8() : importDecl->Module()->Str().Mutf8();
1852
1853 std::replace(packageName.begin(), packageName.end(), '/', '.');
1854 util::UString packagePath(packageName, checker->Allocator());
1855 std::vector<util::StringView> syntheticNames = checker->GetNameForSynteticObjectType(packagePath.View());
1856
1857 ASSERT(!syntheticNames.empty());
1858
1859 auto assemblerName = syntheticNames[0];
1860 if (importDecl->Module() != nullptr) {
1861 assemblerName = util::UString(assemblerName.Mutf8().append(".").append(compiler::Signatures::ETS_GLOBAL),
1862 checker->Allocator())
1863 .View();
1864 }
1865
1866 auto *moduleObjectType =
1867 checker->Allocator()->New<checker::ETSObjectType>(checker->Allocator(), syntheticNames[0], assemblerName,
1868 st->Local()->AsIdentifier(), checker::ETSObjectFlags::CLASS);
1869
1870 auto *rootDecl = checker->Allocator()->New<varbinder::ClassDecl>(syntheticNames[0]);
1871 varbinder::LocalVariable *rootVar =
1872 checker->Allocator()->New<varbinder::LocalVariable>(rootDecl, varbinder::VariableFlags::NONE);
1873 rootVar->SetTsType(moduleObjectType);
1874
1875 syntheticNames.erase(syntheticNames.begin());
1876 checker::ETSObjectType *lastObjectType(moduleObjectType);
1877
1878 for (const auto &syntheticName : syntheticNames) {
1879 lastObjectType = CreateSyntheticType(checker, syntheticName, lastObjectType, st->Local()->AsIdentifier());
1880 }
1881
1882 checker->SetPropertiesForModuleObject(
1883 lastObjectType,
1884 (importDecl->Module() != nullptr)
1885 ? util::UString(importPath.Mutf8() + importDecl->Module()->Str().Mutf8(), checker->Allocator()).View()
1886 : importPath);
1887 checker->SetrModuleObjectTsType(st->Local(), lastObjectType);
1888
1889 return moduleObjectType;
1890 }
1891
Check(ir::ImportSpecifier * st) const1892 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportSpecifier *st) const
1893 {
1894 UNREACHABLE();
1895 }
1896 // compile methods for STATEMENTS in alphabetical order
Check(ir::AssertStatement * st) const1897 checker::Type *ETSAnalyzer::Check(ir::AssertStatement *st) const
1898 {
1899 ETSChecker *checker = GetETSChecker();
1900 checker->CheckTruthinessOfType(st->test_);
1901
1902 if (st->Second() != nullptr) {
1903 auto *msgType = st->second_->Check(checker);
1904
1905 if (!msgType->IsETSStringType()) {
1906 checker->ThrowTypeError("Assert message must be string", st->Second()->Start());
1907 }
1908 }
1909
1910 return nullptr;
1911 }
1912
Check(ir::BlockStatement * st) const1913 checker::Type *ETSAnalyzer::Check(ir::BlockStatement *st) const
1914 {
1915 ETSChecker *checker = GetETSChecker();
1916 checker::ScopeContext scopeCtx(checker, st->Scope());
1917
1918 for (auto *it : st->Statements()) {
1919 it->Check(checker);
1920 }
1921
1922 for (auto [stmt, trailing_block] : st->trailingBlocks_) {
1923 auto iterator = std::find(st->Statements().begin(), st->Statements().end(), stmt);
1924 ASSERT(iterator != st->Statements().end());
1925 st->Statements().insert(iterator + 1, trailing_block);
1926 trailing_block->Check(checker);
1927 }
1928
1929 return nullptr;
1930 }
1931
Check(ir::BreakStatement * st) const1932 checker::Type *ETSAnalyzer::Check(ir::BreakStatement *st) const
1933 {
1934 ETSChecker *checker = GetETSChecker();
1935 st->target_ = checker->FindJumpTarget(st->Type(), st, st->Ident());
1936 return nullptr;
1937 }
1938
Check(ir::ClassDeclaration * st) const1939 checker::Type *ETSAnalyzer::Check(ir::ClassDeclaration *st) const
1940 {
1941 ETSChecker *checker = GetETSChecker();
1942 st->Definition()->Check(checker);
1943 return nullptr;
1944 }
1945
Check(ir::ContinueStatement * st) const1946 checker::Type *ETSAnalyzer::Check(ir::ContinueStatement *st) const
1947 {
1948 ETSChecker *checker = GetETSChecker();
1949 st->target_ = checker->FindJumpTarget(st->Type(), st, st->Ident());
1950 return nullptr;
1951 }
1952
Check(ir::DebuggerStatement * st) const1953 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::DebuggerStatement *st) const
1954 {
1955 UNREACHABLE();
1956 }
1957
Check(ir::DoWhileStatement * st) const1958 checker::Type *ETSAnalyzer::Check(ir::DoWhileStatement *st) const
1959 {
1960 ETSChecker *checker = GetETSChecker();
1961 checker::ScopeContext scopeCtx(checker, st->Scope());
1962
1963 checker->CheckTruthinessOfType(st->Test());
1964 st->Body()->Check(checker);
1965
1966 return nullptr;
1967 }
1968
Check(ir::EmptyStatement * st) const1969 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const
1970 {
1971 return nullptr;
1972 }
1973
Check(ir::ExpressionStatement * st) const1974 checker::Type *ETSAnalyzer::Check(ir::ExpressionStatement *st) const
1975 {
1976 ETSChecker *checker = GetETSChecker();
1977 return st->GetExpression()->Check(checker);
1978 }
1979
Check(ir::ForInStatement * st) const1980 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ForInStatement *st) const
1981 {
1982 UNREACHABLE();
1983 }
1984
1985 // NOLINTBEGIN(modernize-avoid-c-arrays)
1986 static constexpr char const INVALID_SOURCE_EXPR_TYPE[] =
1987 "'For-of' statement source expression should be either a string or an array.";
1988 static constexpr char const INVALID_CONST_ASSIGNMENT[] = "Cannot assign a value to a constant variable ";
1989 static constexpr char const ITERATOR_TYPE_ABSENT[] = "Cannot obtain iterator type in 'for-of' statement.";
1990 // NOLINTEND(modernize-avoid-c-arrays)
1991
GetIteratorType(ETSChecker * checker,checker::Type * elemType,ir::AstNode * left)1992 checker::Type *GetIteratorType(ETSChecker *checker, checker::Type *elemType, ir::AstNode *left)
1993 {
1994 // Just to avoid extra nested level(s)
1995 auto const getIterType = [checker, elemType](ir::VariableDeclarator *const declarator) -> checker::Type * {
1996 if (declarator->TsType() == nullptr) {
1997 if (auto *resolved = checker->FindVariableInFunctionScope(declarator->Id()->AsIdentifier()->Name());
1998 resolved != nullptr) {
1999 resolved->SetTsType(elemType);
2000 return elemType;
2001 }
2002 } else {
2003 return declarator->TsType();
2004 }
2005 return nullptr;
2006 };
2007
2008 checker::Type *iterType = nullptr;
2009 if (left->IsIdentifier()) {
2010 if (auto *const variable = left->AsIdentifier()->Variable(); variable != nullptr) {
2011 if (variable->Declaration()->IsConstDecl()) {
2012 checker->ThrowTypeError({INVALID_CONST_ASSIGNMENT, variable->Name()},
2013 variable->Declaration()->Node()->Start());
2014 }
2015 }
2016 iterType = left->AsIdentifier()->TsType();
2017 } else if (left->IsVariableDeclaration()) {
2018 if (auto const &declarators = left->AsVariableDeclaration()->Declarators(); !declarators.empty()) {
2019 iterType = getIterType(declarators.front());
2020 }
2021 }
2022
2023 if (iterType == nullptr) {
2024 checker->ThrowTypeError(ITERATOR_TYPE_ABSENT, left->Start());
2025 }
2026 return iterType;
2027 }
2028
Check(ir::ForOfStatement * st) const2029 checker::Type *ETSAnalyzer::Check(ir::ForOfStatement *st) const
2030 {
2031 ETSChecker *checker = GetETSChecker();
2032 checker::ScopeContext scopeCtx(checker, st->Scope());
2033
2034 checker::Type *const exprType = st->Right()->Check(checker);
2035 checker::Type *elemType;
2036
2037 if (exprType == nullptr || (!exprType->IsETSArrayType() && !exprType->IsETSStringType())) {
2038 checker->ThrowTypeError(INVALID_SOURCE_EXPR_TYPE, st->Right()->Start());
2039 } else if (exprType->IsETSStringType()) {
2040 elemType = checker->GetGlobalTypesHolder()->GlobalCharType();
2041 } else {
2042 elemType = exprType->AsETSArrayType()->ElementType()->Instantiate(checker->Allocator(), checker->Relation(),
2043 checker->GetGlobalTypesHolder());
2044 elemType->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
2045 }
2046
2047 st->Left()->Check(checker);
2048 checker::Type *iterType = GetIteratorType(checker, elemType, st->Left());
2049 auto *const relation = checker->Relation();
2050 relation->SetFlags(checker::TypeRelationFlag::ASSIGNMENT_CONTEXT);
2051 relation->SetNode(checker->AllocNode<ir::SuperExpression>()); // Dummy node to avoid assertion!
2052
2053 if (!relation->IsAssignableTo(elemType, iterType)) {
2054 std::stringstream ss {};
2055 ss << "Source element type '";
2056 elemType->ToString(ss);
2057 ss << "' is not assignable to the loop iterator type '";
2058 iterType->ToString(ss);
2059 ss << "'.";
2060 checker->ThrowTypeError(ss.str(), st->Start());
2061 }
2062
2063 relation->SetNode(nullptr);
2064 relation->SetFlags(checker::TypeRelationFlag::NONE);
2065
2066 st->Body()->Check(checker);
2067
2068 return nullptr;
2069 }
2070
Check(ir::ForUpdateStatement * st) const2071 checker::Type *ETSAnalyzer::Check(ir::ForUpdateStatement *st) const
2072 {
2073 ETSChecker *checker = GetETSChecker();
2074 checker::ScopeContext scopeCtx(checker, st->Scope());
2075
2076 if (st->Init() != nullptr) {
2077 st->Init()->Check(checker);
2078 }
2079
2080 if (st->Test() != nullptr) {
2081 checker->CheckTruthinessOfType(st->Test());
2082 }
2083
2084 if (st->Update() != nullptr) {
2085 st->Update()->Check(checker);
2086 }
2087
2088 st->Body()->Check(checker);
2089
2090 return nullptr;
2091 }
2092
Check(ir::FunctionDeclaration * st) const2093 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::FunctionDeclaration *st) const
2094 {
2095 UNREACHABLE();
2096 }
2097
Check(ir::IfStatement * st) const2098 checker::Type *ETSAnalyzer::Check(ir::IfStatement *st) const
2099 {
2100 ETSChecker *checker = GetETSChecker();
2101 checker->CheckTruthinessOfType(st->test_);
2102
2103 st->consequent_->Check(checker);
2104
2105 if (st->Alternate() != nullptr) {
2106 st->alternate_->Check(checker);
2107 }
2108
2109 return nullptr;
2110 }
2111
Check(ir::LabelledStatement * st) const2112 checker::Type *ETSAnalyzer::Check(ir::LabelledStatement *st) const
2113 {
2114 ETSChecker *checker = GetETSChecker();
2115 st->body_->Check(checker);
2116 return nullptr;
2117 }
2118
CheckArgumentVoidType(checker::Type * & funcReturnType,ETSChecker * checker,const std::string & name,ir::ReturnStatement * st)2119 void CheckArgumentVoidType(checker::Type *&funcReturnType, ETSChecker *checker, const std::string &name,
2120 ir::ReturnStatement *st)
2121 {
2122 if (name.find(compiler::Signatures::ETS_MAIN_WITH_MANGLE_BEGIN) != std::string::npos) {
2123 if (funcReturnType == checker->GlobalBuiltinVoidType()) {
2124 funcReturnType = checker->GlobalVoidType();
2125 } else if (!funcReturnType->IsETSVoidType() && !funcReturnType->IsIntType()) {
2126 checker->ThrowTypeError("Bad return type, main enable only void or int type.", st->Start());
2127 }
2128 }
2129 }
2130
CheckReturnType(ETSChecker * checker,checker::Type * funcReturnType,checker::Type * argumentType,ir::Expression * stArgument)2131 void CheckReturnType(ETSChecker *checker, checker::Type *funcReturnType, checker::Type *argumentType,
2132 ir::Expression *stArgument)
2133 {
2134 if (funcReturnType->IsETSVoidType() || funcReturnType == checker->GlobalBuiltinVoidType()) {
2135 if (argumentType != checker->GlobalVoidType() && argumentType != checker->GlobalBuiltinVoidType()) {
2136 checker->ThrowTypeError("Unexpected return value, enclosing method return type is void.",
2137 stArgument->Start());
2138 }
2139 } else {
2140 checker::AssignmentContext(checker->Relation(), stArgument, argumentType, funcReturnType, stArgument->Start(),
2141 {"Return statement type is not compatible with the enclosing method's return type."},
2142 checker::TypeRelationFlag::DIRECT_RETURN);
2143 }
2144 }
2145
InferReturnType(ETSChecker * checker,ir::ScriptFunction * containingFunc,checker::Type * & funcReturnType,ir::Expression * stArgument)2146 void InferReturnType(ETSChecker *checker, ir::ScriptFunction *containingFunc, checker::Type *&funcReturnType,
2147 ir::Expression *stArgument)
2148 {
2149 // First (or single) return statement in the function:
2150 funcReturnType = stArgument == nullptr
2151 ? containingFunc->IsEntryPoint() ? checker->GlobalVoidType() : checker->GlobalBuiltinVoidType()
2152 : stArgument->Check(checker);
2153 if (funcReturnType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
2154 // remove CONSTANT type modifier if exists
2155 funcReturnType =
2156 funcReturnType->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder());
2157 funcReturnType->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
2158 }
2159 /*
2160 when st_argment is ArrowFunctionExpression, need infer type for st_argment
2161 example code:
2162 ```
2163 return () => {}
2164 ```
2165 */
2166 if (stArgument != nullptr && stArgument->IsArrowFunctionExpression()) {
2167 auto arrowFunc = stArgument->AsArrowFunctionExpression();
2168 auto typeAnnotation = arrowFunc->CreateTypeAnnotation(checker);
2169 funcReturnType = typeAnnotation->GetType(checker);
2170 checker::AssignmentContext(checker->Relation(), arrowFunc, arrowFunc->TsType(), funcReturnType,
2171 stArgument->Start(),
2172 {"Return statement type is not compatible with the enclosing method's return type."},
2173 checker::TypeRelationFlag::DIRECT_RETURN);
2174 }
2175
2176 containingFunc->Signature()->SetReturnType(funcReturnType);
2177 containingFunc->Signature()->RemoveSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE);
2178 checker->VarBinder()->AsETSBinder()->BuildFunctionName(containingFunc);
2179
2180 if (stArgument != nullptr && stArgument->IsObjectExpression()) {
2181 stArgument->AsObjectExpression()->SetPreferredType(funcReturnType);
2182 }
2183 }
2184
ProcessReturnStatements(ETSChecker * checker,ir::ScriptFunction * containingFunc,checker::Type * & funcReturnType,ir::ReturnStatement * st,ir::Expression * stArgument)2185 void ProcessReturnStatements(ETSChecker *checker, ir::ScriptFunction *containingFunc, checker::Type *&funcReturnType,
2186 ir::ReturnStatement *st, ir::Expression *stArgument)
2187 {
2188 funcReturnType = containingFunc->Signature()->ReturnType();
2189
2190 if (stArgument == nullptr) {
2191 // previous return statement(s) have value
2192 if (!funcReturnType->IsETSVoidType() && funcReturnType != checker->GlobalBuiltinVoidType()) {
2193 checker->ThrowTypeError("All return statements in the function should be empty or have a value.",
2194 st->Start());
2195 }
2196 } else {
2197 // previous return statement(s) don't have any value
2198 if (funcReturnType->IsETSVoidType() || funcReturnType == checker->GlobalBuiltinVoidType()) {
2199 checker->ThrowTypeError("All return statements in the function should be empty or have a value.",
2200 stArgument->Start());
2201 }
2202
2203 const auto name = containingFunc->Scope()->InternalName().Mutf8();
2204 if (name.find(compiler::Signatures::ETS_MAIN_WITH_MANGLE_BEGIN) != std::string::npos) {
2205 if (funcReturnType == checker->GlobalBuiltinVoidType()) {
2206 funcReturnType = checker->GlobalVoidType();
2207 } else if (!funcReturnType->IsETSVoidType() && !funcReturnType->IsIntType()) {
2208 checker->ThrowTypeError("Bad return type, main enable only void or int type.", st->Start());
2209 }
2210 }
2211
2212 if (stArgument->IsObjectExpression()) {
2213 stArgument->AsObjectExpression()->SetPreferredType(funcReturnType);
2214 }
2215
2216 if (stArgument->IsMemberExpression()) {
2217 checker->SetArrayPreferredTypeForNestedMemberExpressions(stArgument->AsMemberExpression(), funcReturnType);
2218 }
2219
2220 checker::Type *argumentType = stArgument->Check(checker);
2221 // remove CONSTANT type modifier if exists
2222 if (argumentType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
2223 argumentType =
2224 argumentType->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder());
2225 argumentType->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
2226 }
2227
2228 auto *const relation = checker->Relation();
2229 relation->SetNode(stArgument);
2230
2231 if (!relation->IsIdenticalTo(funcReturnType, argumentType)) {
2232 checker->ResolveReturnStatement(funcReturnType, argumentType, containingFunc, st);
2233 }
2234
2235 relation->SetNode(nullptr);
2236 relation->SetFlags(checker::TypeRelationFlag::NONE);
2237 }
2238 }
2239
GetFunctionReturnType(ir::ReturnStatement * st,ir::ScriptFunction * containingFunc) const2240 checker::Type *ETSAnalyzer::GetFunctionReturnType(ir::ReturnStatement *st, ir::ScriptFunction *containingFunc) const
2241 {
2242 ASSERT(containingFunc->ReturnTypeAnnotation() != nullptr || containingFunc->Signature()->ReturnType() != nullptr);
2243
2244 ETSChecker *checker = GetETSChecker();
2245 checker::Type *funcReturnType = nullptr;
2246
2247 if (auto *const returnTypeAnnotation = containingFunc->ReturnTypeAnnotation(); returnTypeAnnotation != nullptr) {
2248 if (returnTypeAnnotation->IsTSThisType() &&
2249 (st->Argument() == nullptr || !st->Argument()->IsThisExpression())) {
2250 checker->ThrowTypeError(
2251 "The only allowed return value is 'this' if the method's return type is the 'this' type", st->Start());
2252 }
2253
2254 // Case when function's return type is defined explicitly:
2255 funcReturnType = checker->GetTypeFromTypeAnnotation(returnTypeAnnotation);
2256
2257 if (st->argument_ == nullptr) {
2258 if (!funcReturnType->IsETSVoidType() && funcReturnType != checker->GlobalBuiltinVoidType()) {
2259 checker->ThrowTypeError("Missing return value.", st->Start());
2260 }
2261 funcReturnType =
2262 containingFunc->IsEntryPoint() ? checker->GlobalVoidType() : checker->GlobalBuiltinVoidType();
2263 } else {
2264 const auto name = containingFunc->Scope()->InternalName().Mutf8();
2265 CheckArgumentVoidType(funcReturnType, checker, name, st);
2266
2267 if (st->argument_->IsObjectExpression()) {
2268 st->argument_->AsObjectExpression()->SetPreferredType(funcReturnType);
2269 }
2270 if (st->argument_->IsMemberExpression()) {
2271 checker->SetArrayPreferredTypeForNestedMemberExpressions(st->argument_->AsMemberExpression(),
2272 funcReturnType);
2273 }
2274
2275 if (st->argument_->IsArrayExpression()) {
2276 st->argument_->AsArrayExpression()->SetPreferredType(funcReturnType);
2277 }
2278
2279 checker::Type *argumentType = st->argument_->Check(checker);
2280
2281 CheckReturnType(checker, funcReturnType, argumentType, st->argument_);
2282 }
2283 } else {
2284 // Case when function's return type should be inferred from return statement(s):
2285 if (containingFunc->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) {
2286 InferReturnType(checker, containingFunc, funcReturnType, st->argument_);
2287 } else {
2288 // All subsequent return statements:
2289 ProcessReturnStatements(checker, containingFunc, funcReturnType, st, st->argument_);
2290 }
2291 }
2292
2293 if ((st->argument_ != nullptr) && st->argument_->IsArrayExpression()) {
2294 checker->ModifyPreferredType(st->argument_->AsArrayExpression(), funcReturnType);
2295 st->argument_->Check(checker);
2296 }
2297
2298 return funcReturnType;
2299 }
2300
Check(ir::ReturnStatement * st) const2301 checker::Type *ETSAnalyzer::Check(ir::ReturnStatement *st) const
2302 {
2303 ETSChecker *checker = GetETSChecker();
2304
2305 ir::AstNode *ancestor = util::Helpers::FindAncestorGivenByType(st, ir::AstNodeType::SCRIPT_FUNCTION);
2306 ASSERT(ancestor && ancestor->IsScriptFunction());
2307 auto *containingFunc = ancestor->AsScriptFunction();
2308
2309 if (containingFunc->IsConstructor()) {
2310 if (st->argument_ != nullptr) {
2311 checker->ThrowTypeError("Return statement with expression isn't allowed in constructor.", st->Start());
2312 }
2313 return nullptr;
2314 }
2315
2316 st->returnType_ = GetFunctionReturnType(st, containingFunc);
2317 return nullptr;
2318 }
2319
Check(ir::SwitchCaseStatement * st) const2320 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::SwitchCaseStatement *st) const
2321 {
2322 UNREACHABLE();
2323 }
2324
Check(ir::SwitchStatement * st) const2325 checker::Type *ETSAnalyzer::Check(ir::SwitchStatement *st) const
2326 {
2327 ETSChecker *checker = GetETSChecker();
2328 checker::ScopeContext scopeCtx(checker, st->scope_);
2329 st->discriminant_->Check(checker);
2330 checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(checker->Relation(),
2331 checker::TypeRelationFlag::NONE);
2332 // NOTE (user): check exhaustive Switch
2333 checker->CheckSwitchDiscriminant(st->discriminant_);
2334 auto *comparedExprType = st->discriminant_->TsType();
2335 auto unboxedDiscType = (st->Discriminant()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG) != 0U
2336 ? checker->ETSBuiltinTypeAsPrimitiveType(comparedExprType)
2337 : comparedExprType;
2338
2339 bool validCaseType;
2340
2341 for (auto *it : st->Cases()) {
2342 if (it->Test() != nullptr) {
2343 auto *caseType = it->Test()->Check(checker);
2344 validCaseType = true;
2345 if (caseType->HasTypeFlag(checker::TypeFlag::CHAR)) {
2346 validCaseType = comparedExprType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL);
2347 } else if (caseType->IsETSEnumType() && st->Discriminant()->TsType()->IsETSEnumType()) {
2348 validCaseType =
2349 st->Discriminant()->TsType()->AsETSEnumType()->IsSameEnumType(caseType->AsETSEnumType());
2350 } else if (caseType->IsETSStringEnumType() && st->Discriminant()->TsType()->IsETSStringEnumType()) {
2351 validCaseType = st->Discriminant()->TsType()->AsETSStringEnumType()->IsSameEnumType(
2352 caseType->AsETSStringEnumType());
2353 } else {
2354 checker::AssignmentContext(
2355 checker->Relation(), st->discriminant_, caseType, unboxedDiscType, it->Test()->Start(),
2356 {"Switch case type ", caseType, " is not comparable to discriminant type ", comparedExprType},
2357 (comparedExprType->IsETSObjectType() ? checker::TypeRelationFlag::NO_WIDENING
2358 : checker::TypeRelationFlag::NO_UNBOXING) |
2359 checker::TypeRelationFlag::NO_BOXING);
2360 }
2361
2362 if (!validCaseType) {
2363 checker->ThrowTypeError(
2364 {"Switch case type ", caseType, " is not comparable to discriminant type ", comparedExprType},
2365 it->Test()->Start());
2366 }
2367 }
2368
2369 for (auto *caseStmt : it->Consequent()) {
2370 caseStmt->Check(checker);
2371 }
2372 }
2373
2374 checker->CheckForSameSwitchCases(&st->cases_);
2375
2376 return nullptr;
2377 }
2378
Check(ir::ThrowStatement * st) const2379 checker::Type *ETSAnalyzer::Check(ir::ThrowStatement *st) const
2380 {
2381 ETSChecker *checker = GetETSChecker();
2382 auto *argType = st->argument_->Check(checker);
2383 checker->CheckExceptionOrErrorType(argType, st->Start());
2384
2385 if (checker->Relation()->IsAssignableTo(argType, checker->GlobalBuiltinExceptionType())) {
2386 checker->CheckThrowingStatements(st);
2387 }
2388 return nullptr;
2389 }
2390
Check(ir::TryStatement * st) const2391 checker::Type *ETSAnalyzer::Check(ir::TryStatement *st) const
2392 {
2393 ETSChecker *checker = GetETSChecker();
2394 std::vector<checker::ETSObjectType *> exceptions;
2395 st->Block()->Check(checker);
2396
2397 for (auto *catchClause : st->CatchClauses()) {
2398 auto exceptionType = catchClause->Check(checker);
2399 if ((exceptionType != nullptr) && (catchClause->Param() != nullptr)) {
2400 auto *clauseType = exceptionType->AsETSObjectType();
2401
2402 for (auto *exception : exceptions) {
2403 checker->Relation()->IsIdenticalTo(clauseType, exception);
2404 if (checker->Relation()->IsTrue()) {
2405 checker->ThrowTypeError("Redeclaration of exception type", catchClause->Start());
2406 }
2407 }
2408
2409 exceptions.push_back(clauseType);
2410 }
2411 }
2412
2413 bool defaultCatchFound = false;
2414
2415 for (auto *catchClause : st->CatchClauses()) {
2416 if (defaultCatchFound) {
2417 checker->ThrowTypeError("Default catch clause should be the last in the try statement",
2418 catchClause->Start());
2419 }
2420
2421 defaultCatchFound = catchClause->IsDefaultCatchClause();
2422 }
2423
2424 if (st->HasFinalizer()) {
2425 st->finalizer_->Check(checker);
2426 }
2427
2428 return nullptr;
2429 }
2430
Check(ir::VariableDeclarator * st) const2431 checker::Type *ETSAnalyzer::Check(ir::VariableDeclarator *st) const
2432 {
2433 ETSChecker *checker = GetETSChecker();
2434 ASSERT(st->Id()->IsIdentifier());
2435 ir::ModifierFlags flags = ir::ModifierFlags::NONE;
2436
2437 if (st->Id()->Parent()->Parent()->AsVariableDeclaration()->Kind() ==
2438 ir::VariableDeclaration::VariableDeclarationKind::CONST) {
2439 flags |= ir::ModifierFlags::CONST;
2440 }
2441
2442 st->SetTsType(checker->CheckVariableDeclaration(st->Id()->AsIdentifier(),
2443 st->Id()->AsIdentifier()->TypeAnnotation(), st->Init(), flags));
2444 return st->TsType();
2445 }
2446
Check(ir::VariableDeclaration * st) const2447 checker::Type *ETSAnalyzer::Check(ir::VariableDeclaration *st) const
2448 {
2449 ETSChecker *checker = GetETSChecker();
2450 for (auto *it : st->Declarators()) {
2451 it->Check(checker);
2452 }
2453
2454 return nullptr;
2455 }
2456
Check(ir::WhileStatement * st) const2457 checker::Type *ETSAnalyzer::Check(ir::WhileStatement *st) const
2458 {
2459 ETSChecker *checker = GetETSChecker();
2460 checker::ScopeContext scopeCtx(checker, st->Scope());
2461
2462 checker->CheckTruthinessOfType(st->Test());
2463
2464 st->Body()->Check(checker);
2465 return nullptr;
2466 }
2467 // from ts folder
Check(ir::TSAnyKeyword * node) const2468 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSAnyKeyword *node) const
2469 {
2470 UNREACHABLE();
2471 }
2472
Check(ir::TSArrayType * node) const2473 checker::Type *ETSAnalyzer::Check(ir::TSArrayType *node) const
2474 {
2475 ETSChecker *checker = GetETSChecker();
2476 node->elementType_->Check(checker);
2477 return nullptr;
2478 }
2479
Check(ir::TSAsExpression * expr) const2480 checker::Type *ETSAnalyzer::Check(ir::TSAsExpression *expr) const
2481 {
2482 ETSChecker *checker = GetETSChecker();
2483
2484 auto *const targetType = expr->TypeAnnotation()->AsTypeNode()->GetType(checker);
2485 // Object expression requires that its type be set by the context before checking. in this case, the target type
2486 // provides that context.
2487 if (expr->Expr()->IsObjectExpression()) {
2488 expr->Expr()->AsObjectExpression()->SetPreferredType(targetType);
2489 }
2490
2491 if (expr->Expr()->IsArrayExpression()) {
2492 expr->Expr()->AsArrayExpression()->SetPreferredType(targetType);
2493 }
2494
2495 auto *const sourceType = expr->Expr()->Check(checker);
2496
2497 if (targetType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) &&
2498 sourceType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT | checker::TypeFlag::TYPE_PARAMETER)) {
2499 auto *const boxedTargetType = checker->PrimitiveTypeAsETSBuiltinType(targetType);
2500 if (!checker->Relation()->IsIdenticalTo(sourceType, boxedTargetType)) {
2501 expr->Expr()->AddAstNodeFlags(ir::AstNodeFlags::CHECKCAST);
2502 }
2503 }
2504
2505 const checker::CastingContext ctx(checker->Relation(), expr->Expr(), sourceType, targetType, expr->Expr()->Start(),
2506 {"Cannot cast type '", sourceType, "' to '", targetType, "'"});
2507
2508 if (sourceType->IsETSDynamicType() && targetType->IsLambdaObject()) {
2509 // NOTE: itrubachev. change targetType to created lambdaobject type.
2510 // Now targetType is not changed, only construct signature is added to it
2511 checker->BuildLambdaObjectClass(targetType->AsETSObjectType(),
2512 expr->TypeAnnotation()->AsETSFunctionType()->ReturnType());
2513 }
2514 expr->isUncheckedCast_ = ctx.UncheckedCast();
2515
2516 // Make sure the array type symbol gets created for the assembler to be able to emit checkcast.
2517 // Because it might not exist, if this particular array type was never created explicitly.
2518 if (!expr->isUncheckedCast_ && targetType->IsETSArrayType()) {
2519 auto *const targetArrayType = targetType->AsETSArrayType();
2520 checker->CreateBuiltinArraySignature(targetArrayType, targetArrayType->Rank());
2521 }
2522
2523 expr->SetTsType(targetType);
2524 return expr->TsType();
2525 }
2526
Check(ir::TSBigintKeyword * node) const2527 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSBigintKeyword *node) const
2528 {
2529 UNREACHABLE();
2530 }
2531
Check(ir::TSBooleanKeyword * node) const2532 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSBooleanKeyword *node) const
2533 {
2534 UNREACHABLE();
2535 }
2536
Check(ir::TSClassImplements * expr) const2537 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSClassImplements *expr) const
2538 {
2539 UNREACHABLE();
2540 }
2541
Check(ir::TSConditionalType * node) const2542 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSConditionalType *node) const
2543 {
2544 UNREACHABLE();
2545 }
2546
Check(ir::TSConstructorType * node) const2547 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSConstructorType *node) const
2548 {
2549 UNREACHABLE();
2550 }
2551
Check(ir::TSEnumDeclaration * st) const2552 checker::Type *ETSAnalyzer::Check(ir::TSEnumDeclaration *st) const
2553 {
2554 ETSChecker *checker = GetETSChecker();
2555 varbinder::Variable *enumVar = st->Key()->Variable();
2556 ASSERT(enumVar != nullptr);
2557
2558 if (enumVar->TsType() == nullptr) {
2559 checker::Type *etsEnumType;
2560 if (auto *const itemInit = st->Members().front()->AsTSEnumMember()->Init(); itemInit->IsNumberLiteral()) {
2561 etsEnumType = checker->CreateETSEnumType(st);
2562 } else if (itemInit->IsStringLiteral()) {
2563 etsEnumType = checker->CreateETSStringEnumType(st);
2564 } else {
2565 checker->ThrowTypeError("Invalid enumeration value type.", st->Start());
2566 }
2567 st->SetTsType(etsEnumType);
2568 etsEnumType->SetVariable(enumVar);
2569 enumVar->SetTsType(etsEnumType);
2570 } else if (st->TsType() == nullptr) {
2571 st->SetTsType(enumVar->TsType());
2572 }
2573
2574 return st->TsType();
2575 }
2576
Check(ir::TSEnumMember * st) const2577 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSEnumMember *st) const
2578 {
2579 UNREACHABLE();
2580 }
2581
Check(ir::TSExternalModuleReference * expr) const2582 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSExternalModuleReference *expr) const
2583 {
2584 UNREACHABLE();
2585 }
2586
Check(ir::TSFunctionType * node) const2587 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSFunctionType *node) const
2588 {
2589 UNREACHABLE();
2590 }
2591
Check(ir::TSImportEqualsDeclaration * st) const2592 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSImportEqualsDeclaration *st) const
2593 {
2594 UNREACHABLE();
2595 }
2596
Check(ir::TSImportType * node) const2597 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSImportType *node) const
2598 {
2599 UNREACHABLE();
2600 }
2601
Check(ir::TSIndexedAccessType * node) const2602 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSIndexedAccessType *node) const
2603 {
2604 UNREACHABLE();
2605 }
2606
Check(ir::TSInferType * node) const2607 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSInferType *node) const
2608 {
2609 UNREACHABLE();
2610 }
2611
Check(ir::TSInterfaceBody * expr) const2612 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSInterfaceBody *expr) const
2613 {
2614 UNREACHABLE();
2615 }
2616
Check(ir::TSInterfaceDeclaration * st) const2617 checker::Type *ETSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const
2618 {
2619 ETSChecker *checker = GetETSChecker();
2620
2621 checker::ETSObjectType *interfaceType {};
2622
2623 if (st->TsType() == nullptr) {
2624 interfaceType = checker->BuildInterfaceProperties(st);
2625 ASSERT(interfaceType != nullptr);
2626 interfaceType->SetSuperType(checker->GlobalETSObjectType());
2627 checker->CheckInvokeMethodsLegitimacy(interfaceType);
2628 st->SetTsType(interfaceType);
2629 }
2630
2631 checker::ScopeContext scopeCtx(checker, st->Scope());
2632 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_INTERFACE, interfaceType);
2633
2634 for (auto *it : st->Body()->Body()) {
2635 it->Check(checker);
2636 }
2637
2638 return nullptr;
2639 }
2640
Check(ir::TSInterfaceHeritage * expr) const2641 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSInterfaceHeritage *expr) const
2642 {
2643 UNREACHABLE();
2644 }
2645
Check(ir::TSIntersectionType * node) const2646 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSIntersectionType *node) const
2647 {
2648 UNREACHABLE();
2649 }
2650
Check(ir::TSLiteralType * node) const2651 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSLiteralType *node) const
2652 {
2653 UNREACHABLE();
2654 }
2655
Check(ir::TSMappedType * node) const2656 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSMappedType *node) const
2657 {
2658 UNREACHABLE();
2659 }
2660
Check(ir::TSModuleBlock * st) const2661 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSModuleBlock *st) const
2662 {
2663 UNREACHABLE();
2664 }
2665
Check(ir::TSModuleDeclaration * st) const2666 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSModuleDeclaration *st) const
2667 {
2668 UNREACHABLE();
2669 }
2670
Check(ir::TSNamedTupleMember * node) const2671 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNamedTupleMember *node) const
2672 {
2673 UNREACHABLE();
2674 }
2675
Check(ir::TSNeverKeyword * node) const2676 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNeverKeyword *node) const
2677 {
2678 UNREACHABLE();
2679 }
2680
Check(ir::TSNonNullExpression * expr) const2681 checker::Type *ETSAnalyzer::Check(ir::TSNonNullExpression *expr) const
2682 {
2683 ETSChecker *checker = GetETSChecker();
2684 auto exprType = expr->expr_->Check(checker);
2685 if (!checker->MayHaveNulllikeValue(exprType)) {
2686 checker->ThrowTypeError("Bad operand type, the operand of the non-null expression must be a nullable type",
2687 expr->Expr()->Start());
2688 }
2689
2690 expr->SetTsType(exprType->IsNullish() ? checker->GetNonNullishType(exprType) : exprType);
2691 return expr->TsType();
2692 }
2693
Check(ir::TSNullKeyword * node) const2694 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNullKeyword *node) const
2695 {
2696 UNREACHABLE();
2697 }
2698
Check(ir::TSNumberKeyword * node) const2699 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNumberKeyword *node) const
2700 {
2701 UNREACHABLE();
2702 }
2703
Check(ir::TSObjectKeyword * node) const2704 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSObjectKeyword *node) const
2705 {
2706 UNREACHABLE();
2707 }
2708
Check(ir::TSParameterProperty * expr) const2709 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSParameterProperty *expr) const
2710 {
2711 UNREACHABLE();
2712 }
2713
Check(ir::TSParenthesizedType * node) const2714 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSParenthesizedType *node) const
2715 {
2716 UNREACHABLE();
2717 }
2718
Check(ir::TSQualifiedName * expr) const2719 checker::Type *ETSAnalyzer::Check(ir::TSQualifiedName *expr) const
2720 {
2721 ETSChecker *checker = GetETSChecker();
2722 checker::Type *baseType = expr->Left()->Check(checker);
2723 if (baseType->IsETSObjectType()) {
2724 varbinder::Variable *prop =
2725 baseType->AsETSObjectType()->GetProperty(expr->Right()->Name(), checker::PropertySearchFlags::SEARCH_DECL);
2726
2727 if (prop != nullptr) {
2728 return checker->GetTypeOfVariable(prop);
2729 }
2730 }
2731
2732 checker->ThrowTypeError({"'", expr->Right()->Name(), "' type does not exist."}, expr->Right()->Start());
2733 }
2734
Check(ir::TSStringKeyword * node) const2735 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSStringKeyword *node) const
2736 {
2737 UNREACHABLE();
2738 }
2739
Check(ir::TSThisType * node) const2740 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSThisType *node) const
2741 {
2742 UNREACHABLE();
2743 }
2744
Check(ir::TSTupleType * node) const2745 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTupleType *node) const
2746 {
2747 UNREACHABLE();
2748 }
2749
Check(ir::TSTypeAliasDeclaration * st) const2750 checker::Type *ETSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const
2751 {
2752 ETSChecker *checker = GetETSChecker();
2753 if (st->TypeParams() != nullptr) {
2754 st->SetTypeParameterTypes(checker->CreateTypeForTypeParameters(st->TypeParams()));
2755 for (auto *const param : st->TypeParams()->Params()) {
2756 const auto *const res = st->TypeAnnotation()->FindChild([¶m](const ir::AstNode *const node) {
2757 if (!node->IsIdentifier()) {
2758 return false;
2759 }
2760
2761 return param->Name()->AsIdentifier()->Variable() == node->AsIdentifier()->Variable();
2762 });
2763
2764 if (res == nullptr) {
2765 checker->ThrowTypeError(
2766 {"Type alias generic parameter '", param->Name()->Name(), "' is not used in type annotation"},
2767 param->Start());
2768 }
2769 }
2770 }
2771
2772 const checker::SavedTypeRelationFlagsContext savedFlagsCtx(checker->Relation(),
2773 checker::TypeRelationFlag::NO_THROW_GENERIC_TYPEALIAS);
2774
2775 st->TypeAnnotation()->Check(checker);
2776
2777 return nullptr;
2778 }
2779
Check(ir::TSTypeAssertion * expr) const2780 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeAssertion *expr) const
2781 {
2782 UNREACHABLE();
2783 }
2784
Check(ir::TSTypeLiteral * node) const2785 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeLiteral *node) const
2786 {
2787 UNREACHABLE();
2788 }
2789
Check(ir::TSTypeOperator * node) const2790 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeOperator *node) const
2791 {
2792 UNREACHABLE();
2793 }
2794
Check(ir::TSTypeParameter * expr) const2795 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeParameter *expr) const
2796 {
2797 UNREACHABLE();
2798 }
2799
Check(ir::TSTypeParameterDeclaration * expr) const2800 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeParameterDeclaration *expr) const
2801 {
2802 UNREACHABLE();
2803 }
2804
Check(ir::TSTypeParameterInstantiation * expr) const2805 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeParameterInstantiation *expr) const
2806 {
2807 UNREACHABLE();
2808 }
2809
Check(ir::TSTypePredicate * node) const2810 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypePredicate *node) const
2811 {
2812 UNREACHABLE();
2813 }
2814
Check(ir::TSTypeQuery * node) const2815 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeQuery *node) const
2816 {
2817 UNREACHABLE();
2818 }
2819
Check(ir::TSTypeReference * node) const2820 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeReference *node) const
2821 {
2822 UNREACHABLE();
2823 }
2824
Check(ir::TSUndefinedKeyword * node) const2825 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSUndefinedKeyword *node) const
2826 {
2827 UNREACHABLE();
2828 }
2829
Check(ir::TSUnionType * node) const2830 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSUnionType *node) const
2831 {
2832 UNREACHABLE();
2833 }
2834
Check(ir::TSUnknownKeyword * node) const2835 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSUnknownKeyword *node) const
2836 {
2837 UNREACHABLE();
2838 }
2839
Check(ir::TSVoidKeyword * node) const2840 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSVoidKeyword *node) const
2841 {
2842 UNREACHABLE();
2843 }
2844
2845 } // namespace panda::es2panda::checker
2846