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