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 "utils/logger.h"
17 #include "varbinder/ETSBinder.h"
18 #include "checker/ETSchecker.h"
19 #include "checker/ets/castingContext.h"
20 #include "checker/ets/function_helpers.h"
21 #include "checker/ets/typeRelationContext.h"
22 #include "checker/types/ets/etsAsyncFuncReturnType.h"
23 #include "checker/types/ets/etsObjectType.h"
24 #include "ir/base/catchClause.h"
25 #include "ir/base/classDefinition.h"
26 #include "ir/base/classProperty.h"
27 #include "ir/base/methodDefinition.h"
28 #include "ir/base/scriptFunction.h"
29 #include "ir/base/spreadElement.h"
30 #include "ir/ets/etsFunctionType.h"
31 #include "ir/ets/etsParameterExpression.h"
32 #include "ir/ets/etsTypeReference.h"
33 #include "ir/ets/etsTypeReferencePart.h"
34 #include "ir/ets/etsUnionType.h"
35 #include "ir/expressions/arrowFunctionExpression.h"
36 #include "ir/expressions/assignmentExpression.h"
37 #include "ir/expressions/callExpression.h"
38 #include "ir/expressions/functionExpression.h"
39 #include "ir/expressions/identifier.h"
40 #include "ir/expressions/literals/numberLiteral.h"
41 #include "ir/expressions/literals/undefinedLiteral.h"
42 #include "ir/expressions/memberExpression.h"
43 #include "ir/expressions/objectExpression.h"
44 #include "ir/expressions/thisExpression.h"
45 #include "ir/statements/blockStatement.h"
46 #include "ir/statements/doWhileStatement.h"
47 #include "ir/statements/expressionStatement.h"
48 #include "ir/statements/forInStatement.h"
49 #include "ir/statements/forOfStatement.h"
50 #include "ir/statements/forUpdateStatement.h"
51 #include "ir/statements/returnStatement.h"
52 #include "ir/statements/switchStatement.h"
53 #include "ir/statements/whileStatement.h"
54 #include "ir/ts/tsTypeAliasDeclaration.h"
55 #include "ir/ts/tsTypeParameter.h"
56 #include "ir/ts/tsTypeParameterInstantiation.h"
57 #include "parser/program/program.h"
58 #include "util/helpers.h"
59 #include "util/language.h"
60 
61 namespace ark::es2panda::checker {
62 
63 // NOTE: #14993 merge with InstantiationContext::ValidateTypeArg
IsCompatibleTypeArgument(ETSTypeParameter *typeParam, Type *typeArgument, const Substitution *substitution)64 bool ETSChecker::IsCompatibleTypeArgument(ETSTypeParameter *typeParam, Type *typeArgument,
65                                           const Substitution *substitution)
66 {
67     if (typeArgument->IsWildcardType()) {
68         return true;
69     }
70     ASSERT(IsReferenceType(typeArgument) || typeArgument->IsETSVoidType());
71     auto *constraint = typeParam->GetConstraintType()->Substitute(Relation(), substitution);
72     bool retVal = false;
73     if (typeArgument->IsETSVoidType()) {
74         retVal = Relation()->IsSupertypeOf(constraint, GlobalETSUndefinedType());
75     } else if (typeArgument->IsETSFunctionType()) {
76         retVal = Relation()->IsSupertypeOf(
77             constraint,
78             this->FunctionTypeToFunctionalInterfaceType(typeArgument->AsETSFunctionType()->CallSignatures().front()));
79     } else {
80         retVal = Relation()->IsSupertypeOf(constraint, typeArgument);
81     }
82 
83     return retVal;
84 }
85 
HasTypeArgsOfObject(Type *argType, Type *paramType)86 bool ETSChecker::HasTypeArgsOfObject(Type *argType, Type *paramType)
87 {
88     return paramType->IsETSObjectType() && argType->IsETSObjectType() &&
89            !argType->AsETSObjectType()->TypeArguments().empty() &&
90            !paramType->AsETSObjectType()->TypeArguments().empty();
91 }
92 
InsertTypeIntoSubstitution(const ArenaVector<Type *> &typeParams, const Type *typeParam, const size_t index, Substitution *substitution, Type *objectParam)93 bool ETSChecker::InsertTypeIntoSubstitution(const ArenaVector<Type *> &typeParams, const Type *typeParam,
94                                             const size_t index, Substitution *substitution, Type *objectParam)
95 {
96     // Check if the type parameter is in the signature, and the type argument is not already in the return vector
97     if (typeParams.size() > index &&
98         IsCompatibleTypeArgument(typeParams[index]->AsETSTypeParameter(), objectParam, substitution) &&
99         std::find(typeParams.begin(), typeParams.end(), typeParam) != typeParams.end()) {
100         substitution->emplace(typeParams[index]->AsETSTypeParameter(), objectParam);
101         return true;
102     }
103 
104     return false;
105 }
106 
EnhanceSubstitutionForGenericType(const ArenaVector<Type *> &typeParams, const Type *argType, const Type *paramType, Substitution *substitution)107 bool ETSChecker::EnhanceSubstitutionForGenericType(const ArenaVector<Type *> &typeParams, const Type *argType,
108                                                    const Type *paramType, Substitution *substitution)
109 {
110     ArenaVector<Type *> objectParams(Allocator()->Adapter());
111 
112     if (!argType->AsETSObjectType()->GetDeclNode()->IsClassDefinition()) {
113         return false;
114     }
115 
116     const auto paramTypeArgs = paramType->AsETSObjectType()->TypeArguments();
117 
118     for (const auto it : typeParams) {
119         bool found = false;
120 
121         for (size_t i = 0; i < paramTypeArgs.size() && !found; i++) {
122             if (paramTypeArgs[i] == it) {
123                 objectParams.push_back(argType->AsETSObjectType()->TypeArguments()[i]);
124                 found = true;
125             }
126         }
127 
128         if (!found) {
129             objectParams.push_back(nullptr);
130         }
131     }
132 
133     if (objectParams.size() < paramTypeArgs.size()) {
134         return false;
135     }
136 
137     bool res = true;
138     for (size_t j = 0; j < paramTypeArgs.size() && res; ++j) {
139         if (objectParams[j] != nullptr) {
140             res = InsertTypeIntoSubstitution(typeParams, paramTypeArgs[j], j, substitution, objectParams[j]);
141         } else {
142             res = EnhanceSubstitutionForType(typeParams, paramTypeArgs[j],
143                                              argType->AsETSObjectType()->TypeArguments()[j], substitution);
144         }
145     }
146 
147     return res;
148 }
149 
EnhanceSubstitutionForReadonly(const ArenaVector<Type *> &typeParams, ETSReadonlyType *paramType, Type *argumentType, Substitution *substitution)150 bool ETSChecker::EnhanceSubstitutionForReadonly(const ArenaVector<Type *> &typeParams, ETSReadonlyType *paramType,
151                                                 Type *argumentType, Substitution *substitution)
152 {
153     return EnhanceSubstitutionForType(typeParams, paramType->GetUnderlying(), GetReadonlyType(argumentType),
154                                       substitution);
155 }
156 
157 /* A very rough and imprecise partial type inference */
EnhanceSubstitutionForType(const ArenaVector<Type *> &typeParams, Type *paramType, Type *argumentType, Substitution *substitution)158 bool ETSChecker::EnhanceSubstitutionForType(const ArenaVector<Type *> &typeParams, Type *paramType, Type *argumentType,
159                                             Substitution *substitution)
160 {
161     if (argumentType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
162         argumentType = PrimitiveTypeAsETSBuiltinType(argumentType);
163     }
164     if (paramType->IsETSTypeParameter()) {
165         auto *const tparam = paramType->AsETSTypeParameter();
166         auto *const originalTparam = tparam->GetOriginal();
167         if (std::find(typeParams.begin(), typeParams.end(), originalTparam) != typeParams.end() &&
168             substitution->count(originalTparam) == 0) {
169             if (!IsReferenceType(argumentType)) {
170                 LogTypeError({argumentType, " is not compatible with type ", tparam}, tparam->GetDeclNode()->Start());
171                 return false;
172             }
173 
174             ETSChecker::EmplaceSubstituted(substitution, originalTparam, argumentType);
175             return IsCompatibleTypeArgument(tparam, argumentType, substitution);
176         }
177     }
178 
179     if (paramType->IsETSReadonlyType()) {
180         return EnhanceSubstitutionForReadonly(typeParams, paramType->AsETSReadonlyType(), argumentType, substitution);
181     }
182     if (paramType->IsETSUnionType()) {
183         return EnhanceSubstitutionForUnion(typeParams, paramType->AsETSUnionType(), argumentType, substitution);
184     }
185     if (paramType->IsETSObjectType()) {
186         if (HasTypeArgsOfObject(argumentType, paramType) &&
187             EnhanceSubstitutionForGenericType(typeParams, argumentType, paramType, substitution)) {
188             return true;
189         }
190         return EnhanceSubstitutionForObject(typeParams, paramType->AsETSObjectType(), argumentType, substitution);
191     }
192     if (paramType->IsETSArrayType()) {
193         return EnhanceSubstitutionForArray(typeParams, paramType->AsETSArrayType(), argumentType, substitution);
194     }
195 
196     return true;
197 }
198 
EnhanceSubstitutionForUnion(const ArenaVector<Type *> &typeParams, ETSUnionType *paramUn, Type *argumentType, Substitution *substitution)199 bool ETSChecker::EnhanceSubstitutionForUnion(const ArenaVector<Type *> &typeParams, ETSUnionType *paramUn,
200                                              Type *argumentType, Substitution *substitution)
201 {
202     if (!argumentType->IsETSUnionType()) {
203         return std::any_of(
204             paramUn->ConstituentTypes().begin(), paramUn->ConstituentTypes().end(),
205             [this, typeParams, argumentType, substitution](Type *ctype) {
206                 return EnhanceSubstitutionForType(typeParams, ctype, argumentType, substitution) &&
207                        (!ctype->IsETSTypeParameter() ||
208                         (substitution->find(ctype->AsETSTypeParameter()) != substitution->end() &&
209                          Relation()->IsAssignableTo(argumentType, substitution->at(ctype->AsETSTypeParameter()))));
210             });
211     }
212     auto *const argUn = argumentType->AsETSUnionType();
213 
214     ArenaVector<Type *> paramWlist(Allocator()->Adapter());
215     ArenaVector<Type *> argWlist(Allocator()->Adapter());
216 
217     for (auto *pc : paramUn->ConstituentTypes()) {
218         for (auto *ac : argUn->ConstituentTypes()) {
219             if (ETSChecker::GetOriginalBaseType(pc) != ETSChecker::GetOriginalBaseType(ac)) {
220                 paramWlist.push_back(pc);
221                 argWlist.push_back(ac);
222                 continue;
223             }
224             if (!EnhanceSubstitutionForType(typeParams, pc, ac, substitution)) {
225                 return false;
226             }
227         }
228     }
229     auto *const newArg = CreateETSUnionType(std::move(argWlist));
230 
231     for (auto *pc : paramWlist) {
232         if (!EnhanceSubstitutionForType(typeParams, pc, newArg, substitution)) {
233             return false;
234         }
235     }
236     return true;
237 }
238 
EnhanceSubstitutionForObject(const ArenaVector<Type *> &typeParams, ETSObjectType *paramType, Type *argumentType, Substitution *substitution)239 bool ETSChecker::EnhanceSubstitutionForObject(const ArenaVector<Type *> &typeParams, ETSObjectType *paramType,
240                                               Type *argumentType, Substitution *substitution)
241 {
242     auto *paramObjType = paramType->AsETSObjectType();
243 
244     auto const enhance = [this, typeParams, substitution](Type *ptype, Type *atype) {
245         return EnhanceSubstitutionForType(typeParams, ptype, atype, substitution);
246     };
247 
248     if (argumentType->IsETSObjectType()) {
249         auto *argObjType = argumentType->AsETSObjectType();
250         if (GetOriginalBaseType(argObjType) != GetOriginalBaseType(paramObjType)) {
251             return true;  // don't attempt anything fancy for now
252         }
253         bool res = true;
254         for (size_t i = 0; i < argObjType->TypeArguments().size(); i++) {
255             res &= enhance(paramObjType->TypeArguments()[i], argObjType->TypeArguments()[i]);
256         }
257         return res;
258     }
259 
260     if (argumentType->IsETSFunctionType() && paramObjType->HasObjectFlag(ETSObjectFlags::FUNCTIONAL_INTERFACE)) {
261         auto &parameterSignatures =
262             paramObjType
263                 ->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME)
264                 ->TsType()
265                 ->AsETSFunctionType()
266                 ->CallSignatures();
267         auto &argumentSignatures = argumentType->AsETSFunctionType()->CallSignatures();
268         ASSERT(argumentSignatures.size() == 1);
269         ASSERT(parameterSignatures.size() == 1);
270         auto *argumentSignature = argumentSignatures[0];
271         auto *parameterSignature = parameterSignatures[0];
272         // NOTE(gogabr): handle rest parameter for argumentSignature
273         if (parameterSignature->GetSignatureInfo()->params.size() !=
274             argumentSignature->GetSignatureInfo()->params.size()) {
275             return false;
276         }
277         bool res = true;
278         for (size_t idx = 0; idx < argumentSignature->GetSignatureInfo()->params.size(); idx++) {
279             res &= enhance(parameterSignature->GetSignatureInfo()->params[idx]->TsType(),
280                            argumentSignature->GetSignatureInfo()->params[idx]->TsType());
281         }
282         res &= enhance(parameterSignature->ReturnType(), argumentSignature->ReturnType());
283         return res;
284     }
285 
286     return true;
287 }
288 
EnhanceSubstitutionForArray(const ArenaVector<Type *> &typeParams, ETSArrayType *const paramType, Type *const argumentType, Substitution *const substitution)289 bool ETSChecker::EnhanceSubstitutionForArray(const ArenaVector<Type *> &typeParams, ETSArrayType *const paramType,
290                                              Type *const argumentType, Substitution *const substitution)
291 {
292     auto *const elementType =
293         argumentType->IsETSArrayType() ? argumentType->AsETSArrayType()->ElementType() : argumentType;
294 
295     return EnhanceSubstitutionForType(typeParams, paramType->ElementType(), elementType, substitution);
296 }
297 
ValidateParameterlessConstructor(Signature *signature, const lexer::SourcePosition &pos, TypeRelationFlag flags)298 Signature *ETSChecker::ValidateParameterlessConstructor(Signature *signature, const lexer::SourcePosition &pos,
299                                                         TypeRelationFlag flags)
300 {
301     std::size_t const parameterCount = signature->MinArgCount();
302     auto const reportError = (flags & TypeRelationFlag::NO_THROW) == 0;
303 
304     if (parameterCount != 0) {
305         if (reportError) {
306             LogTypeError({"No Matching Parameterless Constructor, parameter count ", parameterCount}, pos);
307         }
308         return nullptr;
309     }
310     return signature;
311 }
312 
CheckOptionalLambdaFunction(ir::Expression *argument, Signature *substitutedSig, std::size_t index)313 bool ETSChecker::CheckOptionalLambdaFunction(ir::Expression *argument, Signature *substitutedSig, std::size_t index)
314 {
315     if (argument->IsArrowFunctionExpression()) {
316         auto *const arrowFuncExpr = argument->AsArrowFunctionExpression();
317 
318         if (ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
319             CheckLambdaAssignable(substitutedSig->Function()->Params()[index], lambda)) {
320             if (arrowFuncExpr->TsTypeOrError() != nullptr) {
321                 arrowFuncExpr->Check(this);
322                 return true;
323             }
324         }
325     }
326 
327     return false;
328 }
329 
ValidateArgumentAsIdentifier(const ir::Identifier *identifier)330 bool ETSChecker::ValidateArgumentAsIdentifier(const ir::Identifier *identifier)
331 {
332     auto result = Scope()->Find(identifier->Name());
333     return result.variable != nullptr && (result.variable->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE));
334 }
335 
ValidateSignatureRequiredParams(Signature *substitutedSig, const ArenaVector<ir::Expression *> &arguments, TypeRelationFlag flags, const std::vector<bool> &argTypeInferenceRequired, bool reportError)336 bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig,
337                                                  const ArenaVector<ir::Expression *> &arguments, TypeRelationFlag flags,
338                                                  const std::vector<bool> &argTypeInferenceRequired, bool reportError)
339 {
340     std::size_t const argumentCount = arguments.size();
341     std::size_t const parameterCount = substitutedSig->MinArgCount();
342     auto count = std::min(parameterCount, argumentCount);
343     for (std::size_t index = 0; index < count; ++index) {
344         auto &argument = arguments[index];
345 
346         if (argument->IsObjectExpression()) {
347             if (substitutedSig->Params()[index]->TsType()->IsETSObjectType()) {
348                 // No chance to check the argument at this point
349                 continue;
350             }
351             return false;
352         }
353 
354         if (argument->IsMemberExpression()) {
355             SetArrayPreferredTypeForNestedMemberExpressions(arguments[index]->AsMemberExpression(),
356                                                             substitutedSig->Params()[index]->TsType());
357         } else if (argument->IsSpreadElement()) {
358             if (reportError) {
359                 LogTypeError("Spread argument cannot be passed for ordinary parameter.", argument->Start());
360             }
361             return false;
362         }
363 
364         if (argTypeInferenceRequired[index]) {
365             ASSERT(argument->IsArrowFunctionExpression());
366             auto *const arrowFuncExpr = argument->AsArrowFunctionExpression();
367             ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
368             if (CheckLambdaAssignable(substitutedSig->Function()->Params()[index], lambda)) {
369                 continue;
370             }
371             return false;
372         }
373 
374         if (argument->IsArrayExpression()) {
375             argument->AsArrayExpression()->GetPrefferedTypeFromFuncParam(
376                 this, substitutedSig->Function()->Params()[index], flags);
377         }
378 
379         if (!CheckInvokable(substitutedSig, argument, index, flags)) {
380             return false;
381         }
382 
383         if (argument->IsIdentifier() && ValidateArgumentAsIdentifier(argument->AsIdentifier())) {
384             LogTypeError("Class name can't be the argument of function or method.", argument->Start());
385             return false;
386         }
387 
388         // clang-format off
389         if (!ValidateSignatureInvocationContext(
390             substitutedSig, argument,
391             TryGettingFunctionTypeFromInvokeFunction(substitutedSig->Params()[index]->TsType()), index, flags)) {
392             // clang-format on
393             return false;
394         }
395     }
396 
397     return true;
398 }
399 
CheckInvokable(Signature *substitutedSig, ir::Expression *argument, std::size_t index, TypeRelationFlag flags)400 bool ETSChecker::CheckInvokable(Signature *substitutedSig, ir::Expression *argument, std::size_t index,
401                                 TypeRelationFlag flags)
402 {
403     auto *argumentType = argument->Check(this);
404     auto *targetType = substitutedSig->Params()[index]->TsType();
405 
406     auto const invocationCtx =
407         checker::InvocationContext(Relation(), argument, argumentType, targetType, argument->Start(),
408                                    {"Type '", argumentType, "' is not compatible with type '",
409                                     TryGettingFunctionTypeFromInvokeFunction(targetType), "' at index ", index + 1},
410                                    flags);
411     return invocationCtx.IsInvocable() || CheckOptionalLambdaFunction(argument, substitutedSig, index);
412 }
413 
ValidateSignatureInvocationContext(Signature *substitutedSig, ir::Expression *argument, const Type *targetType, std::size_t index, TypeRelationFlag flags)414 bool ETSChecker::ValidateSignatureInvocationContext(Signature *substitutedSig, ir::Expression *argument,
415                                                     const Type *targetType, std::size_t index, TypeRelationFlag flags)
416 {
417     Type *argumentType = argument->Check(this);
418     auto const invocationCtx = checker::InvocationContext(
419         Relation(), argument, argumentType, substitutedSig->Params()[index]->TsType(), argument->Start(),
420         {"Type '", argumentType, "' is not compatible with type '", targetType, "' at index ", index + 1}, flags);
421     if (!invocationCtx.IsInvocable()) {
422         return CheckOptionalLambdaFunction(argument, substitutedSig, index);
423     }
424 
425     return true;
426 }
427 
ValidateSignatureRestParams(Signature *substitutedSig, const ArenaVector<ir::Expression *> &arguments, TypeRelationFlag flags, bool reportError)428 bool ETSChecker::ValidateSignatureRestParams(Signature *substitutedSig, const ArenaVector<ir::Expression *> &arguments,
429                                              TypeRelationFlag flags, bool reportError)
430 {
431     std::size_t const argumentCount = arguments.size();
432     std::size_t const parameterCount = substitutedSig->MinArgCount();
433     auto count = std::min(parameterCount, argumentCount);
434     auto const restCount = argumentCount - count;
435 
436     for (std::size_t index = count; index < argumentCount; ++index) {
437         auto &argument = arguments[index];
438 
439         if (!argument->IsSpreadElement()) {
440             auto *const argumentType = argument->Check(this);
441             const Type *targetType = TryGettingFunctionTypeFromInvokeFunction(
442                 substitutedSig->RestVar()->TsType()->AsETSArrayType()->ElementType());
443             const Type *sourceType = TryGettingFunctionTypeFromInvokeFunction(argumentType);
444             auto const invocationCtx = checker::InvocationContext(
445                 Relation(), argument, argumentType,
446                 substitutedSig->RestVar()->TsType()->AsETSArrayType()->ElementType(), argument->Start(),
447                 {"Type '", sourceType, "' is not compatible with rest parameter type '", targetType, "' at index ",
448                  index + 1},
449                 flags);
450             if (!invocationCtx.IsInvocable()) {
451                 return false;
452             }
453             continue;
454         }
455 
456         if (restCount > 1U) {
457             if (reportError) {
458                 LogTypeError("Spread argument for the rest parameter can be only one.", argument->Start());
459             }
460             return false;
461         }
462 
463         auto *const restArgument = argument->AsSpreadElement()->Argument();
464         auto *const argumentType = restArgument->Check(this);
465         const Type *targetType = TryGettingFunctionTypeFromInvokeFunction(substitutedSig->RestVar()->TsType());
466         const Type *sourceType = TryGettingFunctionTypeFromInvokeFunction(argumentType);
467 
468         auto const invocationCtx = checker::InvocationContext(
469             Relation(), restArgument, argumentType, substitutedSig->RestVar()->TsType(), argument->Start(),
470             {"Type '", sourceType, "' is not compatible with rest parameter type '", targetType, "' at index ",
471              index + 1},
472             flags);
473         if (!invocationCtx.IsInvocable()) {
474             return false;
475         }
476     }
477 
478     return true;
479 }
480 
MaybeSubstituteLambdaArgumentsInFunctionCall(ir::CallExpression *callExpr)481 void ETSChecker::MaybeSubstituteLambdaArgumentsInFunctionCall(ir::CallExpression *callExpr)
482 {
483     ir::AstNode *expr = callExpr;
484 
485     while (!expr->IsFunctionExpression()) {
486         if (expr->Parent() == nullptr || expr->Parent()->IsClassDefinition()) {
487             return;
488         }
489         expr = expr->Parent();
490     }
491 
492     for (const auto it : expr->AsFunctionExpression()->Function()->Params()) {
493         if (const auto ident = it->AsETSParameterExpression()->Ident();
494             callExpr->Callee()->IsIdentifier() && ident->Name() == callExpr->Callee()->AsIdentifier()->Name() &&
495             ident->IsAnnotatedExpression()) {
496             if (ident->AsAnnotatedExpression()->TypeAnnotation()->IsETSFunctionType()) {
497                 MaybeSubstituteLambdaArguments(
498                     ident->AsAnnotatedExpression()->TypeAnnotation()->AsETSFunctionType()->Params(), callExpr);
499             }
500         }
501     }
502 }
503 
MaybeSubstituteLambdaArgumentsInFunctionCallHelper(ir::CallExpression *callExpr, ir::Identifier *ident)504 void ETSChecker::MaybeSubstituteLambdaArgumentsInFunctionCallHelper(ir::CallExpression *callExpr, ir::Identifier *ident)
505 {
506     ir::ETSFunctionType *funcType = nullptr;
507     ir::TypeNode *typeAnnotation = ident->TypeAnnotation();
508 
509     if (typeAnnotation->IsETSTypeReference()) {
510         auto typeAnnotationIdentifier = ident->TypeAnnotation()->AsETSTypeReference()->Part()->Name()->Variable();
511         typeAnnotation = typeAnnotationIdentifier->Declaration()->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation();
512     }
513 
514     if (typeAnnotation->IsETSFunctionType()) {
515         funcType = typeAnnotation->AsETSFunctionType();
516     } else if (typeAnnotation->IsETSUnionType()) {
517         auto found = std::find_if(typeAnnotation->AsETSUnionType()->Types().begin(),
518                                   typeAnnotation->AsETSUnionType()->Types().end(),
519                                   [](ir::TypeNode *const type) { return type->IsETSFunctionType(); });
520         if (found != typeAnnotation->AsETSUnionType()->Types().end()) {
521             funcType = (*found)->AsETSFunctionType();
522         }
523     }
524 
525     if (funcType == nullptr) {
526         return;
527     }
528 
529     MaybeSubstituteLambdaArguments(funcType->AsETSFunctionType()->Params(), callExpr);
530 }
531 
MaybeSubstituteLambdaArguments(const ArenaVector<ir::Expression *> &params, ir::CallExpression *callExpr)532 void ETSChecker::MaybeSubstituteLambdaArguments(const ArenaVector<ir::Expression *> &params,
533                                                 ir::CallExpression *callExpr)
534 {
535     for (size_t i = 0; i < params.size(); i++) {
536         if (params[i]->AsETSParameterExpression()->IsDefault() && callExpr->Arguments().size() <= i &&
537             params[i]->AsETSParameterExpression()->Initializer() != nullptr) {
538             callExpr->Arguments().push_back(
539                 params[i]->AsETSParameterExpression()->Initializer()->Clone(Allocator(), callExpr)->AsExpression());
540         }
541     }
542 }
543 
ValidateSignature( std::tuple<Signature *, const ir::TSTypeParameterInstantiation *, TypeRelationFlag> info, const ArenaVector<ir::Expression *> &arguments, const lexer::SourcePosition &pos, const std::vector<bool> &argTypeInferenceRequired)544 Signature *ETSChecker::ValidateSignature(
545     std::tuple<Signature *, const ir::TSTypeParameterInstantiation *, TypeRelationFlag> info,
546     const ArenaVector<ir::Expression *> &arguments, const lexer::SourcePosition &pos,
547     const std::vector<bool> &argTypeInferenceRequired)
548 {
549     auto [signature, typeArguments, flags] = info;
550     Signature *substitutedSig = MaybeSubstituteTypeParameters(this, signature, typeArguments, arguments, pos, flags);
551     if (substitutedSig == nullptr) {
552         return nullptr;
553     }
554 
555     fflush(stdout);
556 
557     auto const hasRestParameter = substitutedSig->RestVar() != nullptr;
558     std::size_t const argumentCount = arguments.size();
559     std::size_t const parameterCount = substitutedSig->MinArgCount();
560     auto const reportError = (flags & TypeRelationFlag::NO_THROW) == 0;
561 
562     if (argumentCount < parameterCount || (argumentCount > parameterCount && !hasRestParameter)) {
563         if (reportError) {
564             LogTypeError({"Expected ", parameterCount, " arguments, got ", argumentCount, "."}, pos);
565         }
566         return nullptr;
567     }
568 
569     if (argumentCount > parameterCount && hasRestParameter && (flags & TypeRelationFlag::IGNORE_REST_PARAM) != 0) {
570         return nullptr;
571     }
572 
573     auto count = std::min(parameterCount, argumentCount);
574     // Check all required formal parameter(s) first
575     if (!ValidateSignatureRequiredParams(substitutedSig, arguments, flags, argTypeInferenceRequired, reportError)) {
576         return nullptr;
577     }
578 
579     // Check rest parameter(s) if any exists
580     if (!hasRestParameter || count >= argumentCount) {
581         return substitutedSig;
582     }
583     if (!ValidateSignatureRestParams(substitutedSig, arguments, flags, reportError)) {
584         return nullptr;
585     }
586 
587     return substitutedSig;
588 }
589 
CollectParameterlessConstructor(ArenaVector<Signature *> &signatures, const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)590 Signature *ETSChecker::CollectParameterlessConstructor(ArenaVector<Signature *> &signatures,
591                                                        const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
592 {
593     Signature *compatibleSignature = nullptr;
594 
595     auto collectSignatures = [&](TypeRelationFlag relationFlags) {
596         for (auto *sig : signatures) {
597             if (auto *concreteSig = ValidateParameterlessConstructor(sig, pos, relationFlags); concreteSig != nullptr) {
598                 compatibleSignature = concreteSig;
599                 break;
600             }
601         }
602     };
603 
604     // We are able to provide more specific error messages.
605     if (signatures.size() == 1) {
606         collectSignatures(resolveFlags);
607     } else {
608         collectSignatures(resolveFlags | TypeRelationFlag::NO_THROW);
609     }
610 
611     if (compatibleSignature == nullptr) {
612         if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0) {
613             LogTypeError({"No matching parameterless constructor"}, pos);
614         }
615     }
616     return compatibleSignature;
617 }
618 
IsSignatureAccessible(Signature *sig, ETSObjectType *containingClass, TypeRelation *relation)619 bool IsSignatureAccessible(Signature *sig, ETSObjectType *containingClass, TypeRelation *relation)
620 {
621     // NOTE(vivienvoros): this check can be removed if signature is implicitly declared as public according to the spec.
622     if (!sig->HasSignatureFlag(SignatureFlags::PUBLIC | SignatureFlags::PROTECTED | SignatureFlags::PRIVATE |
623                                SignatureFlags::INTERNAL)) {
624         return true;
625     }
626 
627     // NOTE(vivienvoros): take care of SignatureFlags::INTERNAL and SignatureFlags::INTERNAL_PROTECTED
628     if (sig->HasSignatureFlag(SignatureFlags::INTERNAL) && !sig->HasSignatureFlag(SignatureFlags::PROTECTED)) {
629         return true;
630     }
631 
632     if (sig->HasSignatureFlag(SignatureFlags::PUBLIC) || sig->Owner() == containingClass ||
633         (sig->HasSignatureFlag(SignatureFlags::PROTECTED) && relation->IsSupertypeOf(sig->Owner(), containingClass))) {
634         return true;
635     }
636 
637     return false;
638 }
639 
640 // NOLINTNEXTLINE(readability-magic-numbers)
GetFlagVariants()641 std::array<TypeRelationFlag, 9U> GetFlagVariants()
642 {
643     // NOTE(boglarkahaag): Not in sync with specification, but solves the issues with rest params for now (#17483)
644     return {
645         TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_BOXING |
646             TypeRelationFlag::IGNORE_REST_PARAM,
647         TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_BOXING,
648         TypeRelationFlag::NO_THROW | TypeRelationFlag::IGNORE_REST_PARAM,
649         TypeRelationFlag::NO_THROW,
650         TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING | TypeRelationFlag::NO_UNBOXING |
651             TypeRelationFlag::NO_BOXING | TypeRelationFlag::IGNORE_REST_PARAM,
652         TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING | TypeRelationFlag::NO_UNBOXING |
653             TypeRelationFlag::NO_BOXING,
654         TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING | TypeRelationFlag::IGNORE_REST_PARAM,
655         TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING,
656         TypeRelationFlag::NO_THROW | TypeRelationFlag::STRING_TO_CHAR,
657     };
658 }
CollectSignatures(ArenaVector<Signature *> &signatures, const ir::TSTypeParameterInstantiation *typeArguments, const ArenaVector<ir::Expression *> &arguments, const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)659 ArenaVector<Signature *> ETSChecker::CollectSignatures(ArenaVector<Signature *> &signatures,
660                                                        const ir::TSTypeParameterInstantiation *typeArguments,
661                                                        const ArenaVector<ir::Expression *> &arguments,
662                                                        const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
663 {
664     ArenaVector<Signature *> compatibleSignatures(Allocator()->Adapter());
665     std::vector<bool> argTypeInferenceRequired = FindTypeInferenceArguments(arguments);
666     Signature *notVisibleSignature = nullptr;
667 
668     auto collectSignatures = [&](TypeRelationFlag relationFlags) {
669         for (auto *sig : signatures) {
670             if (notVisibleSignature != nullptr &&
671                 !IsSignatureAccessible(sig, Context().ContainingClass(), Relation())) {
672                 continue;
673             }
674             auto *concreteSig = ValidateSignature(std::make_tuple(sig, typeArguments, relationFlags), arguments, pos,
675                                                   argTypeInferenceRequired);
676             if (concreteSig == nullptr) {
677                 continue;
678             }
679             if (notVisibleSignature == nullptr &&
680                 !IsSignatureAccessible(sig, Context().ContainingClass(), Relation())) {
681                 notVisibleSignature = concreteSig;
682             } else {
683                 compatibleSignatures.push_back(concreteSig);
684             }
685         }
686     };
687 
688     // If there's only one signature, we don't need special checks for boxing/unboxing/widening.
689     // We are also able to provide more specific error messages.
690     if (signatures.size() == 1) {
691         TypeRelationFlag flags = TypeRelationFlag::WIDENING | TypeRelationFlag::STRING_TO_CHAR | resolveFlags;
692         collectSignatures(flags);
693     } else {
694         for (auto flags : GetFlagVariants()) {
695             flags = flags | resolveFlags;
696             collectSignatures(flags);
697             if (!compatibleSignatures.empty()) {
698                 break;
699             }
700         }
701     }
702 
703     if (compatibleSignatures.empty() && notVisibleSignature != nullptr) {
704         LogTypeError(
705             {"Signature ", notVisibleSignature->Function()->Id()->Name(), notVisibleSignature, " is not visible here."},
706             pos);
707     }
708     return compatibleSignatures;
709 }
710 
GetMostSpecificSignature(ArenaVector<Signature *> &compatibleSignatures, const ArenaVector<ir::Expression *> &arguments, const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)711 Signature *ETSChecker::GetMostSpecificSignature(ArenaVector<Signature *> &compatibleSignatures,
712                                                 const ArenaVector<ir::Expression *> &arguments,
713                                                 const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
714 {
715     std::vector<bool> argTypeInferenceRequired = FindTypeInferenceArguments(arguments);
716     Signature *mostSpecificSignature = ChooseMostSpecificSignature(compatibleSignatures, argTypeInferenceRequired, pos);
717 
718     if (mostSpecificSignature == nullptr) {
719         LogTypeError({"Reference to ", compatibleSignatures.front()->Function()->Id()->Name(), " is ambiguous"}, pos);
720         return nullptr;
721     }
722 
723     if (!TypeInference(mostSpecificSignature, arguments, resolveFlags)) {
724         return nullptr;
725     }
726 
727     return mostSpecificSignature;
728 }
729 
ValidateSignatures(ArenaVector<Signature *> &signatures, const ir::TSTypeParameterInstantiation *typeArguments, const ArenaVector<ir::Expression *> &arguments, const lexer::SourcePosition &pos, std::string_view signatureKind, TypeRelationFlag resolveFlags)730 Signature *ETSChecker::ValidateSignatures(ArenaVector<Signature *> &signatures,
731                                           const ir::TSTypeParameterInstantiation *typeArguments,
732                                           const ArenaVector<ir::Expression *> &arguments,
733                                           const lexer::SourcePosition &pos, std::string_view signatureKind,
734                                           TypeRelationFlag resolveFlags)
735 {
736     auto compatibleSignatures = CollectSignatures(signatures, typeArguments, arguments, pos, resolveFlags);
737     if (!compatibleSignatures.empty()) {
738         return GetMostSpecificSignature(compatibleSignatures, arguments, pos, resolveFlags);
739     }
740 
741     if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0 && !arguments.empty() && !signatures.empty()) {
742         std::stringstream ss;
743 
744         if (signatures[0]->Function()->IsConstructor()) {
745             ss << util::Helpers::GetClassDefiniton(signatures[0]->Function())->PrivateId().Mutf8();
746         } else {
747             ss << signatures[0]->Function()->Id()->Name().Mutf8();
748         }
749 
750         ss << "(";
751 
752         for (uint32_t index = 0; index < arguments.size(); ++index) {
753             if (arguments[index]->IsArrowFunctionExpression()) {
754                 // NOTE(peterseres): Refactor this case and add test case
755                 break;
756             }
757 
758             arguments[index]->Check(this);
759             arguments[index]->TsType()->ToString(ss);
760 
761             if (index == arguments.size() - 1) {
762                 ss << ")";
763                 LogTypeError({"No matching ", signatureKind, " signature for ", ss.str().c_str()}, pos);
764                 return nullptr;
765             }
766 
767             ss << ", ";
768         }
769     }
770 
771     if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0) {
772         LogTypeError({"No matching ", signatureKind, " signature"}, pos);
773     }
774 
775     return nullptr;
776 }
777 
FindMostSpecificSignature(const ArenaVector<Signature *> &signatures, const ArenaMultiMap<size_t, Signature *> &bestSignaturesForParameter, size_t paramCount)778 Signature *ETSChecker::FindMostSpecificSignature(const ArenaVector<Signature *> &signatures,
779                                                  const ArenaMultiMap<size_t, Signature *> &bestSignaturesForParameter,
780                                                  size_t paramCount)
781 {
782     Signature *mostSpecificSignature = nullptr;
783 
784     for (auto *sig : signatures) {
785         bool mostSpecific = true;
786 
787         for (size_t paramIdx = 0; paramIdx < paramCount; ++paramIdx) {
788             const auto range = bestSignaturesForParameter.equal_range(paramIdx);
789             // Check if signature is most specific for i. parameter type.
790             mostSpecific = std::any_of(range.first, range.second, [&sig](auto entry) { return entry.second == sig; });
791             if (!mostSpecific) {
792                 break;
793             }
794         }
795 
796         if (!mostSpecific) {
797             continue;
798         }
799         if (mostSpecificSignature == nullptr) {
800             mostSpecificSignature = sig;
801             continue;
802         }
803         if (mostSpecificSignature->Owner() == sig->Owner()) {
804             // NOTE: audovichenko. Remove this 'if' when #12443 gets resolved
805             if (mostSpecificSignature->Function() == sig->Function()) {
806                 // The same signature
807                 continue;
808             }
809             return nullptr;
810         }
811     }
812     return mostSpecificSignature;
813 }
814 
InitMostSpecificType(const ArenaVector<Signature *> &signatures, [[maybe_unused]] Type *&mostSpecificType, [[maybe_unused]] Signature *&prevSig, const size_t idx)815 static void InitMostSpecificType(const ArenaVector<Signature *> &signatures, [[maybe_unused]] Type *&mostSpecificType,
816                                  [[maybe_unused]] Signature *&prevSig, const size_t idx)
817 {
818     for (auto *sig : signatures) {
819         if (Type *sigType = sig->Params().at(idx)->TsType();
820             sigType->IsETSObjectType() && !sigType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
821             mostSpecificType = sigType;
822             prevSig = sig;
823             return;
824         }
825     }
826 }
827 
SearchAmongMostSpecificTypes( Type *&mostSpecificType, Signature *&prevSig, std::tuple<const lexer::SourcePosition &, size_t, size_t, size_t, Signature *> info, bool lookForClassType)828 void ETSChecker::SearchAmongMostSpecificTypes(
829     Type *&mostSpecificType, Signature *&prevSig,
830     std::tuple<const lexer::SourcePosition &, size_t, size_t, size_t, Signature *> info, bool lookForClassType)
831 {
832     auto [pos, argumentsSize, paramCount, idx, sig] = info;
833     if (lookForClassType && argumentsSize == ULONG_MAX) {
834         [[maybe_unused]] const bool equalParamSize = sig->Params().size() == paramCount;
835         ASSERT(equalParamSize);
836     }
837     Type *sigType = sig->Params().at(idx)->TsType();
838     const bool isClassType =
839         sigType->IsETSObjectType() && !sigType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE);
840     if (isClassType == lookForClassType) {
841         if (Relation()->IsIdenticalTo(sigType, mostSpecificType)) {
842             return;
843         }
844         if (Relation()->IsAssignableTo(sigType, mostSpecificType)) {
845             mostSpecificType = sigType;
846             prevSig = sig;
847         } else if (sigType->IsETSObjectType() && mostSpecificType->IsETSObjectType() &&
848                    !Relation()->IsAssignableTo(mostSpecificType, sigType)) {
849             auto funcName = sig->Function()->Id()->Name();
850             LogTypeError({"Call to `", funcName, "` is ambiguous as `2` versions of `", funcName, "` are available: `",
851                           funcName, prevSig, "` and `", funcName, sig, "`"},
852                          pos);
853         }
854     }
855 }
856 
GetSuitableSignaturesForParameter( const std::vector<bool> &argTypeInferenceRequired, size_t paramCount, ArenaVector<Signature *> &signatures, const lexer::SourcePosition &pos, size_t argumentsSize)857 ArenaMultiMap<size_t, Signature *> ETSChecker::GetSuitableSignaturesForParameter(
858     const std::vector<bool> &argTypeInferenceRequired, size_t paramCount, ArenaVector<Signature *> &signatures,
859     const lexer::SourcePosition &pos, size_t argumentsSize)
860 {
861     // Collect which signatures are most specific for each parameter.
862     ArenaMultiMap<size_t /* parameter index */, Signature *> bestSignaturesForParameter(Allocator()->Adapter());
863 
864     const checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(Relation(),
865                                                                           TypeRelationFlag::ONLY_CHECK_WIDENING);
866 
867     for (size_t i = 0; i < paramCount; ++i) {
868         if (argTypeInferenceRequired[i]) {
869             for (auto *sig : signatures) {
870                 bestSignaturesForParameter.insert({i, sig});
871             }
872             continue;
873         }
874         // 1st step: check which is the most specific parameter type for i. parameter.
875         Type *mostSpecificType = signatures.front()->Params().at(i)->TsType();
876         Signature *prevSig = signatures.front();
877 
878         InitMostSpecificType(signatures, mostSpecificType, prevSig, i);
879         for (auto *sig : signatures) {
880             SearchAmongMostSpecificTypes(mostSpecificType, prevSig,
881                                          std::make_tuple(pos, argumentsSize, paramCount, i, sig), true);
882         }
883         for (auto *sig : signatures) {
884             SearchAmongMostSpecificTypes(mostSpecificType, prevSig,
885                                          std::make_tuple(pos, argumentsSize, paramCount, i, sig), false);
886         }
887 
888         for (auto *sig : signatures) {
889             Type *sigType = sig->Params().at(i)->TsType();
890             if (Relation()->IsIdenticalTo(sigType, mostSpecificType)) {
891                 bestSignaturesForParameter.insert({i, sig});
892             }
893         }
894     }
895     return bestSignaturesForParameter;
896 }
897 
ChooseMostSpecificSignature(ArenaVector<Signature *> &signatures, const std::vector<bool> &argTypeInferenceRequired, const lexer::SourcePosition &pos, size_t argumentsSize)898 Signature *ETSChecker::ChooseMostSpecificSignature(ArenaVector<Signature *> &signatures,
899                                                    const std::vector<bool> &argTypeInferenceRequired,
900                                                    const lexer::SourcePosition &pos, size_t argumentsSize)
901 {
902     ASSERT(signatures.empty() == false);
903 
904     if (signatures.size() == 1) {
905         return signatures.front();
906     }
907 
908     size_t paramCount = signatures.front()->Params().size();
909     if (argumentsSize != ULONG_MAX) {
910         paramCount = argumentsSize;
911     }
912     // Multiple signatures with zero parameter because of inheritance.
913     // Return the closest one in inheritance chain that is defined at the beginning of the vector.
914     if (paramCount == 0) {
915         auto zeroParamSignature = std::find_if(signatures.begin(), signatures.end(),
916                                                [](auto *signature) { return signature->RestVar() == nullptr; });
917         // If there is a zero parameter signature, return that
918         if (zeroParamSignature != signatures.end()) {
919             return *zeroParamSignature;
920         }
921         // If there are multiple rest parameter signatures with different argument types, throw error
922         if (signatures.size() > 1 && std::any_of(signatures.begin(), signatures.end(), [signatures](const auto *param) {
923                 return param->RestVar()->TsType() != signatures.front()->RestVar()->TsType();
924             })) {
925             ThrowTypeError({"Call to `", signatures.front()->Function()->Id()->Name(), "` is ambiguous "}, pos);
926         }
927         // Else return the signature with the rest parameter
928         auto restParamSignature = std::find_if(signatures.begin(), signatures.end(),
929                                                [](auto *signature) { return signature->RestVar() != nullptr; });
930         return *restParamSignature;
931     }
932 
933     ArenaMultiMap<size_t /* parameter index */, Signature *> bestSignaturesForParameter =
934         GetSuitableSignaturesForParameter(argTypeInferenceRequired, paramCount, signatures, pos, argumentsSize);
935     // Find the signature that are most specific for all parameters.
936     Signature *mostSpecificSignature = FindMostSpecificSignature(signatures, bestSignaturesForParameter, paramCount);
937 
938     return mostSpecificSignature;
939 }
940 
ResolveCallExpressionAndTrailingLambda(ArenaVector<Signature *> &signatures, ir::CallExpression *callExpr, const lexer::SourcePosition &pos, const TypeRelationFlag reportFlag)941 Signature *ETSChecker::ResolveCallExpressionAndTrailingLambda(ArenaVector<Signature *> &signatures,
942                                                               ir::CallExpression *callExpr,
943                                                               const lexer::SourcePosition &pos,
944                                                               const TypeRelationFlag reportFlag)
945 {
946     Signature *sig = nullptr;
947     if (callExpr->TrailingBlock() == nullptr) {
948         for (auto it : signatures) {
949             MaybeSubstituteLambdaArguments(it->Function()->Params(), callExpr);
950 
951             if (callExpr->Arguments().size() != it->Function()->Params().size()) {
952                 MaybeSubstituteLambdaArgumentsInFunctionCall(callExpr);
953             }
954         }
955 
956         sig = ValidateSignatures(signatures, callExpr->TypeParams(), callExpr->Arguments(), pos, "call", reportFlag);
957         return sig;
958     }
959 
960     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
961     auto arguments = ExtendArgumentsWithFakeLamda(callExpr);
962     sig = ValidateSignatures(signatures, callExpr->TypeParams(), arguments, pos, "call",
963                              TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA);
964     if (sig != nullptr) {
965         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
966         TransformTraillingLambda(callExpr);
967         TypeInference(sig, callExpr->Arguments());
968         return sig;
969     }
970 
971     sig = ValidateSignatures(signatures, callExpr->TypeParams(), callExpr->Arguments(), pos, "call", reportFlag);
972     if (sig != nullptr) {
973         EnsureValidCurlyBrace(callExpr);
974     }
975 
976     return sig;
977 }
978 
ResolveConstructExpression(ETSObjectType *type, const ArenaVector<ir::Expression *> &arguments, const lexer::SourcePosition &pos)979 Signature *ETSChecker::ResolveConstructExpression(ETSObjectType *type, const ArenaVector<ir::Expression *> &arguments,
980                                                   const lexer::SourcePosition &pos)
981 {
982     return ValidateSignatures(type->ConstructSignatures(), nullptr, arguments, pos, "construct");
983 }
984 
985 /*
986  * Object literals do not get checked in the process of call resolution; we need to check them separately
987  * afterwards.
988  */
CheckObjectLiteralArguments(Signature *signature, ArenaVector<ir::Expression *> const &arguments)989 void ETSChecker::CheckObjectLiteralArguments(Signature *signature, ArenaVector<ir::Expression *> const &arguments)
990 {
991     for (uint32_t index = 0; index < arguments.size(); index++) {
992         if (!arguments[index]->IsObjectExpression()) {
993             continue;
994         }
995 
996         Type *tp;
997         if (index >= signature->MinArgCount()) {
998             ASSERT(signature->RestVar());
999             tp = signature->RestVar()->TsType();
1000         } else {
1001             tp = signature->Params()[index]->TsType();
1002         }
1003 
1004         arguments[index]->AsObjectExpression()->SetPreferredType(tp);
1005         arguments[index]->Check(this);
1006     }
1007 }
1008 
BuildMethodSignature(ir::MethodDefinition *method)1009 checker::ETSFunctionType *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method)
1010 {
1011     if (method->TsTypeOrError() != nullptr) {
1012         return method->TsTypeOrError()->AsETSFunctionType();
1013     }
1014 
1015     bool isConstructSig = method->IsConstructor();
1016 
1017     method->Function()->Id()->SetVariable(method->Id()->Variable());
1018     BuildFunctionSignature(method->Function(), isConstructSig);
1019     if (method->Function()->Signature() == nullptr) {
1020         return nullptr;
1021     }
1022     auto *funcType = BuildNamedFunctionType(method->Function());
1023     std::vector<checker::ETSFunctionType *> overloads;
1024 
1025     for (ir::MethodDefinition *const currentFunc : method->Overloads()) {
1026         currentFunc->Function()->Id()->SetVariable(currentFunc->Id()->Variable());
1027         BuildFunctionSignature(currentFunc->Function(), isConstructSig);
1028         if (currentFunc->Function()->Signature() == nullptr) {
1029             return nullptr;
1030         }
1031         auto *const overloadType = BuildNamedFunctionType(currentFunc->Function());
1032         CheckIdenticalOverloads(funcType, overloadType, currentFunc);
1033         currentFunc->SetTsType(overloadType);
1034         funcType->AddCallSignature(currentFunc->Function()->Signature());
1035         overloads.push_back(overloadType);
1036     }
1037     for (size_t baseFuncCounter = 0; baseFuncCounter < overloads.size(); ++baseFuncCounter) {
1038         auto *overloadType = overloads.at(baseFuncCounter);
1039         for (size_t compareFuncCounter = baseFuncCounter + 1; compareFuncCounter < overloads.size();
1040              compareFuncCounter++) {
1041             auto *compareOverloadType = overloads.at(compareFuncCounter);
1042             CheckIdenticalOverloads(overloadType, compareOverloadType, method->Overloads()[compareFuncCounter]);
1043         }
1044     }
1045 
1046     method->Id()->Variable()->SetTsType(funcType);
1047     return funcType;
1048 }
1049 
CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload, const ir::MethodDefinition *const currentFunc)1050 void ETSChecker::CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload,
1051                                          const ir::MethodDefinition *const currentFunc)
1052 {
1053     SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK);
1054 
1055     Relation()->IsIdenticalTo(func, overload);
1056     if (Relation()->IsTrue() && func->CallSignatures()[0]->GetSignatureInfo()->restVar ==
1057                                     overload->CallSignatures()[0]->GetSignatureInfo()->restVar) {
1058         LogTypeError("Function " + func->Name().Mutf8() + " is already declared.", currentFunc->Start());
1059         return;
1060     }
1061     if (HasSameAssemblySignatures(func, overload)) {
1062         LogTypeError("Function " + func->Name().Mutf8() + " with this assembly signature already declared.",
1063                      currentFunc->Start());
1064     }
1065 }
1066 
ComposeSignature(ir::ScriptFunction *func, SignatureInfo *signatureInfo, Type *returnType, varbinder::Variable *nameVar)1067 Signature *ETSChecker::ComposeSignature(ir::ScriptFunction *func, SignatureInfo *signatureInfo, Type *returnType,
1068                                         varbinder::Variable *nameVar)
1069 {
1070     auto *signature = CreateSignature(signatureInfo, returnType, func);
1071     signature->SetOwner(Context().ContainingClass());
1072     signature->SetOwnerVar(nameVar);
1073 
1074     const auto *returnTypeAnnotation = func->ReturnTypeAnnotation();
1075     if (returnTypeAnnotation == nullptr && ((func->Flags() & ir::ScriptFunctionFlags::HAS_RETURN) != 0)) {
1076         signature->AddSignatureFlag(SignatureFlags::NEED_RETURN_TYPE);
1077     }
1078 
1079     if (returnTypeAnnotation != nullptr && returnTypeAnnotation->IsTSThisType()) {
1080         signature->AddSignatureFlag(SignatureFlags::THIS_RETURN_TYPE);
1081     }
1082 
1083     if (func->IsAbstract()) {
1084         signature->AddSignatureFlag(SignatureFlags::ABSTRACT);
1085         signature->AddSignatureFlag(SignatureFlags::VIRTUAL);
1086     }
1087 
1088     if (func->IsStatic()) {
1089         signature->AddSignatureFlag(SignatureFlags::STATIC);
1090     }
1091 
1092     if (func->IsConstructor()) {
1093         signature->AddSignatureFlag(SignatureFlags::CONSTRUCTOR);
1094     }
1095 
1096     if (signature->Owner()->GetDeclNode()->IsFinal() || func->IsFinal()) {
1097         signature->AddSignatureFlag(SignatureFlags::FINAL);
1098     }
1099 
1100     if (func->IsPublic()) {
1101         signature->AddSignatureFlag(SignatureFlags::PUBLIC);
1102     } else if (func->IsInternal()) {
1103         if (func->IsProtected()) {
1104             signature->AddSignatureFlag(SignatureFlags::INTERNAL_PROTECTED);
1105         } else {
1106             signature->AddSignatureFlag(SignatureFlags::INTERNAL);
1107         }
1108     } else if (func->IsProtected()) {
1109         signature->AddSignatureFlag(SignatureFlags::PROTECTED);
1110     } else if (func->IsPrivate()) {
1111         signature->AddSignatureFlag(SignatureFlags::PRIVATE);
1112     }
1113 
1114     return signature;
1115 }
1116 
ComposeReturnType(ir::ScriptFunction *func)1117 Type *ETSChecker::ComposeReturnType(ir::ScriptFunction *func)
1118 {
1119     auto *const returnTypeAnnotation = func->ReturnTypeAnnotation();
1120     checker::Type *returnType {};
1121 
1122     if (returnTypeAnnotation == nullptr) {
1123         // implicit void return type
1124         returnType = GlobalVoidType();
1125 
1126         if (func->IsAsyncFunc()) {
1127             auto implicitPromiseVoid = [this]() {
1128                 const auto &promiseGlobal = GlobalBuiltinPromiseType()->AsETSObjectType();
1129                 auto promiseType =
1130                     promiseGlobal->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsETSObjectType();
1131                 promiseType->AddTypeFlag(checker::TypeFlag::GENERIC);
1132                 promiseType->TypeArguments().clear();
1133                 promiseType->TypeArguments().emplace_back(GlobalVoidType());
1134                 return promiseType;
1135             };
1136 
1137             returnType = implicitPromiseVoid();
1138         }
1139     } else if (func->IsEntryPoint() && returnTypeAnnotation->GetType(this) == GlobalVoidType()) {
1140         returnType = GlobalVoidType();
1141     } else {
1142         returnType = returnTypeAnnotation->GetType(this);
1143         returnTypeAnnotation->SetTsType(returnType);
1144     }
1145 
1146     return returnType;
1147 }
1148 
ComposeSignatureInfo(ir::ScriptFunction *func)1149 SignatureInfo *ETSChecker::ComposeSignatureInfo(ir::ScriptFunction *func)
1150 {
1151     auto *signatureInfo = CreateSignatureInfo();
1152     signatureInfo->restVar = nullptr;
1153     signatureInfo->minArgCount = 0;
1154 
1155     if ((func->IsConstructor() || !func->IsStatic()) && !func->IsArrow()) {
1156         auto *thisVar = func->Scope()->ParamScope()->Params().front();
1157         thisVar->SetTsType(Context().ContainingClass());
1158     }
1159 
1160     if (func->TypeParams() != nullptr) {
1161         auto [typeParamTypes, ok] = CreateUnconstrainedTypeParameters(func->TypeParams());
1162         signatureInfo->typeParams = std::move(typeParamTypes);
1163         if (ok) {
1164             AssignTypeParameterConstraints(func->TypeParams());
1165         }
1166     }
1167 
1168     for (auto *const it : func->Params()) {
1169         auto *const param = it->AsETSParameterExpression();
1170 
1171         if (param->IsRestParameter()) {
1172             auto const *const restIdent = param->Ident();
1173 
1174             ASSERT(restIdent->Variable());
1175             signatureInfo->restVar = restIdent->Variable()->AsLocalVariable();
1176 
1177             auto *const restParamTypeAnnotation = param->TypeAnnotation();
1178             ASSERT(restParamTypeAnnotation);
1179 
1180             signatureInfo->restVar->SetTsType(restParamTypeAnnotation->GetType(this));
1181             auto arrayType = signatureInfo->restVar->TsType()->AsETSArrayType();
1182             CreateBuiltinArraySignature(arrayType, arrayType->Rank());
1183         } else {
1184             auto *const paramIdent = param->Ident();
1185 
1186             varbinder::Variable *const paramVar = paramIdent->Variable();
1187             ASSERT(paramVar);
1188 
1189             auto *const paramTypeAnnotation = param->TypeAnnotation();
1190             if (paramIdent->TsType() == nullptr && paramTypeAnnotation == nullptr) {
1191                 LogTypeError({"The type of parameter '", paramIdent->Name(), "' cannot be determined"}, param->Start());
1192                 return nullptr;
1193             }
1194 
1195             if (paramIdent->TsType() == nullptr) {
1196                 ASSERT(paramTypeAnnotation);
1197 
1198                 paramVar->SetTsType(paramTypeAnnotation->GetType(this));
1199             } else {
1200                 paramVar->SetTsType(paramIdent->TsTypeOrError());
1201             }
1202             signatureInfo->params.push_back(paramVar->AsLocalVariable());
1203             ++signatureInfo->minArgCount;
1204         }
1205     }
1206 
1207     return signatureInfo;
1208 }
1209 
ComposeSignatureInfosForArrowFunction( ir::ArrowFunctionExpression *arrowFuncExpr)1210 ArenaVector<SignatureInfo *> ETSChecker::ComposeSignatureInfosForArrowFunction(
1211     ir::ArrowFunctionExpression *arrowFuncExpr)
1212 {
1213     ArenaVector<SignatureInfo *> signatureInfos(Allocator()->Adapter());
1214 
1215     for (size_t i = arrowFuncExpr->Function()->DefaultParamIndex(); i < arrowFuncExpr->Function()->Params().size();
1216          i++) {
1217         auto *signatureInfo = CreateSignatureInfo();
1218         signatureInfo->restVar = nullptr;
1219         signatureInfo->minArgCount = 0;
1220 
1221         if (arrowFuncExpr->Function()->TypeParams() != nullptr) {
1222             signatureInfo->typeParams =
1223                 CreateUnconstrainedTypeParameters(arrowFuncExpr->Function()->TypeParams()).first;
1224         }
1225 
1226         for (size_t j = 0; j < i; j++) {
1227             SetParamForSignatureInfoOfArrowFunction(signatureInfo,
1228                                                     arrowFuncExpr->Function()->Params()[j]->AsETSParameterExpression());
1229         }
1230 
1231         signatureInfos.push_back(signatureInfo);
1232     }
1233 
1234     return signatureInfos;
1235 }
1236 
SetParamForSignatureInfoOfArrowFunction(SignatureInfo *signatureInfo, ir::ETSParameterExpression *param)1237 void ETSChecker::SetParamForSignatureInfoOfArrowFunction(SignatureInfo *signatureInfo,
1238                                                          ir::ETSParameterExpression *param)
1239 {
1240     if (param->IsRestParameter()) {
1241         auto const *const restIdent = param->Ident();
1242 
1243         ASSERT(restIdent->Variable());
1244         signatureInfo->restVar = restIdent->Variable()->AsLocalVariable();
1245 
1246         auto *const restParamTypeAnnotation = param->TypeAnnotation();
1247         ASSERT(restParamTypeAnnotation);
1248 
1249         signatureInfo->restVar->SetTsType(restParamTypeAnnotation->GetType(this));
1250         auto arrayType = signatureInfo->restVar->TsType()->AsETSArrayType();
1251         CreateBuiltinArraySignature(arrayType, arrayType->Rank());
1252     } else {
1253         auto *const paramIdent = param->Ident();
1254 
1255         varbinder::Variable *const paramVar = paramIdent->Variable();
1256         ASSERT(paramVar);
1257 
1258         auto *const paramTypeAnnotation = param->TypeAnnotation();
1259         if (paramIdent->TsType() == nullptr) {
1260             ASSERT(paramTypeAnnotation);
1261 
1262             paramVar->SetTsType(paramTypeAnnotation->GetType(this));
1263         } else {
1264             paramVar->SetTsType(paramIdent->TsType());
1265         }
1266         signatureInfo->params.push_back(paramVar->AsLocalVariable());
1267         ++signatureInfo->minArgCount;
1268     }
1269 }
1270 
ValidateMainSignature(ir::ScriptFunction *func)1271 void ETSChecker::ValidateMainSignature(ir::ScriptFunction *func)
1272 {
1273     if (func->Params().size() >= 2U) {
1274         LogTypeError("0 or 1 argument are allowed", func->Start());
1275         return;
1276     }
1277 
1278     if (func->Params().size() == 1) {
1279         auto const *const param = func->Params()[0]->AsETSParameterExpression();
1280 
1281         if (param->IsRestParameter()) {
1282             LogTypeError("Rest parameter is not allowed in the 'main' function.", param->Start());
1283         }
1284 
1285         const auto paramType = param->Variable()->TsType();
1286         if (!paramType->IsETSArrayType() || !paramType->AsETSArrayType()->ElementType()->IsETSStringType()) {
1287             LogTypeError("Only 'string[]' type argument is allowed.", param->Start());
1288         }
1289     }
1290 }
1291 
AddSignatureFlags(const ir::ScriptFunction *const func, Signature *const signature)1292 static void AddSignatureFlags(const ir::ScriptFunction *const func, Signature *const signature)
1293 {
1294     if (func->IsAbstract()) {
1295         signature->AddSignatureFlag(SignatureFlags::ABSTRACT);
1296         signature->AddSignatureFlag(SignatureFlags::VIRTUAL);
1297     }
1298 
1299     if (func->IsStatic()) {
1300         signature->AddSignatureFlag(SignatureFlags::STATIC);
1301     }
1302 
1303     if (func->IsConstructor()) {
1304         signature->AddSignatureFlag(SignatureFlags::CONSTRUCTOR);
1305     }
1306 
1307     if (func->Signature()->Owner()->GetDeclNode()->IsFinal() || func->IsFinal()) {
1308         signature->AddSignatureFlag(SignatureFlags::FINAL);
1309     }
1310 
1311     if (func->IsPublic()) {
1312         signature->AddSignatureFlag(SignatureFlags::PUBLIC);
1313     } else if (func->IsInternal()) {
1314         if (func->IsProtected()) {
1315             signature->AddSignatureFlag(SignatureFlags::INTERNAL_PROTECTED);
1316         } else {
1317             signature->AddSignatureFlag(SignatureFlags::INTERNAL);
1318         }
1319     } else if (func->IsProtected()) {
1320         signature->AddSignatureFlag(SignatureFlags::PROTECTED);
1321     } else if (func->IsPrivate()) {
1322         signature->AddSignatureFlag(SignatureFlags::PRIVATE);
1323     }
1324 
1325     if (func->IsSetter()) {
1326         signature->AddSignatureFlag(SignatureFlags::SETTER);
1327     } else if (func->IsGetter()) {
1328         signature->AddSignatureFlag(SignatureFlags::GETTER);
1329     }
1330 }
1331 
BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig)1332 void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig)
1333 {
1334     bool isArrow = func->IsArrow();
1335     auto *nameVar = isArrow ? nullptr : func->Id()->Variable();
1336     auto funcName = nameVar == nullptr ? util::StringView() : nameVar->Name();
1337 
1338     auto *signatureInfo = ComposeSignatureInfo(func);
1339     if (signatureInfo == nullptr) {
1340         return;
1341     }
1342 
1343     if (funcName.Is(compiler::Signatures::MAIN) &&
1344         func->Scope()->Name().Utf8().find(compiler::Signatures::ETS_GLOBAL) != std::string::npos) {
1345         func->AddFlag(ir::ScriptFunctionFlags::ENTRY_POINT);
1346     }
1347     if (func->IsEntryPoint()) {
1348         ValidateMainSignature(func);
1349     }
1350 
1351     auto *returnType = ComposeReturnType(func);
1352     auto *signature = ComposeSignature(func, signatureInfo, returnType, nameVar);
1353     if (isConstructSig) {
1354         signature->AddSignatureFlag(SignatureFlags::CONSTRUCT);
1355     } else {
1356         signature->AddSignatureFlag(SignatureFlags::CALL);
1357     }
1358     func->SetSignature(signature);
1359     AddSignatureFlags(func, signature);
1360     VarBinder()->AsETSBinder()->BuildFunctionName(func);
1361 }
1362 
BuildNamedFunctionType(ir::ScriptFunction *func)1363 checker::ETSFunctionType *ETSChecker::BuildNamedFunctionType(ir::ScriptFunction *func)
1364 {
1365     ASSERT(!func->IsArrow());
1366     auto *nameVar = func->Id()->Variable();
1367     auto *funcType = CreateETSFunctionType(func, func->Signature(), nameVar->Name());
1368     funcType->SetVariable(nameVar);
1369     return funcType;
1370 }
1371 
CheckEveryAbstractSignatureIsOverridden(ETSFunctionType *target, ETSFunctionType *source)1372 Signature *ETSChecker::CheckEveryAbstractSignatureIsOverridden(ETSFunctionType *target, ETSFunctionType *source)
1373 {
1374     for (auto targetSig = target->CallSignatures().begin(); targetSig != target->CallSignatures().end();) {
1375         if (!(*targetSig)->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
1376             continue;
1377         }
1378 
1379         bool isOverridden = false;
1380         for (auto sourceSig : source->CallSignatures()) {
1381             if ((*targetSig)->Function()->Id()->Name() == sourceSig->Function()->Id()->Name() &&
1382                 Relation()->IsCompatibleTo(*targetSig, sourceSig)) {
1383                 target->CallSignatures().erase(targetSig);
1384                 isOverridden = true;
1385                 break;
1386             }
1387             sourceSig++;
1388         }
1389 
1390         if (!isOverridden) {
1391             return *targetSig;
1392         }
1393     }
1394 
1395     return nullptr;
1396 }
1397 
IsOverridableIn(Signature *signature)1398 bool ETSChecker::IsOverridableIn(Signature *signature)
1399 {
1400     if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) {
1401         return false;
1402     }
1403 
1404     // NOTE: #15095 workaround, separate internal visibility check
1405     if (signature->HasSignatureFlag(SignatureFlags::PUBLIC | SignatureFlags::INTERNAL)) {
1406         return true;
1407     }
1408 
1409     return signature->HasSignatureFlag(SignatureFlags::PROTECTED);
1410 }
1411 
IsMethodOverridesOther(Signature *base, Signature *derived)1412 bool ETSChecker::IsMethodOverridesOther(Signature *base, Signature *derived)
1413 {
1414     if (derived->Function()->IsConstructor()) {
1415         return false;
1416     }
1417 
1418     if (base == derived) {
1419         return true;
1420     }
1421 
1422     if (derived->HasSignatureFlag(SignatureFlags::STATIC) != base->HasSignatureFlag(SignatureFlags::STATIC)) {
1423         return false;
1424     }
1425 
1426     if (IsOverridableIn(base)) {
1427         SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK |
1428                                                                     TypeRelationFlag::OVERRIDING_CONTEXT);
1429         if (Relation()->IsCompatibleTo(base, derived)) {
1430             CheckThrowMarkers(base, derived);
1431 
1432             if (derived->HasSignatureFlag(SignatureFlags::STATIC)) {
1433                 return false;
1434             }
1435 
1436             derived->Function()->SetOverride();
1437             return true;
1438         }
1439     }
1440 
1441     return false;
1442 }
1443 
CheckThrowMarkers(Signature *source, Signature *target)1444 bool ETSChecker::CheckThrowMarkers(Signature *source, Signature *target)
1445 {
1446     ir::ScriptFunctionFlags throwMarkers = ir::ScriptFunctionFlags::THROWS | ir::ScriptFunctionFlags::RETHROWS;
1447     if ((source->Function()->Flags() & throwMarkers) == (target->Function()->Flags() & throwMarkers)) {
1448         return true;
1449     }
1450 
1451     if ((source->Function()->IsRethrowing() && target->Function()->IsThrowing()) ||
1452         (!source->Function()->IsThrowing() &&
1453          (target->Function()->IsRethrowing() || target->Function()->IsThrowing()))) {
1454         ThrowTypeError(
1455             "A method that overrides or hides another method cannot change throw or rethrow clauses of the "
1456             "overridden "
1457             "or hidden method.",
1458             target->Function()->Body() == nullptr ? target->Function()->Start() : target->Function()->Body()->Start());
1459         return false;
1460     }
1461     return true;
1462 }
1463 
CheckOverride(Signature *signature, Signature *other)1464 OverrideErrorCode ETSChecker::CheckOverride(Signature *signature, Signature *other)
1465 {
1466     if (other->HasSignatureFlag(SignatureFlags::STATIC)) {
1467         ASSERT(signature->HasSignatureFlag(SignatureFlags::STATIC));
1468         return OverrideErrorCode::NO_ERROR;
1469     }
1470 
1471     if (other->IsFinal()) {
1472         return OverrideErrorCode::OVERRIDDEN_FINAL;
1473     }
1474 
1475     if (!other->ReturnType()->IsETSTypeParameter()) {
1476         if (!IsReturnTypeSubstitutable(signature, other)) {
1477             return OverrideErrorCode::INCOMPATIBLE_RETURN;
1478         }
1479     } else {
1480         // We need to have this branch to allow generic overriding of the form:
1481         // foo<T>(x: T): T -> foo<someClass>(x: someClass): someClass
1482         if (!signature->ReturnType()->IsETSReferenceType()) {
1483             return OverrideErrorCode::INCOMPATIBLE_RETURN;
1484         }
1485     }
1486 
1487     if (signature->ProtectionFlag() > other->ProtectionFlag()) {
1488         return OverrideErrorCode::OVERRIDDEN_WEAKER;
1489     }
1490 
1491     return OverrideErrorCode::NO_ERROR;
1492 }
1493 
AdjustForTypeParameters(Signature *source, Signature *target)1494 Signature *ETSChecker::AdjustForTypeParameters(Signature *source, Signature *target)
1495 {
1496     auto &sourceTypeParams = source->GetSignatureInfo()->typeParams;
1497     auto &targetTypeParams = target->GetSignatureInfo()->typeParams;
1498     if (sourceTypeParams.size() != targetTypeParams.size()) {
1499         return nullptr;
1500     }
1501     if (sourceTypeParams.empty()) {
1502         return target;
1503     }
1504     auto *substitution = NewSubstitution();
1505     for (size_t ix = 0; ix < sourceTypeParams.size(); ix++) {
1506         if (!targetTypeParams[ix]->IsETSTypeParameter()) {
1507             continue;
1508         }
1509         ETSChecker::EmplaceSubstituted(substitution, targetTypeParams[ix]->AsETSTypeParameter(), sourceTypeParams[ix]);
1510     }
1511     return target->Substitute(Relation(), substitution);
1512 }
1513 
ReportOverrideError(Signature *signature, Signature *overriddenSignature, const OverrideErrorCode &errorCode)1514 void ETSChecker::ReportOverrideError(Signature *signature, Signature *overriddenSignature,
1515                                      const OverrideErrorCode &errorCode)
1516 {
1517     const char *reason {};
1518     switch (errorCode) {
1519         case OverrideErrorCode::OVERRIDDEN_FINAL: {
1520             reason = "overridden method is final.";
1521             break;
1522         }
1523         case OverrideErrorCode::INCOMPATIBLE_RETURN: {
1524             reason = "overriding return type is not compatible with the other return type.";
1525             break;
1526         }
1527         case OverrideErrorCode::OVERRIDDEN_WEAKER: {
1528             reason = "overridden method has weaker access privilege.";
1529             break;
1530         }
1531         default: {
1532             UNREACHABLE();
1533         }
1534     }
1535 
1536     LogTypeError({signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), " cannot override ",
1537                   overriddenSignature->Function()->Id()->Name(), overriddenSignature, " in ",
1538                   overriddenSignature->Owner(), " because ", reason},
1539                  signature->Function()->Start());
1540 }
1541 
CheckOverride(Signature *signature, ETSObjectType *site)1542 bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site)
1543 {
1544     auto *target = site->GetProperty(signature->Function()->Id()->Name(), PropertySearchFlags::SEARCH_METHOD);
1545     bool isOverridingAnySignature = false;
1546 
1547     if (target == nullptr) {
1548         return isOverridingAnySignature;
1549     }
1550 
1551     for (auto *it : target->TsType()->AsETSFunctionType()->CallSignatures()) {
1552         auto *itSubst = AdjustForTypeParameters(signature, it);
1553 
1554         if (itSubst == nullptr) {
1555             continue;
1556         }
1557 
1558         if (itSubst->HasSignatureFlag(SignatureFlags::ABSTRACT) || site->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
1559             if (site->HasObjectFlag(ETSObjectFlags::INTERFACE) && !CheckThrowMarkers(itSubst, signature)) {
1560                 return false;
1561             }
1562 
1563             if ((itSubst->Function()->IsSetter() && !signature->Function()->IsSetter()) ||
1564                 (itSubst->Function()->IsGetter() && !signature->Function()->IsGetter())) {
1565                 continue;
1566             }
1567         }
1568 
1569         if (!IsMethodOverridesOther(itSubst, signature)) {
1570             continue;
1571         }
1572 
1573         if (auto err = CheckOverride(signature, itSubst); err != OverrideErrorCode::NO_ERROR) {
1574             ReportOverrideError(signature, it, err);
1575             return false;
1576         }
1577 
1578         if (signature->Owner()->HasObjectFlag(ETSObjectFlags::INTERFACE) &&
1579             Relation()->IsIdenticalTo(itSubst->Owner(), GlobalETSObjectType()) &&
1580             !itSubst->HasSignatureFlag(SignatureFlags::PRIVATE)) {
1581             LogTypeError("Cannot override non-private method of the class Object from an interface.",
1582                          signature->Function()->Start());
1583             return false;
1584         }
1585 
1586         isOverridingAnySignature = true;
1587         it->AddSignatureFlag(SignatureFlags::VIRTUAL);
1588     }
1589 
1590     return isOverridingAnySignature;
1591 }
1592 
CheckOverride(Signature *signature)1593 void ETSChecker::CheckOverride(Signature *signature)
1594 {
1595     auto *owner = signature->Owner();
1596     bool isOverriding = false;
1597 
1598     if (!owner->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE)) {
1599         return;
1600     }
1601 
1602     for (auto *const interface : owner->Interfaces()) {
1603         isOverriding |= CheckInterfaceOverride(this, interface, signature);
1604     }
1605 
1606     ETSObjectType *iter = owner->SuperType();
1607     while (iter != nullptr) {
1608         isOverriding |= CheckOverride(signature, iter);
1609 
1610         for (auto *const interface : iter->Interfaces()) {
1611             isOverriding |= CheckInterfaceOverride(this, interface, signature);
1612         }
1613 
1614         iter = iter->SuperType();
1615     }
1616 
1617     if (!isOverriding && signature->Function()->IsOverride()) {
1618         LogTypeError({"Method ", signature->Function()->Id()->Name(), signature, " in ", signature->Owner(),
1619                       " not overriding any method"},
1620                      signature->Function()->Start());
1621     }
1622 }
1623 
GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef)1624 Signature *ETSChecker::GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef)
1625 {
1626     if (methodDef->TsTypeOrError()->IsTypeError()) {
1627         return nullptr;
1628     }
1629     ASSERT(methodDef->TsType() && methodDef->TsType()->IsETSFunctionType());
1630     for (auto *it : methodDef->TsType()->AsETSFunctionType()->CallSignatures()) {
1631         if (it->Function() == methodDef->Function()) {
1632             return it;
1633         }
1634     }
1635 
1636     return nullptr;
1637 }
1638 
ValidateSignatureAccessibility(ETSObjectType *callee, const ir::CallExpression *callExpr, Signature *signature, const lexer::SourcePosition &pos, char const *errorMessage)1639 void ETSChecker::ValidateSignatureAccessibility(ETSObjectType *callee, const ir::CallExpression *callExpr,
1640                                                 Signature *signature, const lexer::SourcePosition &pos,
1641                                                 char const *errorMessage)
1642 {
1643     if ((Context().Status() & CheckerStatus::IGNORE_VISIBILITY) != 0U ||
1644         (!signature->HasSignatureFlag(SignatureFlags::PRIVATE) &&
1645          !signature->HasSignatureFlag(SignatureFlags::PROTECTED))) {
1646         return;
1647     }
1648     const auto *declNode = callee->GetDeclNode();
1649     auto *containingClass = Context().ContainingClass();
1650     bool isContainingSignatureInherited = containingClass->IsSignatureInherited(signature);
1651     ASSERT(declNode && (declNode->IsClassDefinition() || declNode->IsTSInterfaceDeclaration()));
1652 
1653     if (declNode->IsTSInterfaceDeclaration()) {
1654         const auto *enclosingFunc =
1655             util::Helpers::FindAncestorGivenByType(callExpr, ir::AstNodeType::SCRIPT_FUNCTION)->AsScriptFunction();
1656         if (callExpr->Callee()->IsMemberExpression() &&
1657             callExpr->Callee()->AsMemberExpression()->Object()->IsThisExpression() &&
1658             signature->Function()->IsPrivate() && !enclosingFunc->IsPrivate()) {
1659             LogTypeError({"Cannot reference 'this' in this context."}, enclosingFunc->Start());
1660         }
1661 
1662         if (containingClass == declNode->AsTSInterfaceDeclaration()->TsType() && isContainingSignatureInherited) {
1663             return;
1664         }
1665     }
1666     if (containingClass == declNode->AsClassDefinition()->TsType() && isContainingSignatureInherited) {
1667         return;
1668     }
1669 
1670     bool isSignatureInherited = callee->IsSignatureInherited(signature);
1671     const auto *currentOutermost = containingClass->OutermostClass();
1672     if (!signature->HasSignatureFlag(SignatureFlags::PRIVATE) &&
1673         ((signature->HasSignatureFlag(SignatureFlags::PROTECTED) && containingClass->IsDescendantOf(callee)) ||
1674          (currentOutermost != nullptr && currentOutermost == callee->OutermostClass())) &&
1675         isSignatureInherited) {
1676         return;
1677     }
1678 
1679     if (errorMessage == nullptr) {
1680         LogTypeError({"Signature ", signature->Function()->Id()->Name(), signature, " is not visible here."}, pos);
1681         return;
1682     }
1683     LogTypeError(errorMessage, pos);
1684 }
1685 
CheckCapturedVariable(ir::AstNode *const node, varbinder::Variable *const var)1686 void ETSChecker::CheckCapturedVariable(ir::AstNode *const node, varbinder::Variable *const var)
1687 {
1688     if (node->IsIdentifier()) {
1689         const auto *const parent = node->Parent();
1690 
1691         if (parent->IsUpdateExpression() ||
1692             (parent->IsAssignmentExpression() && parent->AsAssignmentExpression()->Left() == node)) {
1693             const auto *const identNode = node->AsIdentifier();
1694 
1695             const auto *resolved = identNode->Variable();
1696 
1697             if (resolved == nullptr) {
1698                 resolved =
1699                     FindVariableInFunctionScope(identNode->Name(), varbinder::ResolveBindingOptions::ALL_NON_TYPE);
1700             }
1701 
1702             if (resolved == nullptr) {
1703                 resolved = FindVariableInGlobal(identNode, varbinder::ResolveBindingOptions::ALL_NON_TYPE);
1704             }
1705 
1706             if (resolved == var) {
1707                 // For mutable captured variable [possible] smart-cast is senseless (or even erroneous)
1708                 Context().RemoveSmartCast(var);
1709             }
1710         }
1711     }
1712 
1713     CheckCapturedVariableInSubnodes(node, var);
1714 }
1715 
CheckCapturedVariableInSubnodes(ir::AstNode *node, varbinder::Variable *var)1716 void ETSChecker::CheckCapturedVariableInSubnodes(ir::AstNode *node, varbinder::Variable *var)
1717 {
1718     if (!node->IsClassDefinition()) {
1719         node->Iterate([this, var](ir::AstNode *childNode) { CheckCapturedVariable(childNode, var); });
1720     }
1721 }
1722 
CheckCapturedVariables()1723 void ETSChecker::CheckCapturedVariables()
1724 {
1725     // If we want to capture non constant local variables, we should wrap them in a generic reference class
1726     for (auto [var, _] : Context().CapturedVars()) {
1727         (void)_;
1728         if ((var->Declaration() == nullptr) || var->Declaration()->IsConstDecl() ||
1729             !var->HasFlag(varbinder::VariableFlags::LOCAL) || var->GetScope()->Node()->IsArrowFunctionExpression()) {
1730             continue;
1731         }
1732 
1733         auto *searchNode = var->Declaration()->Node()->Parent();
1734 
1735         if (searchNode->IsVariableDeclarator()) {
1736             searchNode = searchNode->Parent()->Parent();
1737         }
1738 
1739         CheckCapturedVariableInSubnodes(searchNode, var);
1740     }
1741 }
1742 
AreOverrideEquivalent(Signature *const s1, Signature *const s2)1743 bool ETSChecker::AreOverrideEquivalent(Signature *const s1, Signature *const s2)
1744 {
1745     // Two functions, methods or constructors M and N have the same signature if
1746     // their names and type parameters (if any) are the same, and their formal parameter
1747     // types are also the same (after the formal parameter types of N are adapted to the type parameters of M).
1748     // Signatures s1 and s2 are override-equivalent only if s1 and s2 are the same.
1749 
1750     SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::OVERRIDING_CONTEXT);
1751     return s1->Function()->Id()->Name() == s2->Function()->Id()->Name() && Relation()->IsCompatibleTo(s1, s2);
1752 }
1753 
IsReturnTypeSubstitutable(Signature *const s1, Signature *const s2)1754 bool ETSChecker::IsReturnTypeSubstitutable(Signature *const s1, Signature *const s2)
1755 {
1756     auto *const r1 = s1->ReturnType();
1757     auto *const r2 = s2->ReturnType();
1758 
1759     // A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return
1760     // type R2 if any of the following is true:
1761 
1762     // - If R1 is a primitive type then R2 is identical to R1.
1763     if (r1->HasTypeFlag(TypeFlag::ETS_PRIMITIVE | TypeFlag::ETS_INT_ENUM | TypeFlag::ETS_STRING_ENUM |
1764                         TypeFlag::ETS_VOID)) {
1765         return Relation()->IsIdenticalTo(r2, r1);
1766     }
1767 
1768     // - If R1 is a reference type then R1, adapted to the type parameters of d2 (link to generic methods), is a
1769     // subtype of R2.
1770     ASSERT(IsReferenceType(r1));
1771 
1772     if (Relation()->IsSupertypeOf(r2, r1)) {
1773         return true;
1774     }
1775 
1776     return s2->Function()->ReturnTypeAnnotation()->IsETSTypeReference() &&
1777            Relation()->IsSupertypeOf(
1778                s2->Function()->ReturnTypeAnnotation()->GetType(this)->AsETSTypeParameter()->GetConstraintType(), r1);
1779 }
1780 
GetAsyncImplName(const util::StringView &name)1781 std::string ETSChecker::GetAsyncImplName(const util::StringView &name)
1782 {
1783     std::string implName(name);
1784     implName += "$asyncimpl";
1785     return implName;
1786 }
1787 
GetAsyncImplName(ir::MethodDefinition *asyncMethod)1788 std::string ETSChecker::GetAsyncImplName(ir::MethodDefinition *asyncMethod)
1789 {
1790     ir::Identifier *asyncName = asyncMethod->Function()->Id();
1791     ASSERT(asyncName != nullptr);
1792     return GetAsyncImplName(asyncName->Name());
1793 }
1794 
IsAsyncImplMethod(ir::MethodDefinition const *method)1795 bool ETSChecker::IsAsyncImplMethod(ir::MethodDefinition const *method)
1796 {
1797     auto methodName = method->Key()->AsIdentifier()->Name().Utf8();
1798     std::string_view asyncSuffix = "$asyncimpl";
1799     if (methodName.size() < asyncSuffix.size()) {
1800         return false;
1801     }
1802     return methodName.substr(methodName.size() - asyncSuffix.size()) == asyncSuffix;
1803 }
1804 
CreateAsyncImplMethod(ir::MethodDefinition *asyncMethod, ir::ClassDefinition *classDef)1805 ir::MethodDefinition *ETSChecker::CreateAsyncImplMethod(ir::MethodDefinition *asyncMethod,
1806                                                         ir::ClassDefinition *classDef)
1807 {
1808     util::UString implName(GetAsyncImplName(asyncMethod), Allocator());
1809     ir::ModifierFlags modifiers = asyncMethod->Modifiers();
1810     // clear ASYNC flag for implementation
1811     modifiers &= ~ir::ModifierFlags::ASYNC;
1812     ir::ScriptFunction *asyncFunc = asyncMethod->Function();
1813     ir::ScriptFunctionFlags flags = ir::ScriptFunctionFlags::METHOD;
1814 
1815     if (asyncFunc->IsProxy()) {
1816         flags |= ir::ScriptFunctionFlags::PROXY;
1817     }
1818 
1819     if (asyncFunc->HasReturnStatement()) {
1820         flags |= ir::ScriptFunctionFlags::HAS_RETURN;
1821     }
1822 
1823     asyncMethod->AddModifier(ir::ModifierFlags::NATIVE);
1824     asyncFunc->AddModifier(ir::ModifierFlags::NATIVE);
1825     // Create async_impl method copied from CreateInvokeFunction
1826     auto scopeCtx =
1827         varbinder::LexicalScope<varbinder::ClassScope>::Enter(VarBinder(), classDef->Scope()->AsClassScope());
1828     auto *body = asyncFunc->Body();
1829     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
1830     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1831     varbinder::FunctionParamScope *paramScope = CopyParams(asyncFunc->Params(), params);
1832 
1833     ir::ETSTypeReference *returnTypeAnn = nullptr;
1834 
1835     if (!asyncFunc->Signature()->HasSignatureFlag(SignatureFlags::NEED_RETURN_TYPE)) {
1836         // Set impl method return type "Object" because it may return Promise as well as Promise parameter's type
1837         auto *objectId = AllocNode<ir::Identifier>(compiler::Signatures::BUILTIN_OBJECT_CLASS, Allocator());
1838         objectId->SetReference();
1839         VarBinder()->AsETSBinder()->LookupTypeReference(objectId, false);
1840         returnTypeAnn =
1841             AllocNode<ir::ETSTypeReference>(AllocNode<ir::ETSTypeReferencePart>(objectId, nullptr, nullptr));
1842         objectId->SetParent(returnTypeAnn->Part());
1843         returnTypeAnn->Part()->SetParent(returnTypeAnn);
1844         auto *asyncFuncRetTypeAnn = asyncFunc->ReturnTypeAnnotation();
1845         auto *promiseType = [this](ir::TypeNode *type) {
1846             if (type != nullptr) {
1847                 return type->GetType(this)->AsETSObjectType();
1848             }
1849 
1850             return GlobalBuiltinPromiseType()->AsETSObjectType();
1851         }(asyncFuncRetTypeAnn);
1852         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1853         auto *retType = Allocator()->New<ETSAsyncFuncReturnType>(Allocator(), Relation(), promiseType);
1854         returnTypeAnn->SetTsType(retType);
1855     }
1856 
1857     ir::MethodDefinition *implMethod =
1858         CreateMethod(implName.View(), modifiers, flags, std::move(params), paramScope, returnTypeAnn, body);
1859     asyncFunc->SetBody(nullptr);
1860 
1861     if (returnTypeAnn != nullptr) {
1862         returnTypeAnn->SetParent(implMethod->Function());
1863     }
1864 
1865     implMethod->Function()->AddFlag(ir::ScriptFunctionFlags::ASYNC_IMPL);
1866     implMethod->SetParent(asyncMethod->Parent());
1867     return implMethod;
1868 }
1869 
CreateFuncDecl(ETSChecker *checker, ir::MethodDefinition *func, varbinder::LocalScope *scope)1870 static void CreateFuncDecl(ETSChecker *checker, ir::MethodDefinition *func, varbinder::LocalScope *scope)
1871 {
1872     auto *allocator = checker->Allocator();
1873     auto *varBinder = checker->VarBinder();
1874     // Add the function declarations to the lambda class scope
1875     auto ctx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(varBinder, scope);
1876     varbinder::Variable *var = scope->FindLocal(func->Id()->Name(), varbinder::ResolveBindingOptions::ALL_DECLARATION);
1877     if (var == nullptr) {
1878         var = std::get<1>(
1879             varBinder->NewVarDecl<varbinder::FunctionDecl>(func->Start(), allocator, func->Id()->Name(), func));
1880     }
1881     var->AddFlag(varbinder::VariableFlags::METHOD);
1882     var->SetScope(ctx.GetScope());
1883     func->Function()->Id()->SetVariable(var);
1884 }
1885 
CreateAsyncProxy(ir::MethodDefinition *asyncMethod, ir::ClassDefinition *classDef, bool createDecl)1886 ir::MethodDefinition *ETSChecker::CreateAsyncProxy(ir::MethodDefinition *asyncMethod, ir::ClassDefinition *classDef,
1887                                                    bool createDecl)
1888 {
1889     ir::ScriptFunction *asyncFunc = asyncMethod->Function();
1890     if (!asyncFunc->IsExternal()) {
1891         VarBinder()->AsETSBinder()->GetRecordTable()->Signatures().push_back(asyncFunc->Scope());
1892     }
1893 
1894     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1895     ir::MethodDefinition *implMethod = CreateAsyncImplMethod(asyncMethod, classDef);
1896     varbinder::FunctionScope *implFuncScope = implMethod->Function()->Scope();
1897     for (auto *decl : asyncFunc->Scope()->Decls()) {
1898         auto res = asyncFunc->Scope()->Bindings().find(decl->Name());
1899         ASSERT(res != asyncFunc->Scope()->Bindings().end());
1900         auto *const var = std::get<1>(*res);
1901         var->SetScope(implFuncScope);
1902         implFuncScope->Decls().push_back(decl);
1903         implFuncScope->InsertBinding(decl->Name(), var);
1904     }
1905 
1906     ReplaceScope(implMethod->Function()->Body(), asyncFunc, implFuncScope);
1907 
1908     ArenaVector<varbinder::Variable *> captured(Allocator()->Adapter());
1909 
1910     bool isStatic = asyncMethod->IsStatic();
1911     if (createDecl) {
1912         if (isStatic) {
1913             CreateFuncDecl(this, implMethod, classDef->Scope()->AsClassScope()->StaticMethodScope());
1914         } else {
1915             CreateFuncDecl(this, implMethod, classDef->Scope()->AsClassScope()->InstanceMethodScope());
1916         }
1917         implMethod->Id()->SetVariable(implMethod->Function()->Id()->Variable());
1918     }
1919     VarBinder()->AsETSBinder()->BuildProxyMethod(implMethod->Function(), classDef->InternalName(), isStatic,
1920                                                  asyncFunc->IsExternal());
1921     implMethod->SetParent(asyncMethod->Parent());
1922 
1923     return implMethod;
1924 }
1925 
CreateMethod(const util::StringView &name, ir::ModifierFlags modifiers, ir::ScriptFunctionFlags flags, ArenaVector<ir::Expression *> &&params, varbinder::FunctionParamScope *paramScope, ir::TypeNode *returnType, ir::AstNode *body)1926 ir::MethodDefinition *ETSChecker::CreateMethod(const util::StringView &name, ir::ModifierFlags modifiers,
1927                                                ir::ScriptFunctionFlags flags, ArenaVector<ir::Expression *> &&params,
1928                                                varbinder::FunctionParamScope *paramScope, ir::TypeNode *returnType,
1929                                                ir::AstNode *body)
1930 {
1931     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1932     auto *nameId = AllocNode<ir::Identifier>(name, Allocator());
1933     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1934     auto *scope = VarBinder()->Allocator()->New<varbinder::FunctionScope>(Allocator(), paramScope);
1935     // clang-format off
1936     auto *const func = AllocNode<ir::ScriptFunction>(
1937         Allocator(), ir::ScriptFunction::ScriptFunctionData {
1938             body, ir::FunctionSignature(nullptr, std::move(params), returnType), flags, modifiers});
1939     // clang-format on
1940     func->SetScope(scope);
1941     func->SetIdent(nameId);
1942     if (body != nullptr && body->IsBlockStatement()) {
1943         body->AsBlockStatement()->SetScope(scope);
1944     }
1945     scope->BindNode(func);
1946     paramScope->BindNode(func);
1947     scope->BindParamScope(paramScope);
1948     paramScope->BindFunctionScope(scope);
1949     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1950     auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
1951     auto *nameClone = nameId->Clone(Allocator(), nullptr);
1952     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1953     auto *method = AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, nameClone, funcExpr, modifiers,
1954                                                    Allocator(), false);
1955     return method;
1956 }
1957 
CopyParams(const ArenaVector<ir::Expression *> &params, ArenaVector<ir::Expression *> &outParams)1958 varbinder::FunctionParamScope *ETSChecker::CopyParams(const ArenaVector<ir::Expression *> &params,
1959                                                       ArenaVector<ir::Expression *> &outParams)
1960 {
1961     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder());
1962 
1963     for (auto *const it : params) {
1964         auto *const paramOld = it->AsETSParameterExpression();
1965         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1966         auto *const paramNew = paramOld->Clone(Allocator(), paramOld->Parent())->AsETSParameterExpression();
1967 
1968         auto *const var = std::get<1>(VarBinder()->AddParamDecl(paramNew));
1969 
1970         var->SetTsType(paramOld->Ident()->Variable()->TsType());
1971         var->SetScope(paramCtx.GetScope());
1972         paramNew->SetVariable(var);
1973 
1974         paramNew->SetTsType(paramOld->Ident()->Variable()->TsType());
1975 
1976         outParams.emplace_back(paramNew);
1977     }
1978 
1979     return paramCtx.GetScope();
1980 }
1981 
ReplaceScope(ir::AstNode *root, ir::AstNode *oldNode, varbinder::Scope *newScope)1982 void ETSChecker::ReplaceScope(ir::AstNode *root, ir::AstNode *oldNode, varbinder::Scope *newScope)
1983 {
1984     if (root == nullptr) {
1985         return;
1986     }
1987 
1988     root->Iterate([this, oldNode, newScope](ir::AstNode *child) {
1989         auto *scope = NodeScope(child);
1990         if (scope != nullptr) {
1991             while (scope->Parent() != nullptr && scope->Parent()->Node() != oldNode) {
1992                 scope = scope->Parent();
1993             }
1994             scope->SetParent(newScope);
1995         } else {
1996             ReplaceScope(child, oldNode, newScope);
1997         }
1998     });
1999 }
2000 
MoveTrailingBlockToEnclosingBlockStatement(ir::CallExpression *callExpr)2001 void ETSChecker::MoveTrailingBlockToEnclosingBlockStatement(ir::CallExpression *callExpr)
2002 {
2003     if (callExpr == nullptr) {
2004         return;
2005     }
2006 
2007     ir::AstNode *parent = callExpr->Parent();
2008     ir::AstNode *current = callExpr;
2009     while (parent != nullptr) {
2010         if (!parent->IsBlockStatement()) {
2011             current = parent;
2012             parent = parent->Parent();
2013         } else {
2014             // Collect trailing block, insert it only when block statements traversal ends to avoid order mismatch.
2015             parent->AsBlockStatement()->AddTrailingBlock(current, callExpr->TrailingBlock());
2016             callExpr->TrailingBlock()->SetParent(parent);
2017             callExpr->SetTrailingBlock(nullptr);
2018             break;
2019         }
2020     }
2021 }
2022 
TransformTraillingLambda(ir::CallExpression *callExpr)2023 void ETSChecker::TransformTraillingLambda(ir::CallExpression *callExpr)
2024 {
2025     auto *trailingBlock = callExpr->TrailingBlock();
2026     ASSERT(trailingBlock != nullptr);
2027 
2028     auto *funcParamScope = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder()).GetScope();
2029     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), funcParamScope, false);
2030 
2031     auto funcCtx = varbinder::LexicalScope<varbinder::FunctionScope>(VarBinder());
2032     auto *funcScope = funcCtx.GetScope();
2033     funcScope->BindParamScope(funcParamScope);
2034     funcParamScope->BindFunctionScope(funcScope);
2035     funcParamScope->SetParent(trailingBlock->Scope()->Parent());
2036 
2037     for (auto [_, var] : trailingBlock->Scope()->Bindings()) {
2038         (void)_;
2039         if (var->GetScope() == trailingBlock->Scope()) {
2040             var->SetScope(funcScope);
2041             funcScope->InsertBinding(var->Name(), var);
2042         }
2043     }
2044 
2045     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
2046     auto *funcNode = AllocNode<ir::ScriptFunction>(
2047         Allocator(), ir::ScriptFunction::ScriptFunctionData {trailingBlock,
2048                                                              ir::FunctionSignature(nullptr, std::move(params), nullptr),
2049                                                              ir::ScriptFunctionFlags::ARROW});
2050     funcNode->SetScope(funcScope);
2051     funcScope->BindNode(funcNode);
2052     funcParamScope->BindNode(funcNode);
2053 
2054     trailingBlock->SetScope(funcScope);
2055     ReplaceScope(funcNode->Body(), trailingBlock, funcScope);
2056     callExpr->SetTrailingBlock(nullptr);
2057 
2058     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2059     auto *arrowFuncNode = AllocNode<ir::ArrowFunctionExpression>(funcNode);
2060     arrowFuncNode->SetRange(trailingBlock->Range());
2061     arrowFuncNode->SetParent(callExpr);
2062 
2063     callExpr->Arguments().push_back(arrowFuncNode);
2064 }
2065 
ExtendArgumentsWithFakeLamda(ir::CallExpression *callExpr)2066 ArenaVector<ir::Expression *> ETSChecker::ExtendArgumentsWithFakeLamda(ir::CallExpression *callExpr)
2067 {
2068     auto funcCtx = varbinder::LexicalScope<varbinder::FunctionScope>(VarBinder());
2069     auto *funcScope = funcCtx.GetScope();
2070     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
2071 
2072     ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
2073     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2074     auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
2075     body->SetScope(funcScope);
2076 
2077     auto *funcNode = AllocNode<ir::ScriptFunction>(
2078         Allocator(),
2079         ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr),
2080                                                 ir::ScriptFunctionFlags::ARROW});
2081     funcNode->SetScope(funcScope);
2082     funcScope->BindNode(funcNode);
2083     auto *arrowFuncNode = AllocNode<ir::ArrowFunctionExpression>(funcNode);
2084     arrowFuncNode->SetParent(callExpr);
2085 
2086     ArenaVector<ir::Expression *> fakeArguments = callExpr->Arguments();
2087     fakeArguments.push_back(arrowFuncNode);
2088     return fakeArguments;
2089 }
2090 
EnsureValidCurlyBrace(ir::CallExpression *callExpr)2091 void ETSChecker::EnsureValidCurlyBrace(ir::CallExpression *callExpr)
2092 {
2093     if (callExpr->TrailingBlock() == nullptr) {
2094         return;
2095     }
2096 
2097     if (callExpr->IsTrailingBlockInNewLine()) {
2098         MoveTrailingBlockToEnclosingBlockStatement(callExpr);
2099         return;
2100     }
2101 
2102     LogTypeError({"No matching call signature with trailing lambda"}, callExpr->Start());
2103 }
2104 
GetCachedFunctionalInterface(ir::ETSFunctionType *type)2105 ETSObjectType *ETSChecker::GetCachedFunctionalInterface(ir::ETSFunctionType *type)
2106 {
2107     auto hash = GetHashFromFunctionType(type);
2108     auto it = functionalInterfaceCache_.find(hash);
2109     if (it == functionalInterfaceCache_.cend()) {
2110         return nullptr;
2111     }
2112     return it->second;
2113 }
2114 
CacheFunctionalInterface(ir::ETSFunctionType *type, ETSObjectType *ifaceType)2115 void ETSChecker::CacheFunctionalInterface(ir::ETSFunctionType *type, ETSObjectType *ifaceType)
2116 {
2117     auto hash = GetHashFromFunctionType(type);
2118     ASSERT(functionalInterfaceCache_.find(hash) == functionalInterfaceCache_.cend());
2119     functionalInterfaceCache_.emplace(hash, ifaceType);
2120 }
2121 
CollectReturnStatements(ir::AstNode *parent)2122 void ETSChecker::CollectReturnStatements(ir::AstNode *parent)
2123 {
2124     parent->Iterate([this](ir::AstNode *childNode) -> void {
2125         if (childNode->IsScriptFunction()) {
2126             return;
2127         }
2128 
2129         if (childNode->IsReturnStatement()) {
2130             ir::ReturnStatement *returnStmt = childNode->AsReturnStatement();
2131             returnStmt->Check(this);
2132         }
2133 
2134         CollectReturnStatements(childNode);
2135     });
2136 }
2137 
PendingConstraintCheckRecords()2138 ArenaVector<ConstraintCheckRecord> &ETSChecker::PendingConstraintCheckRecords()
2139 {
2140     return pendingConstraintCheckRecords_;
2141 }
2142 
ConstraintCheckScopesCount()2143 size_t &ETSChecker::ConstraintCheckScopesCount()
2144 {
2145     return constraintCheckScopesCount_;
2146 }
2147 
2148 bool ETSChecker::CmpAssemblerTypesWithRank(Signature const *const sig1, Signature const *const sig2) noexcept
2149 {
2150     for (size_t ix = 0; ix < sig1->MinArgCount(); ix++) {
2151         std::stringstream s1;
2152         std::stringstream s2;
2153         sig1->Params()[ix]->TsType()->ToAssemblerTypeWithRank(s1);
2154         sig2->Params()[ix]->TsType()->ToAssemblerTypeWithRank(s2);
2155         if (s1.str() != s2.str()) {
2156             return false;
2157             break;
2158         }
2159     }
2160     return true;
2161 }
2162 
2163 bool ETSChecker::HasSameAssemblySignature(Signature const *const sig1, Signature const *const sig2) noexcept
2164 {
2165     if (sig1->MinArgCount() != sig2->MinArgCount()) {
2166         return false;
2167     }
2168 
2169     if (!CmpAssemblerTypesWithRank(sig1, sig2)) {
2170         return false;
2171     }
2172     auto *rv1 = sig1->RestVar();
2173     auto *rv2 = sig2->RestVar();
2174     if (rv1 == nullptr && rv2 == nullptr) {
2175         return true;
2176     }
2177     if (rv1 == nullptr || rv2 == nullptr) {  // exactly one of them is null
2178         return false;
2179     }
2180     std::stringstream s1;
2181     std::stringstream s2;
2182     rv1->TsType()->ToAssemblerTypeWithRank(s1);
2183     rv2->TsType()->ToAssemblerTypeWithRank(s2);
2184     return s1.str() == s2.str();
2185 }
2186 
2187 bool ETSChecker::HasSameAssemblySignatures(ETSFunctionType const *const func1,
2188                                            ETSFunctionType const *const func2) noexcept
2189 {
2190     for (auto const *sig1 : func1->CallSignatures()) {
2191         for (auto const *sig2 : func2->CallSignatures()) {
2192             if (HasSameAssemblySignature(sig1, sig2)) {
2193                 return true;
2194             }
2195         }
2196     }
2197     return false;
2198 }
2199 }  // namespace ark::es2panda::checker
2200