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