• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 "checker/types/ets/etsResizableArrayType.h"
17 #include "checker/types/ets/etsTupleType.h"
18 #include "generated/signatures.h"
19 #include "varbinder/ETSBinder.h"
20 #include "checker/ETSchecker.h"
21 #include "checker/ets/function_helpers.h"
22 #include "checker/ets/typeRelationContext.h"
23 #include "checker/types/ets/etsAsyncFuncReturnType.h"
24 #include "checker/types/ets/etsObjectType.h"
25 #include "compiler/lowering/scopesInit/scopesInitPhase.h"
26 #include "ir/base/catchClause.h"
27 #include "ir/base/classDefinition.h"
28 #include "ir/base/classProperty.h"
29 #include "ir/base/methodDefinition.h"
30 #include "ir/base/scriptFunction.h"
31 #include "ir/base/spreadElement.h"
32 #include "ir/ets/etsFunctionType.h"
33 #include "ir/ets/etsParameterExpression.h"
34 #include "ir/ets/etsTypeReference.h"
35 #include "ir/ets/etsTypeReferencePart.h"
36 #include "ir/expressions/arrowFunctionExpression.h"
37 #include "ir/expressions/assignmentExpression.h"
38 #include "ir/expressions/callExpression.h"
39 #include "ir/expressions/functionExpression.h"
40 #include "ir/expressions/identifier.h"
41 #include "ir/expressions/memberExpression.h"
42 #include "ir/expressions/objectExpression.h"
43 #include "ir/statements/blockStatement.h"
44 #include "ir/statements/doWhileStatement.h"
45 #include "ir/statements/expressionStatement.h"
46 #include "ir/statements/forInStatement.h"
47 #include "ir/statements/forOfStatement.h"
48 #include "ir/statements/forUpdateStatement.h"
49 #include "ir/statements/returnStatement.h"
50 #include "ir/statements/switchStatement.h"
51 #include "ir/statements/whileStatement.h"
52 #include "ir/ts/tsTypeAliasDeclaration.h"
53 #include "ir/ts/tsTypeParameter.h"
54 #include "ir/ts/tsTypeParameterInstantiation.h"
55 #include "parser/program/program.h"
56 #include "util/helpers.h"
57 
58 #include <compiler/lowering/util.h>
59 
60 namespace ark::es2panda::checker {
61 
62 // NOTE: #14993 merge with InstantiationContext::ValidateTypeArg
IsCompatibleTypeArgument(ETSTypeParameter * typeParam,Type * typeArgument,const Substitution * substitution)63 bool ETSChecker::IsCompatibleTypeArgument(ETSTypeParameter *typeParam, Type *typeArgument,
64                                           const Substitution *substitution)
65 {
66     if (typeArgument->IsWildcardType()) {
67         return true;
68     }
69     if (typeArgument->IsTypeError()) {
70         return true;
71     }
72     // NOTE(vpukhov): #19701 void refactoring
73     if (typeArgument->IsETSVoidType()) {
74         typeArgument = GlobalETSUndefinedType();
75     }
76     ES2PANDA_ASSERT(IsReferenceType(typeArgument));
77     auto constraint = typeParam->GetConstraintType()->Substitute(Relation(), substitution);
78     return Relation()->IsSupertypeOf(constraint, typeArgument);
79 }
80 
EnhanceSubstitutionForReadonly(const ArenaVector<Type * > & typeParams,ETSReadonlyType * paramType,Type * argumentType,Substitution * substitution)81 bool ETSChecker::EnhanceSubstitutionForReadonly(const ArenaVector<Type *> &typeParams, ETSReadonlyType *paramType,
82                                                 Type *argumentType, Substitution *substitution)
83 {
84     return EnhanceSubstitutionForType(typeParams, paramType->GetUnderlying(), GetReadonlyType(argumentType),
85                                       substitution);
86 }
87 
88 /* A very rough and imprecise partial type inference */
EnhanceSubstitutionForType(const ArenaVector<Type * > & typeParams,Type * paramType,Type * argumentType,Substitution * substitution)89 bool ETSChecker::EnhanceSubstitutionForType(const ArenaVector<Type *> &typeParams, Type *paramType, Type *argumentType,
90                                             Substitution *substitution)
91 {
92     ES2PANDA_ASSERT(argumentType != nullptr);
93     if (argumentType->IsETSPrimitiveType()) {
94         argumentType = MaybeBoxInRelation(argumentType);
95     }
96     if (paramType->IsETSTypeParameter()) {
97         auto *const tparam = paramType->AsETSTypeParameter();
98         auto *const originalTparam = tparam->GetOriginal();
99         if (std::find(typeParams.begin(), typeParams.end(), originalTparam) != typeParams.end() &&
100             substitution->count(originalTparam) == 0) {
101             if (!IsReferenceType(argumentType)) {
102                 LogError(diagnostic::INFERENCE_TYPE_INCOMPAT, {tparam, argumentType}, tparam->GetDeclNode()->Start());
103                 return false;
104             }
105 
106             // #23068 substitution happens before the constraint check, should be restored
107             EmplaceSubstituted(substitution, originalTparam, argumentType);
108             return IsCompatibleTypeArgument(tparam, argumentType, substitution);
109         }
110     }
111 
112     if (paramType->IsETSFunctionType()) {
113         return EnhanceSubstitutionForFunction(typeParams, paramType->AsETSFunctionType(), argumentType, substitution);
114     }
115     if (paramType->IsETSReadonlyType()) {
116         return EnhanceSubstitutionForReadonly(typeParams, paramType->AsETSReadonlyType(), argumentType, substitution);
117     }
118     if (paramType->IsETSUnionType()) {
119         return EnhanceSubstitutionForUnion(typeParams, paramType->AsETSUnionType(), argumentType, substitution);
120     }
121     if (paramType->IsETSResizableArrayType()) {
122         return EnhanceSubstitutionForResizableArray(typeParams, paramType->AsETSResizableArrayType(), argumentType,
123                                                     substitution);
124     }
125     if (paramType->IsETSObjectType()) {
126         return EnhanceSubstitutionForObject(typeParams, paramType->AsETSObjectType(), argumentType, substitution);
127     }
128     if (paramType->IsETSArrayType()) {
129         return EnhanceSubstitutionForArray(typeParams, paramType->AsETSArrayType(), argumentType, substitution);
130     }
131     if (paramType->IsETSFunctionType()) {
132         return EnhanceSubstitutionForFunction(typeParams, paramType->AsETSFunctionType(), argumentType, substitution);
133     }
134 
135     return true;
136 }
137 
ValidateTypeSubstitution(const ArenaVector<Type * > & typeParams,Type * ctype,Type * argumentType,Substitution * substitution)138 bool ETSChecker::ValidateTypeSubstitution(const ArenaVector<Type *> &typeParams, Type *ctype, Type *argumentType,
139                                           Substitution *substitution)
140 {
141     if (!EnhanceSubstitutionForType(typeParams, ctype, argumentType, substitution)) {
142         return false;
143     }
144     return !ctype->IsETSTypeParameter() ||
145            (substitution->count(ctype->AsETSTypeParameter()) > 0 &&
146             Relation()->IsAssignableTo(argumentType, substitution->at(ctype->AsETSTypeParameter())));
147 }
148 
EnhanceSubstitutionForUnion(const ArenaVector<Type * > & typeParams,ETSUnionType * paramUn,Type * argumentType,Substitution * substitution)149 bool ETSChecker::EnhanceSubstitutionForUnion(const ArenaVector<Type *> &typeParams, ETSUnionType *paramUn,
150                                              Type *argumentType, Substitution *substitution)
151 {
152     if (!argumentType->IsETSUnionType()) {
153         bool foundValid = false;
154         for (Type *ctype : paramUn->ConstituentTypes()) {
155             foundValid |= ValidateTypeSubstitution(typeParams, ctype, argumentType, substitution);
156         }
157         return foundValid;
158     }
159     auto *const argUn = argumentType->AsETSUnionType();
160 
161     ArenaVector<Type *> paramWlist(ProgramAllocator()->Adapter());
162     ArenaVector<Type *> argWlist(ProgramAllocator()->Adapter());
163 
164     for (auto *pc : paramUn->ConstituentTypes()) {
165         for (auto *ac : argUn->ConstituentTypes()) {
166             if (ETSChecker::GetOriginalBaseType(pc) != ETSChecker::GetOriginalBaseType(ac)) {
167                 paramWlist.push_back(pc);
168                 argWlist.push_back(ac);
169                 continue;
170             }
171             if (!EnhanceSubstitutionForType(typeParams, pc, ac, substitution)) {
172                 return false;
173             }
174         }
175     }
176     auto *const newArg = CreateETSUnionType(std::move(argWlist));
177 
178     for (auto *pc : paramWlist) {
179         if (!EnhanceSubstitutionForType(typeParams, pc, newArg, substitution)) {
180             return false;
181         }
182     }
183     return true;
184 }
185 
ProcessUntypedParameter(ir::AstNode * declNode,size_t paramIndex,Signature * paramSig,Signature * argSig,Substitution * substitution)186 bool ETSChecker::ProcessUntypedParameter(ir::AstNode *declNode, size_t paramIndex, Signature *paramSig,
187                                          Signature *argSig, Substitution *substitution)
188 {
189     if (!declNode->IsETSParameterExpression() || !HasStatus(CheckerStatus::IN_TYPE_INFER)) {
190         return false;
191     }
192 
193     auto *paramExpr = declNode->AsETSParameterExpression();
194     if (paramExpr->Ident()->TypeAnnotation() != nullptr) {
195         return false;
196     }
197 
198     Type *paramType = paramSig->Params()[paramIndex]->TsType();
199     Type *inferredType = paramType->Substitute(Relation(), substitution);
200 
201     varbinder::Variable *argParam = argSig->Params()[paramIndex];
202     argParam->SetTsType(inferredType);
203     paramExpr->Ident()->SetTsType(inferredType);
204 
205     return true;
206 }
207 
RemoveInvalidTypeMarkers(ir::AstNode * node)208 static void RemoveInvalidTypeMarkers(ir::AstNode *node) noexcept
209 {
210     std::function<void(ir::AstNode *)> doNode = [&](ir::AstNode *nn) {
211         if (nn->IsTyped() && !(nn->IsExpression() && nn->AsExpression()->IsTypeNode()) &&
212             nn->AsTyped()->TsType() != nullptr && nn->AsTyped()->TsType()->IsTypeError()) {
213             nn->AsTyped()->SetTsType(nullptr);
214         }
215         if (nn->IsIdentifier() && nn->AsIdentifier()->TsType() != nullptr &&
216             nn->AsIdentifier()->TsType()->IsTypeError()) {
217             nn->AsIdentifier()->SetVariable(nullptr);
218         }
219         if (!nn->IsETSTypeReference()) {
220             nn->Iterate([&](ir::AstNode *child) { doNode(child); });
221         }
222     };
223 
224     doNode(node);
225 }
226 
ResetInferredNode(ETSChecker * checker)227 static void ResetInferredNode(ETSChecker *checker)
228 {
229     auto relation = checker->Relation();
230     auto resetFuncState = [](ir::ArrowFunctionExpression *expr) {
231         auto *func = expr->Function();
232         func->SetSignature(nullptr);
233         func->ReturnStatements().clear();
234         expr->SetTsType(nullptr);
235     };
236 
237     const bool hasValidNode = relation->GetNode() != nullptr && relation->GetNode()->IsArrowFunctionExpression();
238     if (!checker->HasStatus(CheckerStatus::IN_TYPE_INFER) || !hasValidNode) {
239         return;
240     }
241 
242     auto *arrowFunc = relation->GetNode()->AsArrowFunctionExpression();
243     relation->SetNode(nullptr);
244 
245     RemoveInvalidTypeMarkers(arrowFunc);
246     resetFuncState(arrowFunc);
247     arrowFunc->Check(checker);
248 }
249 
EnhanceSubstitutionForFunction(const ArenaVector<Type * > & typeParams,ETSFunctionType * paramType,Type * argumentType,Substitution * substitution)250 bool ETSChecker::EnhanceSubstitutionForFunction(const ArenaVector<Type *> &typeParams, ETSFunctionType *paramType,
251                                                 Type *argumentType, Substitution *substitution)
252 {
253     auto const enhance = [this, typeParams, substitution](Type *ptype, Type *atype) {
254         return EnhanceSubstitutionForType(typeParams, ptype, atype, substitution);
255     };
256 
257     if (!argumentType->IsETSFunctionType()) {
258         return true;
259     }
260 
261     auto *paramSig = paramType->ArrowSignature();
262     auto *argSig = argumentType->AsETSFunctionType()->ArrowSignature();
263 
264     if (paramSig->MinArgCount() < argSig->MinArgCount()) {
265         return false;
266     }
267 
268     bool res = true;
269     const size_t commonArity = std::min(argSig->ArgCount(), paramSig->ArgCount());
270 
271     for (size_t idx = 0; idx < commonArity; idx++) {
272         auto *declNode = argSig->Params()[idx]->Declaration()->Node();
273         if (ProcessUntypedParameter(declNode, idx, paramSig, argSig, substitution)) {
274             continue;
275         }
276         res &= enhance(paramSig->Params()[idx]->TsType(), argSig->Params()[idx]->TsType());
277     }
278 
279     ResetInferredNode(this);
280 
281     if (argSig->HasRestParameter() && paramSig->HasRestParameter()) {
282         res &= enhance(paramSig->RestVar()->TsType(), argSig->RestVar()->TsType());
283     }
284     res &= enhance(paramSig->ReturnType(), argSig->ReturnType());
285 
286     return res;
287 }
288 
289 // Try to find the base type somewhere in object subtypes. Incomplete, yet safe
FindEnhanceTargetInSupertypes(ETSObjectType * object,ETSObjectType * base)290 static ETSObjectType *FindEnhanceTargetInSupertypes(ETSObjectType *object, ETSObjectType *base)
291 {
292     ES2PANDA_ASSERT(base == base->GetOriginalBaseType());
293     if (object->GetConstOriginalBaseType() == base) {
294         return object;
295     }
296     auto const traverse = [base](ETSObjectType *v) { return FindEnhanceTargetInSupertypes(v, base); };
297 
298     for (auto itf : object->Interfaces()) {
299         auto res = traverse(itf);
300         if (res != nullptr) {
301             return res;
302         }
303     }
304 
305     if (object->SuperType() != nullptr) {
306         auto res = traverse(object->SuperType());
307         if (res != nullptr) {
308             return res;
309         }
310     }
311     return nullptr;
312 }
313 
EnhanceSubstitutionForObject(const ArenaVector<Type * > & typeParams,ETSObjectType * paramType,Type * argumentType,Substitution * substitution)314 bool ETSChecker::EnhanceSubstitutionForObject(const ArenaVector<Type *> &typeParams, ETSObjectType *paramType,
315                                               Type *argumentType, Substitution *substitution)
316 {
317     auto const enhance = [this, typeParams, substitution](Type *ptype, Type *atype) {
318         return EnhanceSubstitutionForType(typeParams, ptype, atype, substitution);
319     };
320 
321     if (!argumentType->IsETSObjectType()) {
322         return true;
323     }
324     auto enhanceType = FindEnhanceTargetInSupertypes(argumentType->AsETSObjectType(), paramType->GetOriginalBaseType());
325     if (enhanceType == nullptr) {
326         return true;
327     }
328     ES2PANDA_ASSERT(enhanceType->GetOriginalBaseType() == paramType->GetOriginalBaseType());
329     bool res = true;
330     for (size_t i = 0; i < enhanceType->TypeArguments().size(); i++) {
331         res &= enhance(paramType->TypeArguments()[i], enhanceType->TypeArguments()[i]);
332     }
333     return res;
334 }
335 
EnhanceSubstitutionForArray(const ArenaVector<Type * > & typeParams,ETSArrayType * const paramType,Type * const argumentType,Substitution * const substitution)336 bool ETSChecker::EnhanceSubstitutionForArray(const ArenaVector<Type *> &typeParams, ETSArrayType *const paramType,
337                                              Type *const argumentType, Substitution *const substitution)
338 {
339     auto *const elementType =
340         argumentType->IsETSArrayType() ? argumentType->AsETSArrayType()->ElementType() : argumentType;
341 
342     return EnhanceSubstitutionForType(typeParams, paramType->ElementType(), elementType, substitution);
343 }
344 
EnhanceSubstitutionForResizableArray(const ArenaVector<Type * > & typeParams,ETSResizableArrayType * const paramType,Type * const argumentType,Substitution * const substitution)345 bool ETSChecker::EnhanceSubstitutionForResizableArray(const ArenaVector<Type *> &typeParams,
346                                                       ETSResizableArrayType *const paramType, Type *const argumentType,
347                                                       Substitution *const substitution)
348 {
349     auto *const elementType =
350         argumentType->IsETSResizableArrayType() ? argumentType->AsETSResizableArrayType()->ElementType() : argumentType;
351 
352     return EnhanceSubstitutionForType(typeParams, paramType->ElementType(), elementType, substitution);
353 }
354 
ValidateParameterlessConstructor(Signature * signature,const lexer::SourcePosition & pos,bool throwError)355 Signature *ETSChecker::ValidateParameterlessConstructor(Signature *signature, const lexer::SourcePosition &pos,
356                                                         bool throwError)
357 {
358     if (signature->MinArgCount() != 0) {
359         if (throwError) {
360             LogError(diagnostic::NO_SUCH_PARAMLESS_CTOR_2, {signature->MinArgCount()}, pos);
361         }
362         return nullptr;
363     }
364     return signature;
365 }
366 
367 // #22952: remove optional arrow leftovers
CheckOptionalLambdaFunction(ir::Expression * argument,Signature * substitutedSig,std::size_t index)368 bool ETSChecker::CheckOptionalLambdaFunction(ir::Expression *argument, Signature *substitutedSig, std::size_t index)
369 {
370     if (argument->IsArrowFunctionExpression()) {
371         auto *const arrowFuncExpr = argument->AsArrowFunctionExpression();
372 
373         if (ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
374             CheckLambdaAssignable(substitutedSig->Function()->Params()[index], lambda)) {
375             return true;
376         }
377     }
378 
379     return false;
380 }
381 
ValidateArgumentAsIdentifier(const ir::Identifier * identifier)382 bool ETSChecker::ValidateArgumentAsIdentifier(const ir::Identifier *identifier)
383 {
384     auto result = Scope()->Find(identifier->Name());
385     return result.variable != nullptr && (result.variable->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE));
386 }
387 
ClearPreferredTypeForArray(checker::ETSChecker * checker,ir::Expression * argument,Type * paramType,TypeRelationFlag flags,bool needRecheck)388 static void ClearPreferredTypeForArray(checker::ETSChecker *checker, ir::Expression *argument, Type *paramType,
389                                        TypeRelationFlag flags, bool needRecheck)
390 {
391     if (argument->IsArrayExpression()) {
392         // fixed array and resizeable array will cause problem here, so clear it.
393         argument->AsArrayExpression()->ClearPreferredType();
394         argument->AsArrayExpression()->SetPreferredTypeBasedOnFuncParam(checker, paramType, flags);
395     } else if (argument->IsETSNewArrayInstanceExpression()) {
396         argument->AsETSNewArrayInstanceExpression()->ClearPreferredType();
397         argument->AsETSNewArrayInstanceExpression()->SetPreferredTypeBasedOnFuncParam(checker, paramType, flags);
398     } else if (argument->IsETSNewMultiDimArrayInstanceExpression()) {
399         argument->AsETSNewMultiDimArrayInstanceExpression()->ClearPreferredType();
400         argument->AsETSNewMultiDimArrayInstanceExpression()->SetPreferredTypeBasedOnFuncParam(checker, paramType,
401                                                                                               flags);
402     } else {
403         return;
404     }
405     if (needRecheck) {
406         argument->Check(checker);
407     }
408 }
409 
410 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP, G.FUD.05) solid logic
ValidateSignatureRequiredParams(Signature * substitutedSig,const ArenaVector<ir::Expression * > & arguments,TypeRelationFlag flags,const std::vector<bool> & argTypeInferenceRequired,bool reportError)411 bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig,
412                                                  const ArenaVector<ir::Expression *> &arguments, TypeRelationFlag flags,
413                                                  const std::vector<bool> &argTypeInferenceRequired, bool reportError)
414 {
415     auto commonArity = std::min(arguments.size(), substitutedSig->ArgCount());
416     if ((flags & TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA) != 0) {
417         if (commonArity == 0) {
418             ES2PANDA_ASSERT(substitutedSig->GetSignatureInfo()->params.empty());
419             return true;
420         }
421         commonArity = commonArity - 1;
422     }
423     for (size_t index = 0; index < commonArity; ++index) {
424         auto &argument = arguments[index];
425 
426         // #22952: infer optional parameter heuristics
427         auto const paramType = GetNonNullishType(substitutedSig->Params()[index]->TsType());
428         if (argument->IsObjectExpression()) {
429             ES2PANDA_ASSERT(paramType != nullptr);
430             if (paramType->IsETSObjectType()) {
431                 // No chance to check the argument at this point
432                 continue;
433             }
434             return false;
435         }
436 
437         if (argument->IsMemberExpression()) {
438             SetArrayPreferredTypeForNestedMemberExpressions(argument->AsMemberExpression(), paramType);
439         } else if (argument->IsSpreadElement()) {
440             if (reportError) {
441                 LogError(diagnostic::SPREAD_ONTO_SINGLE_PARAM, {}, argument->Start());
442             }
443             return false;
444         }
445 
446         if (argTypeInferenceRequired[index]) {
447             ES2PANDA_ASSERT(argument->IsArrowFunctionExpression());
448             // Note: If the signatures are from lambdas, then they have no `Function`.
449             ir::ScriptFunction *const lambda = argument->AsArrowFunctionExpression()->Function();
450             auto targetParm = substitutedSig->GetSignatureInfo()->params[index]->Declaration()->Node();
451             if (CheckLambdaAssignable(targetParm->AsETSParameterExpression(), lambda)) {
452                 continue;
453             }
454             return false;
455         }
456 
457         ClearPreferredTypeForArray(this, argument, paramType, flags, false);
458 
459         if (argument->IsIdentifier() && ValidateArgumentAsIdentifier(argument->AsIdentifier())) {
460             LogError(diagnostic::ARG_IS_CLASS_ID, {}, argument->Start());
461             return false;
462         }
463 
464         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
465         if (!ValidateSignatureInvocationContext(substitutedSig, argument, index, flags)) {
466             return false;
467         }
468     }
469 
470     if ((flags & TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA) != 0 && arguments.back()->IsArrowFunctionExpression()) {
471         ir::ScriptFunction *const lambda = arguments.back()->AsArrowFunctionExpression()->Function();
472         auto targetParm = substitutedSig->GetSignatureInfo()->params.back()->Declaration()->Node();
473         if (!CheckLambdaAssignable(targetParm->AsETSParameterExpression(), lambda)) {
474             return false;
475         }
476     }
477     return true;
478 }
479 
ValidateSignatureInvocationContext(Signature * substitutedSig,ir::Expression * argument,std::size_t index,TypeRelationFlag flags)480 bool ETSChecker::ValidateSignatureInvocationContext(Signature *substitutedSig, ir::Expression *argument,
481                                                     std::size_t index, TypeRelationFlag flags)
482 {
483     Type *targetType = substitutedSig->Params()[index]->TsType();
484     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
485     Type *argumentType = argument->Check(this);
486 
487     flags |= TypeRelationFlag::ONLY_CHECK_WIDENING;
488 
489     auto const invocationCtx =
490         checker::InvocationContext(Relation(), argument, argumentType, targetType, argument->Start(),
491                                    {{diagnostic::TYPE_MISMATCH_AT_IDX, {argumentType, targetType, index + 1}}}, flags);
492 
493     return invocationCtx.IsInvocable() || CheckOptionalLambdaFunction(argument, substitutedSig, index);
494 }
495 
IsValidRestArgument(ir::Expression * const argument,Signature * const substitutedSig,const TypeRelationFlag flags,const std::size_t index)496 bool ETSChecker::IsValidRestArgument(ir::Expression *const argument, Signature *const substitutedSig,
497                                      const TypeRelationFlag flags, const std::size_t index)
498 {
499     if (argument->IsObjectExpression()) {
500         // Object literals should be checked separately afterwards after call resolution
501         return true;
502     }
503     const auto argumentType = argument->Check(this);
504     auto *restParam = substitutedSig->RestVar()->TsType();
505     if (restParam->IsETSTupleType()) {
506         return false;
507     }
508     if (argument->HasAstNodeFlags(ir::AstNodeFlags::RESIZABLE_REST)) {
509         return true;
510     }
511 
512     auto targetType = GetElementTypeOfArray(restParam);
513     if (substitutedSig->OwnerVar() == nullptr) {
514         targetType = MaybeBoxType(targetType);
515     }
516     auto const invocationCtx = checker::InvocationContext(
517         Relation(), argument, argumentType, targetType, argument->Start(),
518         {{diagnostic::REST_PARAM_INCOMPAT_AT, {argumentType, targetType, index + 1}}}, flags);
519 
520     return invocationCtx.IsInvocable();
521 }
522 
ValidateSignatureRestParams(Signature * substitutedSig,const ArenaVector<ir::Expression * > & arguments,TypeRelationFlag flags,bool reportError,const bool unique)523 bool ETSChecker::ValidateSignatureRestParams(Signature *substitutedSig, const ArenaVector<ir::Expression *> &arguments,
524                                              TypeRelationFlag flags, bool reportError,
525                                              [[maybe_unused]] const bool unique)
526 {
527     size_t const argumentCount = arguments.size();
528     auto const commonArity = std::min(substitutedSig->ArgCount(), argumentCount);
529     auto const restCount = argumentCount - commonArity;
530 
531     if (argumentCount == commonArity && substitutedSig->RestVar()->TsType()->IsETSTupleType()) {
532         return false;
533     }
534     for (size_t index = commonArity; index < argumentCount; ++index) {
535         auto &argument = arguments[index];
536 
537         if (!argument->IsSpreadElement()) {
538             if (!IsValidRestArgument(argument, substitutedSig, flags, index)) {
539                 return false;
540             }
541             continue;
542         }
543 
544         if (restCount > 1U) {
545             if (reportError) {
546                 LogError(diagnostic::MULTIPLE_SPREADS, {}, argument->Start());
547             }
548             return false;
549         }
550 
551         auto *const restArgument = argument->AsSpreadElement()->Argument();
552         Type *targetType = substitutedSig->RestVar()->TsType();
553         // backing out of check that results in a signature mismatch would be difficult
554         // so only attempt it if there is only one candidate signature
555         if (restArgument->IsArrayExpression()) {
556             restArgument->AsArrayExpression()->SetPreferredType(targetType);
557         }
558         auto const argumentType = restArgument->Check(this);
559 
560         auto const invocationCtx = checker::InvocationContext(
561             Relation(), restArgument, argumentType, substitutedSig->RestVar()->TsType(), argument->Start(),
562             {{diagnostic::REST_PARAM_INCOMPAT_AT, {argumentType, substitutedSig->RestVar()->TsType(), index + 1}}},
563             flags);
564         if (!invocationCtx.IsInvocable()) {
565             if (restArgument->IsArrayExpression()) {
566                 ModifyPreferredType(restArgument->AsArrayExpression(), nullptr);
567             }
568             return false;
569         }
570     }
571 
572     return true;
573 }
574 
ValidateSignature(std::tuple<Signature *,const ir::TSTypeParameterInstantiation *,TypeRelationFlag> info,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos,const std::vector<bool> & argTypeInferenceRequired,const bool unique)575 Signature *ETSChecker::ValidateSignature(
576     std::tuple<Signature *, const ir::TSTypeParameterInstantiation *, TypeRelationFlag> info,
577     const ArenaVector<ir::Expression *> &arguments, const lexer::SourcePosition &pos,
578     const std::vector<bool> &argTypeInferenceRequired, const bool unique)
579 {
580     auto [baseSignature, typeArguments, flags] = info;
581     // In case of overloads, it is necessary to iterate through the compatible signatures again,
582     // setting the boxing/unboxing flag for the arguments if needed.
583     // So handle substitution arguments only in the case of unique function or collecting signature phase.
584     Signature *const signature =
585         MaybeSubstituteTypeParameters(this, baseSignature, typeArguments, arguments, pos, flags);
586     if (signature == nullptr) {
587         return nullptr;
588     }
589 
590     size_t const argCount = arguments.size();
591     auto const hasRestParameter = signature->RestVar() != nullptr;
592     auto const reportError = (flags & TypeRelationFlag::NO_THROW) == 0;
593     size_t compareCount = argCount;
594     if ((flags & TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA) != 0 && !signature->Params().empty() &&
595         signature->Params().back()->Declaration()->Node()->AsETSParameterExpression()->IsOptional()) {
596         compareCount = compareCount - 1;
597     }
598 
599     if (compareCount < signature->MinArgCount() || (argCount > signature->ArgCount() && !hasRestParameter)) {
600         if (reportError) {
601             LogError(diagnostic::PARAM_COUNT_MISMATCH, {signature->MinArgCount(), argCount}, pos);
602         }
603         return nullptr;
604     }
605 
606     if (argCount > signature->ArgCount() && hasRestParameter && (flags & TypeRelationFlag::IGNORE_REST_PARAM) != 0) {
607         return nullptr;
608     }
609 
610     auto count = std::min(signature->ArgCount(), argCount);
611     // Check all required formal parameter(s) first
612     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
613     if (!ValidateSignatureRequiredParams(signature, arguments, flags, argTypeInferenceRequired, reportError)) {
614         return nullptr;
615     }
616 
617     // Check rest parameter(s) if any exists
618     if (!hasRestParameter || (count >= argCount && !signature->RestVar()->TsType()->IsETSTupleType())) {
619         return signature;
620     }
621     if (!ValidateSignatureRestParams(signature, arguments, flags, reportError, unique)) {
622         return nullptr;
623     }
624 
625     return signature;
626 }
627 
CollectParameterlessConstructor(ArenaVector<Signature * > & signatures,const lexer::SourcePosition & pos)628 Signature *ETSChecker::CollectParameterlessConstructor(ArenaVector<Signature *> &signatures,
629                                                        const lexer::SourcePosition &pos)
630 {
631     // We are able to provide more specific error messages.
632     bool throwError = signatures.size() == 1;
633     for (auto *sig : signatures) {
634         if (auto *concreteSig = ValidateParameterlessConstructor(sig, pos, throwError); concreteSig != nullptr) {
635             return concreteSig;
636         }
637     }
638     LogError(diagnostic::NO_SUCH_PARAMLESS_CTOR, {}, pos);
639     return nullptr;
640 }
641 
IsSignatureAccessible(Signature * sig,ETSObjectType * containingClass,TypeRelation * relation)642 bool IsSignatureAccessible(Signature *sig, ETSObjectType *containingClass, TypeRelation *relation)
643 {
644     // NOTE(vivienvoros): this check can be removed if signature is implicitly declared as public according to the spec.
645     if (!sig->HasSignatureFlag(SignatureFlags::PUBLIC | SignatureFlags::PROTECTED | SignatureFlags::PRIVATE |
646                                SignatureFlags::INTERNAL)) {
647         return true;
648     }
649 
650     // NOTE(vivienvoros): take care of SignatureFlags::INTERNAL and SignatureFlags::INTERNAL_PROTECTED
651     if (sig->HasSignatureFlag(SignatureFlags::INTERNAL) && !sig->HasSignatureFlag(SignatureFlags::PROTECTED)) {
652         return true;
653     }
654 
655     if (sig->HasSignatureFlag(SignatureFlags::PUBLIC) || sig->Owner() == containingClass ||
656         (sig->HasSignatureFlag(SignatureFlags::PROTECTED) && relation->IsSupertypeOf(sig->Owner(), containingClass))) {
657         return true;
658     }
659 
660     return false;
661 }
662 
663 // NOLINTNEXTLINE(readability-magic-numbers)
GetFlagVariants()664 std::array<TypeRelationFlag, 9U> GetFlagVariants()
665 {
666     // NOTE(boglarkahaag): Not in sync with specification, but solves the issues with rest params for now (#17483)
667     return {
668         TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_BOXING |
669             TypeRelationFlag::IGNORE_REST_PARAM | TypeRelationFlag::NO_WIDENING,
670         TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_BOXING,
671         TypeRelationFlag::NO_THROW | TypeRelationFlag::IGNORE_REST_PARAM | TypeRelationFlag::NO_WIDENING,
672         TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_WIDENING,
673         TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING | TypeRelationFlag::NO_UNBOXING |
674             TypeRelationFlag::NO_BOXING | TypeRelationFlag::IGNORE_REST_PARAM,
675         TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING | TypeRelationFlag::NO_UNBOXING |
676             TypeRelationFlag::NO_BOXING,
677         TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING | TypeRelationFlag::IGNORE_REST_PARAM,
678         TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING,
679     };
680 }
681 
CollectSignatures(ArenaVector<Signature * > & signatures,const ir::TSTypeParameterInstantiation * typeArguments,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos,TypeRelationFlag resolveFlags)682 ArenaVector<Signature *> ETSChecker::CollectSignatures(ArenaVector<Signature *> &signatures,
683                                                        const ir::TSTypeParameterInstantiation *typeArguments,
684                                                        const ArenaVector<ir::Expression *> &arguments,
685                                                        const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
686 {
687     ArenaVector<Signature *> compatibleSignatures(ProgramAllocator()->Adapter());
688     std::vector<bool> argTypeInferenceRequired = FindTypeInferenceArguments(arguments);
689     Signature *notVisibleSignature = nullptr;
690 
691     auto collectSignatures = [&](TypeRelationFlag relationFlags) {
692         for (auto *sig : signatures) {
693             if (notVisibleSignature != nullptr &&
694                 !IsSignatureAccessible(sig, Context().ContainingClass(), Relation())) {
695                 continue;
696             }
697             // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
698             auto *concreteSig = ValidateSignature(std::make_tuple(sig, typeArguments, relationFlags), arguments, pos,
699                                                   argTypeInferenceRequired, signatures.size() == 1);
700             if (concreteSig == nullptr) {
701                 continue;
702             }
703             if (notVisibleSignature == nullptr &&
704                 !IsSignatureAccessible(sig, Context().ContainingClass(), Relation())) {
705                 notVisibleSignature = concreteSig;
706             } else {
707                 compatibleSignatures.push_back(concreteSig);
708             }
709         }
710     };
711 
712     // If there's only one signature, we don't need special checks for boxing/unboxing/widening.
713     // We are also able to provide more specific error messages.
714     if (signatures.size() == 1) {
715         TypeRelationFlag flags = TypeRelationFlag::WIDENING | resolveFlags;
716         collectSignatures(flags);
717     } else {
718         for (auto flags : GetFlagVariants()) {
719             flags = flags | resolveFlags;
720             collectSignatures(flags);
721             if (!compatibleSignatures.empty()) {
722                 break;
723             }
724         }
725     }
726 
727     if (compatibleSignatures.empty() && notVisibleSignature != nullptr &&
728         ((resolveFlags & TypeRelationFlag::NO_THROW) == 0)) {
729         LogError(diagnostic::SIG_INVISIBLE, {notVisibleSignature->Function()->Id()->Name(), notVisibleSignature}, pos);
730     }
731     return compatibleSignatures;
732 }
733 
ClearUnboxingFlags(TypeRelation * relation,Signature * sig,ir::Expression * argument,size_t index)734 static void ClearUnboxingFlags(TypeRelation *relation, Signature *sig, ir::Expression *argument, size_t index)
735 {
736     auto identical = relation->IsIdenticalTo(sig->Params()[index]->TsType(), argument->TsType());
737     // NOTE(gaborarontakacs): The unboxing flag, which was added due to overloading, needs to be removed when it's
738     // unnecessary for the most specific signature.
739     // Do not remove the flag for tuples, e.g., `let a = [21 as Number] as [number]`,
740     // because unboxing will be executed later during the function call in this case.
741     // This condition may be removed after refactoring primitive types.
742     if (identical && argument->HasBoxingUnboxingFlags(ir::BoxingUnboxingFlags::UNBOXING_FLAG) &&
743         !(argument->IsMemberExpression() && argument->AsMemberExpression()->Object()->TsType()->IsETSTupleType())) {
744         argument->RemoveBoxingUnboxingFlags(ir::BoxingUnboxingFlags::UNBOXING_FLAG);
745     }
746 }
747 
UpdateArrayArgsAndUnboxingFlags(ETSChecker * checker,Signature * sig,const ArenaVector<ir::Expression * > & arguments)748 static void UpdateArrayArgsAndUnboxingFlags(ETSChecker *checker, Signature *sig,
749                                             const ArenaVector<ir::Expression *> &arguments)
750 {
751     auto const commonArity = std::min(arguments.size(), sig->ArgCount());
752     for (size_t index = 0; index < commonArity; ++index) {
753         auto argument = arguments[index];
754         auto const paramType = checker->GetNonNullishType(sig->Params()[index]->TsType());
755         auto flags = TypeRelationFlag::NO_THROW | TypeRelationFlag::BOXING | TypeRelationFlag::UNBOXING |
756                      TypeRelationFlag::WIDENING;
757         ClearPreferredTypeForArray(checker, argument, paramType, flags, true);
758         ClearUnboxingFlags(checker->Relation(), sig, argument, index);
759     }
760 }
761 
GetMostSpecificSignature(ArenaVector<Signature * > & compatibleSignatures,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos,TypeRelationFlag resolveFlags)762 Signature *ETSChecker::GetMostSpecificSignature(ArenaVector<Signature *> &compatibleSignatures,
763                                                 const ArenaVector<ir::Expression *> &arguments,
764                                                 const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
765 {
766     std::vector<bool> argTypeInferenceRequired = FindTypeInferenceArguments(arguments);
767     Signature *mostSpecificSignature =
768         ChooseMostSpecificSignature(compatibleSignatures, argTypeInferenceRequired, arguments, pos);
769 
770     if (mostSpecificSignature == nullptr) {
771         LogError(diagnostic::AMBIGUOUS_FUNC_REF, {compatibleSignatures.front()->Function()->Id()->Name()}, pos);
772         return nullptr;
773     }
774 
775     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
776     if (!TypeInference(mostSpecificSignature, arguments, resolveFlags)) {
777         return nullptr;
778     }
779 
780     // revalidate signature for arrays
781     UpdateArrayArgsAndUnboxingFlags(this, mostSpecificSignature, arguments);
782 
783     return mostSpecificSignature;
784 }
785 
ThrowSignatureMismatch(ArenaVector<Signature * > & signatures,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos,std::string_view signatureKind)786 void ETSChecker::ThrowSignatureMismatch(ArenaVector<Signature *> &signatures,
787                                         const ArenaVector<ir::Expression *> &arguments,
788                                         const lexer::SourcePosition &pos, std::string_view signatureKind)
789 {
790     if (!arguments.empty() && !signatures.empty()) {
791         std::string msg {};
792         auto someSignature = signatures[0];
793 
794         if (someSignature->HasFunction()) {
795             if (someSignature->Function()->IsConstructor()) {
796                 msg.append(util::Helpers::GetClassDefiniton(someSignature->Function())->InternalName().Mutf8());
797             } else {
798                 msg.append(someSignature->Function()->Id()->Name().Mutf8());
799             }
800         }
801 
802         msg += "(";
803 
804         for (std::size_t index = 0U; index < arguments.size(); ++index) {
805             auto const &argument = arguments[index];
806             Type const *const argumentType = argument->Check(this);
807             if (!argumentType->IsTypeError()) {
808                 msg += argumentType->ToString();
809             } else {
810                 //  NOTE (DZ): extra cases for some specific nodes can be added here (as for 'ArrowFunctionExpression')
811                 msg += argument->ToString();
812             }
813 
814             if (index == arguments.size() - 1U) {
815                 msg += ")";
816                 LogError(diagnostic::NO_MATCHING_SIG, {signatureKind, msg.c_str()}, pos);
817                 return;
818             }
819 
820             msg += ", ";
821         }
822     }
823 
824     LogError(diagnostic::NO_MATCHING_SIG_2, {signatureKind}, pos);
825 }
826 
ValidateSignatures(ArenaVector<Signature * > & signatures,const ir::TSTypeParameterInstantiation * typeArguments,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos,std::string_view signatureKind,TypeRelationFlag resolveFlags)827 Signature *ETSChecker::ValidateSignatures(ArenaVector<Signature *> &signatures,
828                                           const ir::TSTypeParameterInstantiation *typeArguments,
829                                           const ArenaVector<ir::Expression *> &arguments,
830                                           const lexer::SourcePosition &pos, std::string_view signatureKind,
831                                           TypeRelationFlag resolveFlags)
832 {
833     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
834     auto compatibleSignatures = CollectSignatures(signatures, typeArguments, arguments, pos, resolveFlags);
835     if (!compatibleSignatures.empty()) {
836         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
837         return GetMostSpecificSignature(compatibleSignatures, arguments, pos, resolveFlags);
838     }
839 
840     if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0) {
841         ThrowSignatureMismatch(signatures, arguments, pos, signatureKind);
842     }
843 
844     return nullptr;
845 }
846 
FindMostSpecificSignature(const ArenaVector<Signature * > & signatures,const ArenaMultiMap<size_t,Signature * > & bestSignaturesForParameter,size_t paramCount)847 Signature *ETSChecker::FindMostSpecificSignature(const ArenaVector<Signature *> &signatures,
848                                                  const ArenaMultiMap<size_t, Signature *> &bestSignaturesForParameter,
849                                                  size_t paramCount)
850 {
851     auto isMostSpecificForAllParams = [&](const Signature *sig) {
852         for (size_t paramIdx = 0; paramIdx < paramCount; ++paramIdx) {
853             const auto [begin, end] = bestSignaturesForParameter.equal_range(paramIdx);
854             if (std::none_of(begin, end, [sig](auto &entry) { return entry.second == sig; })) {
855                 return false;
856             }
857         }
858         return true;
859     };
860 
861     Signature *result = nullptr;
862     size_t currentMinLength = SIZE_MAX;
863 
864     for (auto *candidate : signatures) {
865         if (!isMostSpecificForAllParams(candidate)) {
866             continue;
867         }
868 
869         const auto candidateLength = candidate->Function()->Params().size();
870         if (candidateLength > currentMinLength && !candidate->HasRestParameter()) {
871             continue;
872         }
873 
874         if (result == nullptr) {
875             result = candidate;  // First valid candidate
876             currentMinLength = result->Function()->Params().size();
877             continue;
878         }
879 
880         const auto currentLength = result->Function()->Params().size();
881         if (candidate->HasRestParameter() && result->HasRestParameter()) {
882             if (result->Owner() == candidate->Owner()) {
883                 result = nullptr;
884             }
885         } else if (candidateLength < currentLength) {
886             result = candidate;  // Shorter parameter count wins
887             currentMinLength = result->Function()->Params().size();
888         } else if (candidateLength == currentLength) {
889             // Ambiguous resolution for same-length params
890             if (result->Owner() == candidate->Owner()) {
891                 result = nullptr;
892             }
893         }
894     }
895 
896     return result;
897 }
898 
GetParatmeterTypeOrRestAtIdx(checker::ETSChecker * checker,Signature * sig,const size_t idx)899 static Type *GetParatmeterTypeOrRestAtIdx(checker::ETSChecker *checker, Signature *sig, const size_t idx)
900 {
901     return idx < sig->ArgCount() ? sig->Params().at(idx)->TsType()
902                                  : checker->GetElementTypeOfArray(sig->RestVar()->TsType());
903 }
904 
InitMostSpecificType(checker::ETSChecker * checker,const ArenaVector<Signature * > & signatures,Type * & mostSpecificType,Signature * & prevSig,const size_t idx)905 static void InitMostSpecificType(checker::ETSChecker *checker, const ArenaVector<Signature *> &signatures,
906                                  [[maybe_unused]] Type *&mostSpecificType, [[maybe_unused]] Signature *&prevSig,
907                                  const size_t idx)
908 {
909     for (auto *sig : signatures) {
910         if (Type *sigType = GetParatmeterTypeOrRestAtIdx(checker, sig, idx);
911             sigType->IsETSObjectType() && !sigType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
912             mostSpecificType = sigType;
913             prevSig = sig;
914             return;
915         }
916     }
917 }
918 
SearchAmongMostSpecificTypes(Type * & mostSpecificType,Signature * & prevSig,std::tuple<const lexer::SourcePosition &,size_t,Signature * > info,bool lookForClassType)919 void ETSChecker::SearchAmongMostSpecificTypes(Type *&mostSpecificType, Signature *&prevSig,
920                                               std::tuple<const lexer::SourcePosition &, size_t, Signature *> info,
921                                               bool lookForClassType)
922 {
923     auto [pos, idx, sig] = info;
924     Type *sigType = GetParatmeterTypeOrRestAtIdx(this, sig, idx);
925     const bool isClassType =
926         sigType->IsETSObjectType() && !sigType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE);
927     if (isClassType == lookForClassType) {
928         if (Relation()->IsIdenticalTo(sigType, mostSpecificType)) {
929             return;
930         }
931         if (Relation()->IsAssignableTo(sigType, mostSpecificType)) {
932             mostSpecificType = sigType;
933             prevSig = sig;
934         } else if (sigType->IsETSObjectType() && mostSpecificType->IsETSObjectType() &&
935                    !Relation()->IsAssignableTo(mostSpecificType, sigType)) {
936             auto funcName = sig->Function()->Id()->Name();
937             LogError(diagnostic::AMBIGUOUS_CALL, {funcName, funcName, funcName, prevSig, funcName, sig}, pos);
938         }
939     }
940 }
941 
CollectSuitableSignaturesForTypeInference(size_t paramIdx,ArenaVector<Signature * > & signatures,ArenaMultiMap<size_t,Signature * > & bestSignaturesForParameter,const ArenaVector<ir::Expression * > & arguments)942 void ETSChecker::CollectSuitableSignaturesForTypeInference(
943     size_t paramIdx, ArenaVector<Signature *> &signatures,
944     ArenaMultiMap<size_t, Signature *> &bestSignaturesForParameter, const ArenaVector<ir::Expression *> &arguments)
945 {
946     // For lambda parameters, attempt to obtain the most matching signature through the number of lambda parameters
947     ES2PANDA_ASSERT(arguments.at(paramIdx)->IsArrowFunctionExpression());
948     [[maybe_unused]] size_t paramCount =
949         arguments.at(paramIdx)->AsArrowFunctionExpression()->Function()->Params().size();
950     size_t minMatchArgCount = SIZE_MAX;
951 
952     for (auto *sig : signatures) {
953         auto *sigParamType = GetNonNullishType(sig->Params().at(paramIdx)->TsType());
954         ES2PANDA_ASSERT(sigParamType != nullptr);
955         if (!sigParamType->IsETSFunctionType()) {
956             continue;
957         }
958 
959         auto sigParamArgCount = sigParamType->AsETSFunctionType()->ArrowSignature()->ArgCount();
960         ES2PANDA_ASSERT(sigParamArgCount >= paramCount);
961 
962         minMatchArgCount = std::min(minMatchArgCount, sigParamArgCount);
963     }
964 
965     for (auto *sig : signatures) {
966         auto *sigParamType = GetNonNullishType(sig->Params().at(paramIdx)->TsType());
967         ES2PANDA_ASSERT(sigParamType != nullptr);
968         if (!sigParamType->IsETSFunctionType()) {
969             continue;
970         }
971 
972         if (sigParamType->AsETSFunctionType()->ArrowSignature()->ArgCount() == minMatchArgCount) {
973             bestSignaturesForParameter.insert({paramIdx, sig});
974         }
975     }
976 
977     if (bestSignaturesForParameter.find(paramIdx) != bestSignaturesForParameter.end()) {
978         return;
979     }
980 
981     for (auto *sig : signatures) {
982         if (paramIdx >= sig->Params().size() || !sig->Params().at(paramIdx)->TsType()->IsETSObjectType() ||
983             !sig->Params().at(paramIdx)->TsType()->AsETSObjectType()->IsGlobalETSObjectType()) {
984             bestSignaturesForParameter.insert({paramIdx, sig});
985         }
986     }
987 }
988 
GetSuitableSignaturesForParameter(const std::vector<bool> & argTypeInferenceRequired,size_t paramCount,ArenaVector<Signature * > & signatures,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos)989 ArenaMultiMap<size_t, Signature *> ETSChecker::GetSuitableSignaturesForParameter(
990     const std::vector<bool> &argTypeInferenceRequired, size_t paramCount, ArenaVector<Signature *> &signatures,
991     const ArenaVector<ir::Expression *> &arguments, const lexer::SourcePosition &pos)
992 {
993     // Collect which signatures are most specific for each parameter.
994     ArenaMultiMap<size_t /* parameter index */, Signature *> bestSignaturesForParameter(ProgramAllocator()->Adapter());
995 
996     const checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(Relation(),
997                                                                           TypeRelationFlag::ONLY_CHECK_WIDENING);
998 
999     for (size_t i = 0; i < paramCount; ++i) {
1000         if (i >= argTypeInferenceRequired.size()) {
1001             for (auto *sig : signatures) {
1002                 bestSignaturesForParameter.insert({i, sig});
1003             }
1004             continue;
1005         }
1006         if (argTypeInferenceRequired[i]) {
1007             CollectSuitableSignaturesForTypeInference(i, signatures, bestSignaturesForParameter, arguments);
1008             continue;
1009         }
1010         // 1st step: check which is the most specific parameter type for i. parameter.
1011         Type *mostSpecificType = signatures.front()->Params().at(i)->TsType();
1012         Signature *prevSig = signatures.front();
1013 
1014         InitMostSpecificType(this, signatures, mostSpecificType, prevSig, i);
1015         for (auto *sig : signatures) {
1016             SearchAmongMostSpecificTypes(mostSpecificType, prevSig, std::make_tuple(pos, i, sig), true);
1017         }
1018         for (auto *sig : signatures) {
1019             SearchAmongMostSpecificTypes(mostSpecificType, prevSig, std::make_tuple(pos, i, sig), false);
1020         }
1021 
1022         for (auto *sig : signatures) {
1023             Type *sigType = GetParatmeterTypeOrRestAtIdx(this, sig, i);
1024             if (Relation()->IsIdenticalTo(sigType, mostSpecificType)) {
1025                 bestSignaturesForParameter.insert({i, sig});
1026             }
1027         }
1028     }
1029     return bestSignaturesForParameter;
1030 }
1031 
ChooseMostSpecificSignature(ArenaVector<Signature * > & signatures,const std::vector<bool> & argTypeInferenceRequired,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos,size_t argumentsSize)1032 Signature *ETSChecker::ChooseMostSpecificSignature(ArenaVector<Signature *> &signatures,
1033                                                    const std::vector<bool> &argTypeInferenceRequired,
1034                                                    const ArenaVector<ir::Expression *> &arguments,
1035                                                    const lexer::SourcePosition &pos, size_t argumentsSize)
1036 {
1037     ES2PANDA_ASSERT(signatures.empty() == false);
1038 
1039     if (signatures.size() == 1) {
1040         return signatures.front();
1041     }
1042 
1043     std::sort(signatures.begin(), signatures.end(),
1044               [](Signature *sig1, Signature *sig2) { return sig1->ArgCount() > sig2->ArgCount(); });
1045 
1046     size_t paramCount = signatures.front()->ArgCount();
1047     if (argumentsSize != ULONG_MAX) {
1048         paramCount = argumentsSize;
1049     }
1050     // Multiple signatures with zero parameter because of inheritance.
1051     // Return the closest one in inheritance chain that is defined at the beginning of the vector.
1052     if (paramCount == 0) {
1053         auto zeroParamSignature = std::find_if(signatures.begin(), signatures.end(),
1054                                                [](auto *signature) { return signature->RestVar() == nullptr; });
1055         // If there is a zero parameter signature, return that
1056         if (zeroParamSignature != signatures.end()) {
1057             return *zeroParamSignature;
1058         }
1059         // If there are multiple rest parameter signatures with different argument types, throw error
1060         if (signatures.size() > 1 &&
1061             std::any_of(signatures.begin(), signatures.end(), [signatures, this](const auto *param) {
1062                 auto left = MaybeBoxType(GetElementTypeOfArray(param->RestVar()->TsType()));
1063                 auto right = MaybeBoxType(GetElementTypeOfArray(signatures.front()->RestVar()->TsType()));
1064                 Relation()->IsIdenticalTo(left, right);
1065                 return !Relation()->IsTrue();
1066             })) {
1067             LogError(diagnostic::AMBIGUOUS_CALL_2, {signatures.front()->Function()->Id()->Name()}, pos);
1068             return nullptr;
1069         }
1070         // Else return the signature with the rest parameter
1071         auto restParamSignature = std::find_if(signatures.begin(), signatures.end(),
1072                                                [](auto *signature) { return signature->RestVar() != nullptr; });
1073         return *restParamSignature;
1074     }
1075 
1076     ArenaMultiMap<size_t /* parameter index */, Signature *> bestSignaturesForParameter =
1077         GetSuitableSignaturesForParameter(argTypeInferenceRequired, paramCount, signatures, arguments, pos);
1078     // Find the signature that are most specific for all parameters.
1079     Signature *mostSpecificSignature = FindMostSpecificSignature(signatures, bestSignaturesForParameter, paramCount);
1080 
1081     return mostSpecificSignature;
1082 }
1083 
IsLastParameterLambdaWithReceiver(Signature * sig)1084 static bool IsLastParameterLambdaWithReceiver(Signature *sig)
1085 {
1086     auto const &params = sig->Function()->Params();
1087 
1088     return !params.empty() && (params.back()->AsETSParameterExpression()->TypeAnnotation() != nullptr) &&
1089            params.back()->AsETSParameterExpression()->TypeAnnotation()->IsETSFunctionType() &&
1090            params.back()->AsETSParameterExpression()->TypeAnnotation()->AsETSFunctionType()->IsExtensionFunction();
1091 }
1092 
ResolvePotentialTrailingLambdaWithReceiver(ir::CallExpression * callExpr,ArenaVector<Signature * > const & signatures,ArenaVector<ir::Expression * > & arguments)1093 Signature *ETSChecker::ResolvePotentialTrailingLambdaWithReceiver(ir::CallExpression *callExpr,
1094                                                                   ArenaVector<Signature *> const &signatures,
1095                                                                   ArenaVector<ir::Expression *> &arguments)
1096 {
1097     auto *trailingLambda = arguments.back()->AsArrowFunctionExpression();
1098     ArenaVector<Signature *> normalSig(ProgramAllocator()->Adapter());
1099     ArenaVector<Signature *> sigContainLambdaWithReceiverAsParam(ProgramAllocator()->Adapter());
1100     Signature *signature = nullptr;
1101     for (auto sig : signatures) {
1102         if (!sig->HasFunction()) {
1103             continue;
1104         }
1105 
1106         if (!IsLastParameterLambdaWithReceiver(sig)) {
1107             normalSig.emplace_back(sig);
1108             continue;
1109         }
1110 
1111         auto *candidateFunctionType =
1112             sig->Function()->Params().back()->AsETSParameterExpression()->TypeAnnotation()->AsETSFunctionType();
1113         auto *currentReceiver = candidateFunctionType->Params()[0];
1114         trailingLambda->Function()->Params().emplace_back(currentReceiver);
1115         sigContainLambdaWithReceiverAsParam.emplace_back(sig);
1116         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1117         signature = ValidateSignatures(sigContainLambdaWithReceiverAsParam, callExpr->TypeParams(), arguments,
1118                                        callExpr->Start(), "call",
1119                                        TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA);
1120         if (signature != nullptr) {
1121             return signature;
1122         }
1123         sigContainLambdaWithReceiverAsParam.clear();
1124         trailingLambda->Function()->Params().clear();
1125     }
1126     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1127     return ValidateSignatures(normalSig, callExpr->TypeParams(), arguments, callExpr->Start(), "call",
1128                               TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA);
1129 }
1130 
UpdateDeclarationFromSignature(ir::CallExpression * expr,checker::Signature * signature)1131 void ETSChecker::UpdateDeclarationFromSignature(ir::CallExpression *expr, checker::Signature *signature)
1132 {
1133     if (signature == nullptr) {
1134         return;
1135     }
1136 
1137     ir::AstNode *callIdentifier = expr->Callee();
1138     while (callIdentifier != nullptr && callIdentifier->IsMemberExpression()) {
1139         callIdentifier = callIdentifier->AsMemberExpression()->Property();
1140     }
1141     if (callIdentifier == nullptr || !callIdentifier->IsIdentifier()) {
1142         return;
1143     }
1144 
1145     auto signatureVar = callIdentifier->Variable();
1146     if (signatureVar == nullptr || !signatureVar->HasFlag(varbinder::VariableFlags::METHOD) ||
1147         !signature->HasFunction() || signature->Function()->IsDynamic()) {
1148         return;
1149     }
1150 
1151     auto sigName = signature->Function()->Id()->Name();
1152     if (callIdentifier->AsIdentifier()->Name() != sigName) {
1153         return;
1154     }
1155 
1156     ir::AstNode *declNode = signature->Function();
1157     while (!declNode->IsMethodDefinition()) {
1158         declNode = declNode->Parent();
1159     }
1160     auto allocator = ProgramAllocator();
1161     auto newDecl = allocator->New<varbinder::FunctionDecl>(allocator, sigName, declNode);
1162     auto newVar = allocator->New<varbinder::LocalVariable>(newDecl, varbinder::VariableFlags::METHOD |
1163                                                                         varbinder::VariableFlags::SYNTHETIC);
1164     callIdentifier->SetVariable(newVar);
1165 }
1166 
ResolveCallExpressionAndTrailingLambda(ArenaVector<Signature * > & signatures,ir::CallExpression * callExpr,const lexer::SourcePosition & pos,const TypeRelationFlag reportFlag)1167 Signature *ETSChecker::ResolveCallExpressionAndTrailingLambda(ArenaVector<Signature *> &signatures,
1168                                                               ir::CallExpression *callExpr,
1169                                                               const lexer::SourcePosition &pos,
1170                                                               const TypeRelationFlag reportFlag)
1171 {
1172     if (callExpr->TrailingBlock() == nullptr) {
1173         auto sig =
1174             // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1175             ValidateSignatures(signatures, callExpr->TypeParams(), callExpr->Arguments(), pos, "call", reportFlag);
1176         UpdateDeclarationFromSignature(callExpr, sig);
1177         return sig;
1178     }
1179 
1180     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1181     auto arguments = ExtendArgumentsWithFakeLamda(callExpr);
1182     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1183     auto sig = ResolvePotentialTrailingLambdaWithReceiver(callExpr, signatures, arguments);
1184     if (sig != nullptr) {
1185         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1186         TransformTraillingLambda(callExpr, sig);
1187         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1188         TrailingLambdaTypeInference(sig, callExpr->Arguments());
1189         UpdateDeclarationFromSignature(callExpr, sig);
1190         callExpr->SetIsTrailingCall(true);
1191         return sig;
1192     }
1193 
1194     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1195     sig = ValidateSignatures(signatures, callExpr->TypeParams(), callExpr->Arguments(), pos, "call", reportFlag);
1196     if (sig != nullptr) {
1197         EnsureValidCurlyBrace(callExpr);
1198     }
1199 
1200     UpdateDeclarationFromSignature(callExpr, sig);
1201     return sig;
1202 }
1203 
ResolveConstructExpression(ETSObjectType * type,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos)1204 Signature *ETSChecker::ResolveConstructExpression(ETSObjectType *type, const ArenaVector<ir::Expression *> &arguments,
1205                                                   const lexer::SourcePosition &pos)
1206 {
1207     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
1208     return ValidateSignatures(type->ConstructSignatures(), nullptr, arguments, pos, "construct");
1209 }
1210 
1211 /*
1212  * Object literals do not get checked in the process of call resolution; we need to check them separately
1213  * afterwards.
1214  */
CheckObjectLiteralArguments(Signature * signature,ArenaVector<ir::Expression * > const & arguments)1215 void ETSChecker::CheckObjectLiteralArguments(Signature *signature, ArenaVector<ir::Expression *> const &arguments)
1216 {
1217     for (uint32_t index = 0; index < arguments.size(); index++) {
1218         if (!arguments[index]->IsObjectExpression()) {
1219             continue;
1220         }
1221 
1222         Type *tp;
1223         if (index >= signature->Params().size()) {
1224             ES2PANDA_ASSERT(signature->RestVar());
1225             // Use element type as rest object literal type
1226             tp = GetElementTypeOfArray(signature->RestVar()->TsType());
1227         } else {
1228             // #22952: infer optional parameter heuristics
1229             tp = GetNonNullishType(signature->Params()[index]->TsType());
1230         }
1231 
1232         arguments[index]->AsObjectExpression()->SetPreferredType(tp);
1233         arguments[index]->Check(this);
1234     }
1235 }
1236 
1237 // Note: this function is extracted to reduce the size of `BuildMethodSignature`
CollectOverload(checker::ETSChecker * checker,ir::MethodDefinition * method,ETSFunctionType * funcType)1238 static bool CollectOverload(checker::ETSChecker *checker, ir::MethodDefinition *method, ETSFunctionType *funcType)
1239 {
1240     ir::OverloadInfo &ldInfo = method->GetOverloadInfo();
1241     ArenaVector<ETSFunctionType *> overloads(checker->ProgramAllocator()->Adapter());
1242 
1243     for (ir::MethodDefinition *const currentFunc : method->Overloads()) {
1244         ldInfo.isDeclare &= currentFunc->IsDeclare();
1245         ES2PANDA_ASSERT(currentFunc->Function() != nullptr);
1246         ES2PANDA_ASSERT(currentFunc->Id() != nullptr);
1247         currentFunc->Function()->Id()->SetVariable(currentFunc->Id()->Variable());
1248         checker->BuildFunctionSignature(currentFunc->Function(), method->IsConstructor());
1249         if (currentFunc->Function()->Signature() == nullptr) {
1250             auto *methodId = method->Id();
1251             ES2PANDA_ASSERT(methodId != nullptr);
1252             methodId->Variable()->SetTsType(checker->GlobalTypeError());
1253             return false;
1254         }
1255         auto *const overloadType = checker->BuildMethodType(currentFunc->Function());
1256         ldInfo.needHelperOverload |=
1257             checker->CheckIdenticalOverloads(funcType, overloadType, currentFunc, ldInfo.isDeclare);
1258 
1259         currentFunc->SetTsType(overloadType);
1260         auto overloadSig = currentFunc->Function()->Signature();
1261         funcType->AddCallSignature(overloadSig);
1262         if (overloadSig->IsExtensionAccessor()) {
1263             funcType->GetExtensionAccessorSigs().emplace_back(overloadSig);
1264         } else if (overloadSig->IsExtensionFunction()) {
1265             funcType->GetExtensionFunctionSigs().emplace_back(overloadSig);
1266         }
1267         overloads.push_back(overloadType);
1268 
1269         ldInfo.minArg = std::min(ldInfo.minArg, currentFunc->Function()->Signature()->MinArgCount());
1270         ldInfo.maxArg = std::max(ldInfo.maxArg, currentFunc->Function()->Signature()->ArgCount());
1271         ldInfo.hasRestVar |= (currentFunc->Function()->Signature()->RestVar() != nullptr);
1272         ldInfo.returnVoid |= currentFunc->Function()->Signature()->ReturnType()->IsETSVoidType();
1273     }
1274 
1275     for (size_t baseFuncCounter = 0; baseFuncCounter < overloads.size(); ++baseFuncCounter) {
1276         auto *overloadType = overloads.at(baseFuncCounter);
1277         for (size_t compareFuncCounter = baseFuncCounter + 1; compareFuncCounter < overloads.size();
1278              compareFuncCounter++) {
1279             auto *compareOverloadType = overloads.at(compareFuncCounter);
1280             ldInfo.needHelperOverload |= checker->CheckIdenticalOverloads(
1281                 overloadType, compareOverloadType, method->Overloads()[compareFuncCounter], ldInfo.isDeclare);
1282         }
1283     }
1284     return true;
1285 }
1286 
BuildMethodSignature(ir::MethodDefinition * method)1287 checker::Type *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method)
1288 {
1289     if (method->TsType() != nullptr) {
1290         return method->TsType()->AsETSFunctionType();
1291     }
1292     auto *methodId = method->Id();
1293     ES2PANDA_ASSERT(methodId != nullptr);
1294     ES2PANDA_ASSERT(method->Function() != nullptr);
1295     method->Function()->Id()->SetVariable(methodId->Variable());
1296     BuildFunctionSignature(method->Function(), method->IsConstructor());
1297     if (method->Function()->Signature() == nullptr) {
1298         return methodId->Variable()->SetTsType(GlobalTypeError());
1299     }
1300     auto *funcType = BuildMethodType(method->Function());
1301     method->InitializeOverloadInfo();
1302     if (!CollectOverload(this, method, funcType)) {
1303         return GlobalTypeError();
1304     }
1305     ir::OverloadInfo &ldInfo = method->GetOverloadInfo();
1306 
1307     ldInfo.needHelperOverload &= ldInfo.isDeclare;
1308     if (ldInfo.needHelperOverload) {
1309         LogDiagnostic(diagnostic::FUNCTION_ASM_SIG_COLLISION, {std::string(funcType->Name())}, method->Start());
1310     }
1311 
1312     return methodId->Variable()->SetTsType(funcType);
1313 }
1314 
CheckIdenticalOverloads(ETSFunctionType * func,ETSFunctionType * overload,const ir::MethodDefinition * const currentFunc,bool omitSameAsm)1315 bool ETSChecker::CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload,
1316                                          const ir::MethodDefinition *const currentFunc, bool omitSameAsm)
1317 {
1318     // Don't necessary to check overload for invalid functions
1319     if (func->Name().Is(ERROR_LITERAL)) {
1320         ES2PANDA_ASSERT(IsAnyError());
1321         return false;
1322     }
1323 
1324     SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK);
1325 
1326     Relation()->SignatureIsIdenticalTo(func->CallSignatures()[0], overload->CallSignatures()[0]);
1327     if (Relation()->IsTrue() && func->CallSignatures()[0]->GetSignatureInfo()->restVar ==
1328                                     overload->CallSignatures()[0]->GetSignatureInfo()->restVar) {
1329         LogError(diagnostic::FUNCTION_REDECL_BY_TYPE_SIG, {func->Name().Mutf8()}, currentFunc->Start());
1330         return false;
1331     }
1332 
1333     if (!HasSameAssemblySignatures(func, overload)) {
1334         return false;
1335     }
1336 
1337     if (!omitSameAsm) {
1338         LogError(diagnostic::FUNCTION_REDECL_BY_ASM_SIG, {func->Name().Mutf8()}, currentFunc->Start());
1339         return false;
1340     }
1341 
1342     func->CallSignatures()[0]->AddSignatureFlag(SignatureFlags::DUPLICATE_ASM);
1343     overload->CallSignatures()[0]->AddSignatureFlag(SignatureFlags::DUPLICATE_ASM);
1344 
1345     return true;
1346 }
1347 
ComposeSignature(ir::ScriptFunction * func,SignatureInfo * signatureInfo,Type * returnType,varbinder::Variable * nameVar)1348 Signature *ETSChecker::ComposeSignature(ir::ScriptFunction *func, SignatureInfo *signatureInfo, Type *returnType,
1349                                         varbinder::Variable *nameVar)
1350 {
1351     auto *signature = CreateSignature(signatureInfo, returnType, func);
1352     if (signature == nullptr) {  // #23134
1353         ES2PANDA_ASSERT(IsAnyError());
1354         return nullptr;
1355     }
1356     signature->SetOwner(Context().ContainingClass());
1357     signature->SetOwnerVar(nameVar);
1358 
1359     const auto *returnTypeAnnotation = func->ReturnTypeAnnotation();
1360     if (returnTypeAnnotation == nullptr && ((func->Flags() & ir::ScriptFunctionFlags::HAS_RETURN) != 0)) {
1361         signature->AddSignatureFlag(SignatureFlags::NEED_RETURN_TYPE);
1362     }
1363 
1364     if (returnTypeAnnotation != nullptr && returnTypeAnnotation->IsTSThisType()) {
1365         // #22951: the original signature retains the arbitrary this type
1366         // (sometimes ETSGLOBAL). should be resolved woth proper `this` functions support
1367         signature->AddSignatureFlag(SignatureFlags::THIS_RETURN_TYPE);
1368     }
1369 
1370     if (signature->Owner() != nullptr && signature->Owner()->GetDeclNode()->IsFinal()) {
1371         signature->AddSignatureFlag(SignatureFlags::FINAL);
1372     }
1373     return signature;
1374 }
1375 
ComposeReturnType(ir::TypeNode * typeAnnotation,bool isAsync)1376 Type *ETSChecker::ComposeReturnType(ir::TypeNode *typeAnnotation, bool isAsync)
1377 {
1378     if (typeAnnotation != nullptr) {
1379         return typeAnnotation->GetType(this);
1380     }
1381     return isAsync ? CreatePromiseOf(GlobalVoidType()) : GlobalVoidType();
1382 }
1383 
SetupSignatureParameter(ir::ETSParameterExpression * param,Type * type)1384 static varbinder::LocalVariable *SetupSignatureParameter(ir::ETSParameterExpression *param, Type *type)
1385 {
1386     auto *const variable = param->Ident()->Variable();  // #23134
1387     if (variable == nullptr) {
1388         return nullptr;
1389     }
1390     param->Ident()->SetTsType(type);
1391     variable->SetTsType(type);
1392     return variable->AsLocalVariable();
1393 }
1394 
1395 // Should be moved to original ComposeSignatureInfo after AST fix
AppendSignatureInfoParam(ETSChecker * checker,SignatureInfo * sigInfo,ir::ETSParameterExpression * param)1396 static bool AppendSignatureInfoParam(ETSChecker *checker, SignatureInfo *sigInfo, ir::ETSParameterExpression *param)
1397 {
1398     auto variable = SetupSignatureParameter(param, [checker, param]() {
1399         if (param->TypeAnnotation() != nullptr) {
1400             auto type = param->TypeAnnotation()->GetType(checker);
1401             return param->IsOptional() ? checker->CreateETSUnionType({type, checker->GlobalETSUndefinedType()}) : type;
1402         }
1403         if (param->Ident()->TsType() != nullptr) {
1404             return param->Ident()->TsType();
1405         }
1406 
1407         if (!param->Ident()->IsErrorPlaceHolder() && !checker->HasStatus(checker::CheckerStatus::IN_TYPE_INFER)) {
1408             checker->LogError(diagnostic::INFER_FAILURE_FUNC_PARAM, {param->Ident()->Name()}, param->Start());
1409         }
1410 
1411         return checker->GlobalTypeError();
1412     }());
1413     if (variable == nullptr) {  // #23134
1414         return false;
1415     }
1416     if (param->IsRestParameter()) {
1417         return true;
1418     }
1419 
1420     sigInfo->params.push_back(variable);
1421     if (!param->IsOptional()) {
1422         ++sigInfo->minArgCount;
1423     }
1424     ES2PANDA_ASSERT(!param->IsOptional() || param->Ident()->TsType()->IsTypeError() ||
1425                     checker->Relation()->IsSupertypeOf(param->Ident()->TsType(), checker->GlobalETSUndefinedType()));
1426     return true;
1427 }
1428 
ComposeSignatureInfo(ir::TSTypeParameterDeclaration * typeParams,ArenaVector<ir::Expression * > const & params)1429 SignatureInfo *ETSChecker::ComposeSignatureInfo(ir::TSTypeParameterDeclaration *typeParams,
1430                                                 ArenaVector<ir::Expression *> const &params)
1431 {
1432     auto *const signatureInfo = CreateSignatureInfo();
1433 
1434     if (typeParams != nullptr) {
1435         auto [typeParamTypes, ok] = CreateUnconstrainedTypeParameters(typeParams);
1436         ES2PANDA_ASSERT(signatureInfo != nullptr);
1437         signatureInfo->typeParams = std::move(typeParamTypes);
1438         if (ok) {
1439             AssignTypeParameterConstraints(typeParams);
1440         }
1441     }
1442 
1443     for (auto *const p : params) {
1444         if (!p->IsETSParameterExpression() ||
1445             !AppendSignatureInfoParam(this, signatureInfo, p->AsETSParameterExpression())) {  // #23134
1446             ES2PANDA_ASSERT(IsAnyError());
1447             return nullptr;
1448         }
1449     }
1450 
1451     if (!params.empty()) {
1452         if (auto param = params.back()->AsETSParameterExpression(); param->IsRestParameter()) {
1453             checker::Type *restParamType = nullptr;
1454             if (param->TypeAnnotation() != nullptr) {
1455                 restParamType = param->RestParameter()->TypeAnnotation()->GetType(this);
1456             } else if (param->Ident()->TsType() != nullptr) {
1457                 restParamType = param->Ident()->TsType();
1458             } else {
1459                 ES2PANDA_ASSERT(IsAnyError());  // #23134
1460                 return nullptr;
1461             }
1462             ES2PANDA_ASSERT(restParamType != nullptr);
1463             if (!restParamType->IsETSTupleType() && !restParamType->IsETSArrayType() &&
1464                 !restParamType->IsETSResizableArrayType()) {
1465                 LogError(diagnostic::ONLY_ARRAY_OR_TUPLE_FOR_REST, {}, param->Start());
1466                 return nullptr;
1467             }
1468             signatureInfo->restVar = SetupSignatureParameter(param, restParamType);
1469             ES2PANDA_ASSERT(signatureInfo->restVar != nullptr);
1470         }
1471     }
1472 
1473     return signatureInfo;
1474 }
1475 
ValidateMainSignature(ir::ScriptFunction * func)1476 void ETSChecker::ValidateMainSignature(ir::ScriptFunction *func)
1477 {
1478     if (func->Params().size() >= 2U) {
1479         LogError(diagnostic::MAIN_INVALID_ARG_COUNT, {}, func->Start());
1480         return;
1481     }
1482 
1483     if (func->Params().size() == 1) {
1484         auto const *const param = func->Params()[0]->AsETSParameterExpression();
1485 
1486         if (param->IsRestParameter()) {
1487             LogError(diagnostic::MAIN_WITH_REST, {}, param->Start());
1488         }
1489 
1490         const auto paramType = param->Variable()->TsType();
1491         if (!paramType->IsETSArrayType() || !paramType->AsETSArrayType()->ElementType()->IsETSStringType()) {
1492             LogError(diagnostic::MAIN_PARAM_NOT_ARR_OF_STRING, {}, param->Start());
1493         }
1494     }
1495 }
1496 
BuildFunctionSignature(ir::ScriptFunction * func,bool isConstructSig)1497 void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig)
1498 {
1499     ES2PANDA_ASSERT(func != nullptr);
1500     bool isArrow = func->IsArrow();
1501     auto *nameVar = isArrow ? nullptr : func->Id()->Variable();
1502     auto funcName = nameVar == nullptr ? util::StringView() : nameVar->Name();
1503 
1504     if (func->IsConstructor() && func->IsStatic()) {
1505         LogError(diagnostic::INVALID_DECORATOR_CONSTRUCTOR, {}, func->Start());
1506         return;
1507     }
1508 
1509     if ((func->IsConstructor() || !func->IsStatic()) && !func->IsArrow()) {
1510         auto thisVar = func->Scope()->ParamScope()->Params().front();
1511         thisVar->SetTsType(Context().ContainingClass());
1512     }
1513     auto *signatureInfo = ComposeSignatureInfo(func->TypeParams(), func->Params());
1514     auto *returnType = func->GetPreferredReturnType() != nullptr
1515                            ? func->GetPreferredReturnType()
1516                            : ComposeReturnType(func->ReturnTypeAnnotation(), func->IsAsyncFunc());
1517     auto *signature = ComposeSignature(func, signatureInfo, returnType, nameVar);
1518     if (signature == nullptr) {  // #23134
1519         ES2PANDA_ASSERT(IsAnyError());
1520         return;
1521     }
1522 
1523     func->SetSignature(signature);
1524 
1525     if (isConstructSig) {
1526         signature->AddSignatureFlag(SignatureFlags::CONSTRUCT);
1527     } else {
1528         signature->AddSignatureFlag(SignatureFlags::CALL);
1529     }
1530 
1531     if (funcName.Is(compiler::Signatures::MAIN) &&
1532         func->Scope()->Name().Utf8().find(compiler::Signatures::ETS_GLOBAL) != std::string::npos) {
1533         func->AddFlag(ir::ScriptFunctionFlags::ENTRY_POINT);
1534     }
1535     if (func->IsEntryPoint()) {
1536         ValidateMainSignature(func);
1537     }
1538 
1539     VarBinder()->AsETSBinder()->BuildFunctionName(func);
1540     Program()->AddToFunctionScopes(func->Scope());
1541 }
1542 
BuildMethodType(ir::ScriptFunction * func)1543 checker::ETSFunctionType *ETSChecker::BuildMethodType(ir::ScriptFunction *func)
1544 {
1545     ES2PANDA_ASSERT(!func->IsArrow());
1546     ES2PANDA_ASSERT(func != nullptr);
1547     auto *nameVar = func->Id()->Variable();
1548     ETSFunctionType *funcType;
1549     if (func->IsDynamic()) {
1550         funcType = CreateETSDynamicMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()},
1551                                               func->Language());
1552     } else {
1553         funcType = CreateETSMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()});
1554     }
1555     funcType->SetVariable(nameVar);
1556     return funcType;
1557 }
1558 
CheckEveryAbstractSignatureIsOverridden(ETSFunctionType * target,ETSFunctionType * source)1559 Signature *ETSChecker::CheckEveryAbstractSignatureIsOverridden(ETSFunctionType *target, ETSFunctionType *source)
1560 {
1561     for (auto targetSig = target->CallSignatures().begin(); targetSig != target->CallSignatures().end();) {
1562         if (!(*targetSig)->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
1563             continue;
1564         }
1565 
1566         bool isOverridden = false;
1567         for (auto sourceSig : source->CallSignatures()) {
1568             if ((*targetSig)->Function()->Id()->Name() == sourceSig->Function()->Id()->Name() &&
1569                 Relation()->SignatureIsSupertypeOf(*targetSig, sourceSig)) {
1570                 targetSig = target->CallSignatures().erase(targetSig);
1571                 isOverridden = true;
1572                 break;
1573             }
1574             sourceSig++;
1575         }
1576 
1577         if (!isOverridden) {
1578             return *targetSig;
1579         }
1580     }
1581 
1582     return nullptr;
1583 }
1584 
IsOverridableIn(Signature * signature)1585 bool ETSChecker::IsOverridableIn(Signature *signature)
1586 {
1587     if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) {
1588         return false;
1589     }
1590 
1591     // NOTE: #15095 workaround, separate internal visibility check
1592     if (signature->HasSignatureFlag(SignatureFlags::PUBLIC | SignatureFlags::INTERNAL)) {
1593         return true;
1594     }
1595 
1596     return signature->HasSignatureFlag(SignatureFlags::PROTECTED);
1597 }
1598 
IsMethodOverridesOther(Signature * base,Signature * derived)1599 bool ETSChecker::IsMethodOverridesOther(Signature *base, Signature *derived)
1600 {
1601     if (derived->Function()->IsConstructor()) {
1602         return false;
1603     }
1604 
1605     if (base == derived) {
1606         return true;
1607     }
1608 
1609     if (derived->HasSignatureFlag(SignatureFlags::STATIC) != base->HasSignatureFlag(SignatureFlags::STATIC)) {
1610         return false;
1611     }
1612 
1613     if (IsOverridableIn(base)) {
1614         SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK |
1615                                                                     TypeRelationFlag::OVERRIDING_CONTEXT);
1616         if (Relation()->SignatureIsSupertypeOf(base, derived)) {
1617             if (derived->HasSignatureFlag(SignatureFlags::STATIC)) {
1618                 return false;
1619             }
1620 
1621             derived->Function()->SetOverride();
1622             return true;
1623         }
1624     }
1625 
1626     return false;
1627 }
1628 
CheckOverride(Signature * signature,Signature * other)1629 OverrideErrorCode ETSChecker::CheckOverride(Signature *signature, Signature *other)
1630 {
1631     if (other->HasSignatureFlag(SignatureFlags::STATIC)) {
1632         ES2PANDA_ASSERT(signature->HasSignatureFlag(SignatureFlags::STATIC));
1633         return OverrideErrorCode::NO_ERROR;
1634     }
1635 
1636     if (other->IsFinal()) {
1637         return OverrideErrorCode::OVERRIDDEN_FINAL;
1638     }
1639 
1640     auto *ownerNode = signature->Owner()->GetDeclNode();
1641     auto *superNode = other->Owner()->GetDeclNode();
1642     bool bothRealClasses = (ownerNode != nullptr) && ownerNode->IsClassDefinition() && (superNode != nullptr) &&
1643                            superNode->IsClassDefinition() && signature->Owner()->HasObjectFlag(ETSObjectFlags::CLASS) &&
1644                            other->Owner()->HasObjectFlag(ETSObjectFlags::CLASS);
1645     if (bothRealClasses && signature->HasSignatureFlag(SignatureFlags::ABSTRACT) &&
1646         !other->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
1647         return OverrideErrorCode::ABSTRACT_OVERRIDES_CONCRETE;
1648     }
1649 
1650     if (!other->ReturnType()->IsETSTypeParameter()) {
1651         if (!IsReturnTypeSubstitutable(signature, other)) {
1652             return OverrideErrorCode::INCOMPATIBLE_RETURN;
1653         }
1654     } else {
1655         // We need to have this branch to allow generic overriding of the form:
1656         // foo<T>(x: T): T -> foo<someClass>(x: someClass): someClass
1657         if (!signature->ReturnType()->IsETSReferenceType()) {
1658             return OverrideErrorCode::INCOMPATIBLE_RETURN;
1659         }
1660     }
1661 
1662     if (signature->ProtectionFlag() > other->ProtectionFlag()) {
1663         return OverrideErrorCode::OVERRIDDEN_WEAKER;
1664     }
1665     if (signature->HasProtectionFlagInternal() != other->HasProtectionFlagInternal()) {
1666         return OverrideErrorCode::OVERRIDDEN_INTERNAL;
1667     }
1668 
1669     return OverrideErrorCode::NO_ERROR;
1670 }
1671 
AdjustForTypeParameters(Signature * source,Signature * target)1672 Signature *ETSChecker::AdjustForTypeParameters(Signature *source, Signature *target)
1673 {
1674     auto &sourceTypeParams = source->GetSignatureInfo()->typeParams;
1675     auto &targetTypeParams = target->GetSignatureInfo()->typeParams;
1676     if (sourceTypeParams.size() != targetTypeParams.size()) {
1677         return nullptr;
1678     }
1679     if (sourceTypeParams.empty()) {
1680         return target;
1681     }
1682     auto *substitution = NewSubstitution();
1683     for (size_t ix = 0; ix < sourceTypeParams.size(); ix++) {
1684         if (!targetTypeParams[ix]->IsETSTypeParameter()) {
1685             continue;
1686         }
1687         EmplaceSubstituted(substitution, targetTypeParams[ix]->AsETSTypeParameter(), sourceTypeParams[ix]);
1688     }
1689     return target->Substitute(Relation(), substitution);
1690 }
1691 
ReportOverrideError(Signature * signature,Signature * overriddenSignature,const OverrideErrorCode & errorCode)1692 void ETSChecker::ReportOverrideError(Signature *signature, Signature *overriddenSignature,
1693                                      const OverrideErrorCode &errorCode)
1694 {
1695     const char *reason {};
1696     switch (errorCode) {
1697         case OverrideErrorCode::OVERRIDDEN_FINAL: {
1698             reason = "overridden method is final.";
1699             break;
1700         }
1701         case OverrideErrorCode::INCOMPATIBLE_RETURN: {
1702             reason = "overriding return type is not compatible with the other return type.";
1703             break;
1704         }
1705         case OverrideErrorCode::OVERRIDDEN_WEAKER: {
1706             reason = "overridden method has weaker access privilege.";
1707             break;
1708         }
1709         case OverrideErrorCode::OVERRIDDEN_INTERNAL: {
1710             reason =
1711                 "internal members can only be overridden by internal members, "
1712                 "and non-internal members cannot be overridden by internal members.";
1713             break;
1714         }
1715         case OverrideErrorCode::INCOMPATIBLE_TYPEPARAM: {
1716             reason =
1717                 "overriding type parameter's conatraints are not compatible with type parameter constraints of the "
1718                 "overridden method.";
1719             break;
1720         }
1721         case OverrideErrorCode::ABSTRACT_OVERRIDES_CONCRETE: {
1722             reason = "an abstract method cannot override a non-abstract instance method.";
1723             break;
1724         }
1725         default: {
1726             ES2PANDA_UNREACHABLE();
1727         }
1728     }
1729 
1730     LogError(diagnostic::CANNOT_OVERRIDE,
1731              {signature->Function()->Id()->Name(), signature, signature->Owner(),
1732               overriddenSignature->Function()->Id()->Name(), overriddenSignature, overriddenSignature->Owner(), reason},
1733              signature->Function()->Start());
1734 }
1735 
CheckTypeParameterConstraints(ArenaVector<Type * > typeParamList1,ArenaVector<Type * > typeParamList2,TypeRelation * relation)1736 bool CheckTypeParameterConstraints(ArenaVector<Type *> typeParamList1, ArenaVector<Type *> typeParamList2,
1737                                    TypeRelation *relation)
1738 {
1739     if (!typeParamList1.empty() || !typeParamList2.empty()) {
1740         if (typeParamList1.size() != typeParamList2.size()) {
1741             return false;
1742         }
1743         for (size_t i = 0; i < typeParamList1.size(); i++) {
1744             auto c1 = typeParamList1[i]->AsETSTypeParameter()->GetConstraintType();
1745             auto c2 = typeParamList2[i]->AsETSTypeParameter()->GetConstraintType();
1746             if (!relation->IsSupertypeOf(c1, c2)) {  // contravariance check
1747                 return false;
1748             }
1749         }
1750     }
1751     return true;
1752 }
1753 
CheckOverride(Signature * signature,ETSObjectType * site)1754 bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site)
1755 {
1756     PropertySearchFlags flags =
1757         PropertySearchFlags::SEARCH_METHOD | PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION;
1758     auto *target = site->GetProperty(signature->Function()->Id()->Name(), flags);
1759     bool isOverridingAnySignature = false;
1760 
1761     if (target == nullptr || target->TsType() == nullptr || !target->TsType()->IsETSFunctionType()) {
1762         return isOverridingAnySignature;
1763     }
1764 
1765     for (auto *it : target->TsType()->AsETSFunctionType()->CallSignatures()) {
1766         bool typeParamError = false;
1767         if (!CheckTypeParameterConstraints(signature->TypeParams(), it->TypeParams(), Relation())) {
1768             typeParamError = true;
1769         }
1770 
1771         auto *itSubst = AdjustForTypeParameters(signature, it);
1772 
1773         if (itSubst == nullptr) {
1774             continue;
1775         }
1776 
1777         if (itSubst->HasSignatureFlag(SignatureFlags::ABSTRACT) || site->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
1778             if ((itSubst->Function()->IsSetter() && !signature->Function()->IsSetter()) ||
1779                 (itSubst->Function()->IsGetter() && !signature->Function()->IsGetter())) {
1780                 continue;
1781             }
1782         }
1783 
1784         if (!IsMethodOverridesOther(itSubst, signature)) {
1785             continue;
1786         }
1787 
1788         if (typeParamError) {
1789             ReportOverrideError(signature, it, OverrideErrorCode::INCOMPATIBLE_TYPEPARAM);
1790             return false;
1791         }
1792 
1793         if (auto err = CheckOverride(signature, itSubst); err != OverrideErrorCode::NO_ERROR) {
1794             ReportOverrideError(signature, it, err);
1795             return false;
1796         }
1797 
1798         isOverridingAnySignature = true;
1799     }
1800 
1801     return isOverridingAnySignature;
1802 }
1803 
CheckOverride(Signature * signature)1804 void ETSChecker::CheckOverride(Signature *signature)
1805 {
1806     ES2PANDA_ASSERT(signature != nullptr);
1807     auto *owner = signature->Owner();
1808     ES2PANDA_ASSERT(owner != nullptr);
1809     bool isOverriding = false;
1810 
1811     if (!owner->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE)) {
1812         return;
1813     }
1814 
1815     for (auto *const interface : owner->Interfaces()) {
1816         isOverriding |= CheckInterfaceOverride(this, interface, signature);
1817     }
1818 
1819     ETSObjectType *iter = owner->SuperType();
1820     while (iter != nullptr) {
1821         isOverriding |= CheckOverride(signature, iter);
1822 
1823         for (auto *const interface : iter->Interfaces()) {
1824             isOverriding |= CheckInterfaceOverride(this, interface, signature);
1825         }
1826 
1827         iter = iter->SuperType();
1828     }
1829     lexer::SourcePosition ownerPos = signature->Owner()->GetDeclNode()->Start();
1830     lexer::SourcePosition signaturePos = signature->Function()->Start();
1831     lexer::SourcePosition pos = signaturePos.line == 0 && signaturePos.index == 0 ? ownerPos : signaturePos;
1832     if (!isOverriding && signature->Function()->IsOverride()) {
1833         LogError(diagnostic::OVERRIDE_DOESNT_OVERRIDE,
1834                  {signature->Function()->Id()->Name(), signature, signature->Owner()}, pos);
1835     }
1836 }
1837 
GetSignatureFromMethodDefinition(const ir::MethodDefinition * methodDef)1838 Signature *ETSChecker::GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef)
1839 {
1840     if (methodDef->TsType()->IsTypeError()) {
1841         return nullptr;
1842     }
1843     ES2PANDA_ASSERT_POS(methodDef->TsType() && methodDef->TsType()->IsETSFunctionType(), methodDef->Start());
1844     for (auto *it : methodDef->TsType()->AsETSFunctionType()->CallSignatures()) {
1845         if (it->Function() == methodDef->Function()) {
1846             return it;
1847         }
1848     }
1849 
1850     return nullptr;
1851 }
1852 
NeedToVerifySignatureVisibility(Signature * signature,const lexer::SourcePosition & pos)1853 bool ETSChecker::NeedToVerifySignatureVisibility(Signature *signature, const lexer::SourcePosition &pos)
1854 {
1855     if (signature == nullptr) {
1856         LogError(diagnostic::SIG_UNAVAILABLE, {}, pos);
1857         return false;
1858     }
1859 
1860     return (Context().Status() & CheckerStatus::IGNORE_VISIBILITY) == 0U &&
1861            (signature->HasSignatureFlag(SignatureFlags::PRIVATE) ||
1862             signature->HasSignatureFlag(SignatureFlags::PROTECTED));
1863 }
1864 
ValidateSignatureAccessibility(ETSObjectType * callee,Signature * signature,const lexer::SourcePosition & pos,const MaybeDiagnosticInfo & maybeErrorInfo)1865 void ETSChecker::ValidateSignatureAccessibility(ETSObjectType *callee, Signature *signature,
1866                                                 const lexer::SourcePosition &pos,
1867                                                 const MaybeDiagnosticInfo &maybeErrorInfo)
1868 {
1869     if (!NeedToVerifySignatureVisibility(signature, pos)) {
1870         return;
1871     }
1872     const auto *declNode = callee->GetDeclNode();
1873     auto *containingClass = Context().ContainingClass();
1874     bool isContainingSignatureInherited = containingClass->IsSignatureInherited(signature);
1875     ES2PANDA_ASSERT(declNode && (declNode->IsClassDefinition() || declNode->IsTSInterfaceDeclaration()));
1876 
1877     if (declNode->IsTSInterfaceDeclaration()) {
1878         if (containingClass == declNode->AsTSInterfaceDeclaration()->TsType() && isContainingSignatureInherited) {
1879             return;
1880         }
1881     }
1882     if (containingClass == declNode->AsClassDefinition()->TsType() && isContainingSignatureInherited) {
1883         return;
1884     }
1885 
1886     bool isSignatureInherited = callee->IsSignatureInherited(signature);
1887     const auto *currentOutermost = containingClass->OutermostClass();
1888     if (!signature->HasSignatureFlag(SignatureFlags::PRIVATE) &&
1889         ((signature->HasSignatureFlag(SignatureFlags::PROTECTED) && containingClass->IsDescendantOf(callee)) ||
1890          (currentOutermost != nullptr && currentOutermost == callee->OutermostClass())) &&
1891         isSignatureInherited) {
1892         return;
1893     }
1894 
1895     if (!maybeErrorInfo.has_value()) {
1896         LogError(diagnostic::SIG_INVISIBLE, {signature->Function()->Id()->Name(), signature}, pos);
1897         return;
1898     }
1899     const auto [diagnostic, diagnosticParams] = *maybeErrorInfo;
1900     LogError(diagnostic, diagnosticParams, pos);
1901 }
1902 
CheckCapturedVariable(ir::AstNode * const node,varbinder::Variable * const var)1903 void ETSChecker::CheckCapturedVariable(ir::AstNode *const node, varbinder::Variable *const var)
1904 {
1905     if (node->IsIdentifier()) {
1906         const auto *const parent = node->Parent();
1907 
1908         if (parent->IsUpdateExpression() ||
1909             (parent->IsAssignmentExpression() && parent->AsAssignmentExpression()->Left() == node)) {
1910             const auto *const identNode = node->AsIdentifier();
1911 
1912             const auto *resolved = identNode->Variable();
1913 
1914             if (resolved == nullptr) {
1915                 resolved = FindVariableInFunctionScope(identNode->Name());
1916             }
1917 
1918             if (resolved == nullptr) {
1919                 resolved = FindVariableInGlobal(identNode);
1920             }
1921 
1922             if (resolved == var) {
1923                 // For mutable captured variable [possible] smart-cast is senseless (or even erroneous)
1924                 Context().RemoveSmartCast(var);
1925             }
1926         }
1927     }
1928 
1929     CheckCapturedVariableInSubnodes(node, var);
1930 }
1931 
CheckCapturedVariableInSubnodes(ir::AstNode * node,varbinder::Variable * var)1932 void ETSChecker::CheckCapturedVariableInSubnodes(ir::AstNode *node, varbinder::Variable *var)
1933 {
1934     if (!node->IsClassDefinition()) {
1935         node->Iterate([this, var](ir::AstNode *childNode) { CheckCapturedVariable(childNode, var); });
1936     }
1937 }
1938 
CheckCapturedVariables()1939 void ETSChecker::CheckCapturedVariables()
1940 {
1941     // If we want to capture non constant local variables, we should wrap them in a generic reference class
1942     for (auto [var, _] : Context().CapturedVars()) {
1943         (void)_;
1944         if ((var->Declaration() == nullptr) || var->Declaration()->IsConstDecl() ||
1945             !var->HasFlag(varbinder::VariableFlags::LOCAL) || var->GetScope()->Node()->IsArrowFunctionExpression()) {
1946             continue;
1947         }
1948 
1949         auto *searchNode = var->Declaration()->Node()->Parent();
1950 
1951         if (searchNode->IsVariableDeclarator()) {
1952             searchNode = searchNode->Parent()->Parent();
1953         }
1954 
1955         CheckCapturedVariableInSubnodes(searchNode, var);
1956     }
1957 }
1958 
AreOverrideCompatible(Signature * const s1,Signature * const s2)1959 bool ETSChecker::AreOverrideCompatible(Signature *const s1, Signature *const s2)
1960 {
1961     // Two functions, methods or constructors M and N have the same signature if
1962     // their names and type parameters (if any) are the same, and their formal parameter
1963     // types are also the same (after the formal parameter types of N are adapted to the type parameters of M).
1964     // Signatures s1 and s2 are override-equivalent only if s1 and s2 are the same.
1965     if (s1->Function()->Id()->Name() != s2->Function()->Id()->Name()) {
1966         return false;
1967     }
1968 
1969     SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::OVERRIDING_CONTEXT);
1970     return Relation()->SignatureIsSupertypeOf(s1, s2);
1971 }
1972 
IsReturnTypeSubstitutable(Signature * const s1,Signature * const s2)1973 bool ETSChecker::IsReturnTypeSubstitutable(Signature *const s1, Signature *const s2)
1974 {
1975     if (s2->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) {
1976         s2->Function()->Parent()->Parent()->Check(this);
1977     }
1978     auto *const r1 = s1->ReturnType();
1979     auto *const r2 = s2->ReturnType();
1980 
1981     // A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return
1982     // type R2 if any of the following is true:
1983 
1984     // NOTE(vpukhov): void type leaks into type arguments, so we have to check the original signature if the return type
1985     // is parametrized or not to use a proper subtyping check. To be replaced with IsETSPrimitiveType after #19701.
1986     auto const hasPrimitiveReturnType = [](Signature *s) {
1987         bool origIsRef = s->Function()->Signature()->ReturnType()->IsETSReferenceType();
1988         ES2PANDA_ASSERT_POS(origIsRef == s->ReturnType()->IsETSReferenceType(), s->Function()->Start());
1989         return !origIsRef;
1990     };
1991     // - If R1 is a primitive type then R2 is identical to R1.
1992     if (hasPrimitiveReturnType(s1) || hasPrimitiveReturnType(s2)) {
1993         return Relation()->IsIdenticalTo(r2, r1);
1994     }
1995 
1996     auto const hasThisReturnType = [](Signature *s) {
1997         auto *retAnn = s->Function()->ReturnTypeAnnotation();
1998         return retAnn != nullptr && retAnn->IsTSThisType();
1999     };
2000     // - If S2 is a 'this' type(polymorphic) and S1 must be also 'this'
2001     // If the overridden method (s2) has a 'this' return type, then the overriding method (s1) must also have it.
2002     bool s1HasThisType = hasThisReturnType(s1);
2003     bool s2HasThisType = hasThisReturnType(s2);
2004     if (!s1HasThisType && s2HasThisType) {
2005         return false;
2006     }
2007 
2008     // - If R1 is a reference type then R1, adapted to the type parameters of d2 (link to generic methods), is a
2009     //   subtype of R2.
2010     ES2PANDA_ASSERT(IsReferenceType(r1));
2011     return Relation()->IsSupertypeOf(r2, r1);
2012 }
2013 
GetAsyncImplName(const util::StringView & name)2014 std::string ETSChecker::GetAsyncImplName(const util::StringView &name)
2015 {
2016     std::string implName(name);
2017     implName += "$asyncimpl";
2018     return implName;
2019 }
2020 
GetAsyncImplName(ir::MethodDefinition * asyncMethod)2021 std::string ETSChecker::GetAsyncImplName(ir::MethodDefinition *asyncMethod)
2022 {
2023     ir::ScriptFunction *scriptFunc = asyncMethod->Function();
2024     CHECK_NOT_NULL(scriptFunc);
2025     ir::Identifier *asyncName = scriptFunc->Id();
2026     ES2PANDA_ASSERT_POS(asyncName != nullptr, asyncMethod->Start());
2027     return GetAsyncImplName(asyncName->Name());
2028 }
2029 
IsAsyncImplMethod(ir::MethodDefinition const * method)2030 bool ETSChecker::IsAsyncImplMethod(ir::MethodDefinition const *method)
2031 {
2032     auto methodName = method->Key()->AsIdentifier()->Name().Utf8();
2033     std::string_view asyncSuffix = "$asyncimpl";
2034     if (methodName.size() < asyncSuffix.size()) {
2035         return false;
2036     }
2037     return methodName.substr(methodName.size() - asyncSuffix.size()) == asyncSuffix;
2038 }
2039 
CreateMethod(const util::StringView & name,ir::ModifierFlags modifiers,ir::ScriptFunctionFlags flags,ArenaVector<ir::Expression * > && params,varbinder::FunctionParamScope * paramScope,ir::TypeNode * returnType,ir::AstNode * body)2040 ir::MethodDefinition *ETSChecker::CreateMethod(const util::StringView &name, ir::ModifierFlags modifiers,
2041                                                ir::ScriptFunctionFlags flags, ArenaVector<ir::Expression *> &&params,
2042                                                varbinder::FunctionParamScope *paramScope, ir::TypeNode *returnType,
2043                                                ir::AstNode *body)
2044 {
2045     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2046     auto *nameId = ProgramAllocNode<ir::Identifier>(name, ProgramAllocator());
2047     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2048     auto *scope = ProgramAllocator()->New<varbinder::FunctionScope>(ProgramAllocator(), paramScope);
2049     // clang-format off
2050     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2051     auto *const func = ProgramAllocNode<ir::ScriptFunction>(
2052         ProgramAllocator(), ir::ScriptFunction::ScriptFunctionData {
2053             // CC-OFFNXT(G.FMT.05-CPP) project codestyle clang format off
2054             body, ir::FunctionSignature(nullptr, std::move(params), returnType), flags, modifiers});
2055     // clang-format on
2056     ES2PANDA_ASSERT(func != nullptr);
2057     func->SetScope(scope);
2058     func->SetIdent(nameId);
2059     if (body != nullptr && body->IsBlockStatement()) {
2060         body->AsBlockStatement()->SetScope(scope);
2061     }
2062     ES2PANDA_ASSERT(scope != nullptr);
2063     scope->BindNode(func);
2064     paramScope->BindNode(func);
2065     scope->BindParamScope(paramScope);
2066     paramScope->BindFunctionScope(scope);
2067 
2068     if (!func->IsStatic()) {
2069         auto classDef = VarBinder()->GetScope()->AsClassScope()->Node()->AsClassDefinition();
2070         VarBinder()->AsETSBinder()->AddFunctionThisParam(func);
2071         func->Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS).variable->SetTsType(classDef->TsType());
2072     }
2073 
2074     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2075     auto *funcExpr = ProgramAllocNode<ir::FunctionExpression>(func);
2076     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2077     auto *nameClone = nameId->Clone(ProgramAllocator(), nullptr);
2078     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2079     auto *method = util::NodeAllocator::ForceSetParent<ir::MethodDefinition>(
2080         ProgramAllocator(), ir::MethodDefinitionKind::METHOD, nameClone, funcExpr, modifiers, ProgramAllocator(),
2081         false);
2082 
2083     return method;
2084 }
2085 
CopyParams(const ArenaVector<ir::Expression * > & params,ArenaVector<ir::Expression * > & outParams,ArenaUnorderedMap<varbinder::Variable *,varbinder::Variable * > * paramVarMap)2086 varbinder::FunctionParamScope *ETSChecker::CopyParams(
2087     const ArenaVector<ir::Expression *> &params, ArenaVector<ir::Expression *> &outParams,
2088     ArenaUnorderedMap<varbinder::Variable *, varbinder::Variable *> *paramVarMap)
2089 {
2090     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder());
2091 
2092     for (auto *const it : params) {
2093         auto *const paramOld = it->AsETSParameterExpression();
2094         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2095         auto *typeOld = paramOld->Clone(ProgramAllocator(), paramOld->Parent());
2096         ES2PANDA_ASSERT(typeOld != nullptr);
2097         auto *const paramNew = typeOld->AsETSParameterExpression();
2098 
2099         varbinder::Variable *var = VarBinder()->AddParamDecl(paramNew);
2100         Type *paramType = paramOld->Variable()->TsType();
2101         var->SetTsType(paramType);
2102         var->SetScope(paramCtx.GetScope());
2103 
2104         paramNew->SetVariable(var);
2105         paramNew->SetTsType(paramType);
2106 
2107         if (auto *newTypeAnno = paramNew->TypeAnnotation(); newTypeAnno != nullptr) {
2108             newTypeAnno->SetTsType(paramOld->TypeAnnotation()->TsType());
2109             compiler::InitScopesPhaseETS::RunExternalNode(newTypeAnno, VarBinder()->AsETSBinder());
2110         }
2111 
2112         if (paramVarMap != nullptr) {
2113             paramVarMap->insert({paramOld->Ident()->Variable(), var});
2114         }
2115         outParams.emplace_back(paramNew);
2116     }
2117 
2118     return paramCtx.GetScope();
2119 }
2120 
ReplaceScope(ir::AstNode * root,ir::AstNode * oldNode,varbinder::Scope * newScope)2121 void ETSChecker::ReplaceScope(ir::AstNode *root, ir::AstNode *oldNode, varbinder::Scope *newScope)
2122 {
2123     if (root == nullptr) {
2124         return;
2125     }
2126 
2127     root->Iterate([this, oldNode, newScope](ir::AstNode *child) {
2128         auto *scope = NodeScope(child);
2129         if (scope != nullptr) {
2130             while (scope->Parent() != nullptr && scope->Parent()->Node() != oldNode) {
2131                 scope = scope->Parent();
2132             }
2133             scope->SetParent(newScope);
2134         } else {
2135             ReplaceScope(child, oldNode, newScope);
2136         }
2137     });
2138 }
2139 
MoveTrailingBlockToEnclosingBlockStatement(ir::CallExpression * callExpr)2140 void ETSChecker::MoveTrailingBlockToEnclosingBlockStatement(ir::CallExpression *callExpr)
2141 {
2142     if (callExpr == nullptr) {
2143         return;
2144     }
2145 
2146     ir::AstNode *parent = callExpr->Parent();
2147     ir::AstNode *current = callExpr;
2148     while (parent != nullptr) {
2149         if (!parent->IsBlockStatement()) {
2150             current = parent;
2151             parent = parent->Parent();
2152         } else {
2153             // Collect trailing block, insert it only when block statements traversal ends to avoid order mismatch.
2154             parent->AsBlockStatement()->AddTrailingBlock(current, callExpr->TrailingBlock());
2155             callExpr->TrailingBlock()->SetParent(parent);
2156             callExpr->SetTrailingBlock(nullptr);
2157             break;
2158         }
2159     }
2160 }
2161 
2162 using SFunctionData = ir::ScriptFunction::ScriptFunctionData;
TransformTraillingLambda(ir::CallExpression * callExpr,Signature * sig)2163 void ETSChecker::TransformTraillingLambda(ir::CallExpression *callExpr, Signature *sig)
2164 {
2165     auto *trailingBlock = callExpr->TrailingBlock();
2166     ES2PANDA_ASSERT(trailingBlock != nullptr);
2167 
2168     auto *funcParamScope = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder()).GetScope();
2169     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), funcParamScope, false);
2170 
2171     auto funcCtx = varbinder::LexicalScope<varbinder::FunctionScope>(VarBinder());
2172     auto *funcScope = funcCtx.GetScope();
2173     funcScope->BindParamScope(funcParamScope);
2174     funcParamScope->BindFunctionScope(funcScope);
2175     funcParamScope->SetParent(trailingBlock->Scope()->Parent());
2176 
2177     for (auto [_, var] : trailingBlock->Scope()->Bindings()) {
2178         (void)_;
2179         if (var->GetScope() == trailingBlock->Scope()) {
2180             var->SetScope(funcScope);
2181             funcScope->InsertBinding(var->Name(), var);
2182         }
2183     }
2184 
2185     ArenaVector<ir::Expression *> params(ProgramAllocator()->Adapter());
2186     ir::ScriptFunctionFlags flags = ir::ScriptFunctionFlags::ARROW;
2187     bool trailingLambdaHasReceiver = false;
2188     if (IsLastParameterLambdaWithReceiver(sig)) {
2189         auto *actualLambdaType =
2190             sig->Function()->Params().back()->AsETSParameterExpression()->TypeAnnotation()->AsETSFunctionType();
2191         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2192         auto *receiverOfTrailingBlock =
2193             actualLambdaType->Params()[0]->Clone(ProgramAllocator(), nullptr)->AsExpression();
2194         auto *receiverVar = receiverOfTrailingBlock->AsETSParameterExpression()->Ident()->Variable();
2195         auto *receiverVarClone =
2196             ProgramAllocator()->New<varbinder::LocalVariable>(receiverVar->Declaration(), receiverVar->Flags());
2197         receiverVarClone->SetTsType(receiverVar->TsType());
2198         receiverVarClone->SetScope(funcParamScope);
2199         funcScope->InsertBinding(receiverVarClone->Name(), receiverVarClone);
2200         receiverOfTrailingBlock->AsETSParameterExpression()->Ident()->SetVariable(receiverVarClone);
2201         params.emplace_back(receiverOfTrailingBlock);
2202         trailingLambdaHasReceiver = true;
2203     }
2204     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2205     auto *funcNode = ProgramAllocNode<ir::ScriptFunction>(
2206         ProgramAllocator(),
2207         SFunctionData {trailingBlock,
2208                        ir::FunctionSignature(nullptr, std::move(params), nullptr, trailingLambdaHasReceiver), flags});
2209     funcNode->SetScope(funcScope);
2210     funcScope->BindNode(funcNode);
2211     funcParamScope->BindNode(funcNode);
2212 
2213     trailingBlock->SetScope(funcScope);
2214     ReplaceScope(funcNode->Body(), trailingBlock, funcScope);
2215     callExpr->SetTrailingBlock(nullptr);
2216 
2217     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2218     auto *arrowFuncNode = ProgramAllocNode<ir::ArrowFunctionExpression>(funcNode, ProgramAllocator());
2219     arrowFuncNode->SetRange(trailingBlock->Range());
2220     arrowFuncNode->SetParent(callExpr);
2221     callExpr->Arguments().push_back(arrowFuncNode);
2222 }
2223 
ExtendArgumentsWithFakeLamda(ir::CallExpression * callExpr)2224 ArenaVector<ir::Expression *> ETSChecker::ExtendArgumentsWithFakeLamda(ir::CallExpression *callExpr)
2225 {
2226     auto funcCtx = varbinder::LexicalScope<varbinder::FunctionScope>(VarBinder());
2227     auto *funcScope = funcCtx.GetScope();
2228     ArenaVector<ir::Expression *> params(ProgramAllocator()->Adapter());
2229 
2230     ArenaVector<ir::Statement *> statements(ProgramAllocator()->Adapter());
2231     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2232     auto *body = ProgramAllocNode<ir::BlockStatement>(ProgramAllocator(), std::move(statements));
2233     ES2PANDA_ASSERT(body != nullptr);
2234     body->SetScope(funcScope);
2235 
2236     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2237     auto *funcNode = ProgramAllocNode<ir::ScriptFunction>(
2238         ProgramAllocator(),
2239         ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr),
2240                                                 ir::ScriptFunctionFlags::ARROW});
2241     ES2PANDA_ASSERT(funcNode != nullptr);
2242     funcNode->SetScope(funcScope);
2243     funcScope->BindNode(funcNode);
2244     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2245     auto *arrowFuncNode = ProgramAllocNode<ir::ArrowFunctionExpression>(funcNode, ProgramAllocator());
2246     ES2PANDA_ASSERT(arrowFuncNode != nullptr);
2247     arrowFuncNode->SetParent(callExpr);
2248 
2249     ArenaVector<ir::Expression *> fakeArguments = callExpr->Arguments();
2250     fakeArguments.push_back(arrowFuncNode);
2251     return fakeArguments;
2252 }
2253 
EnsureValidCurlyBrace(ir::CallExpression * callExpr)2254 void ETSChecker::EnsureValidCurlyBrace(ir::CallExpression *callExpr)
2255 {
2256     if (callExpr->TrailingBlock() == nullptr) {
2257         return;
2258     }
2259 
2260     if (callExpr->IsTrailingBlockInNewLine()) {
2261         MoveTrailingBlockToEnclosingBlockStatement(callExpr);
2262         return;
2263     }
2264 
2265     LogError(diagnostic::NO_SUCH_SIG_WITH_TRAILING_LAMBDA, {}, callExpr->Start());
2266 }
2267 
GetCachedFunctionalInterface(ir::ETSFunctionType * type)2268 ETSObjectType *ETSChecker::GetCachedFunctionalInterface(ir::ETSFunctionType *type)
2269 {
2270     auto hash = GetHashFromFunctionType(type);
2271     auto it = functionalInterfaceCache_.find(hash);
2272     if (it == functionalInterfaceCache_.cend()) {
2273         return nullptr;
2274     }
2275     return it->second;
2276 }
2277 
CacheFunctionalInterface(ir::ETSFunctionType * type,ETSObjectType * ifaceType)2278 void ETSChecker::CacheFunctionalInterface(ir::ETSFunctionType *type, ETSObjectType *ifaceType)
2279 {
2280     auto hash = GetHashFromFunctionType(type);
2281     ES2PANDA_ASSERT(functionalInterfaceCache_.find(hash) == functionalInterfaceCache_.cend());
2282     functionalInterfaceCache_.emplace(hash, ifaceType);
2283 }
2284 
CollectReturnStatements(ir::AstNode * parent)2285 void ETSChecker::CollectReturnStatements(ir::AstNode *parent)
2286 {
2287     parent->Iterate([this](ir::AstNode *childNode) -> void {
2288         if (childNode->IsScriptFunction()) {
2289             return;
2290         }
2291 
2292         if (childNode->IsReturnStatement()) {
2293             ir::ReturnStatement *returnStmt = childNode->AsReturnStatement();
2294             returnStmt->Check(this);
2295         }
2296 
2297         CollectReturnStatements(childNode);
2298     });
2299 }
2300 
PendingConstraintCheckRecords()2301 ArenaVector<ConstraintCheckRecord> &ETSChecker::PendingConstraintCheckRecords()
2302 {
2303     return pendingConstraintCheckRecords_;
2304 }
2305 
ConstraintCheckScopesCount()2306 size_t &ETSChecker::ConstraintCheckScopesCount()
2307 {
2308     return constraintCheckScopesCount_;
2309 }
2310 
CmpAssemblerTypesWithRank(Signature const * const sig1,Signature const * const sig2)2311 bool ETSChecker::CmpAssemblerTypesWithRank(Signature const *const sig1, Signature const *const sig2) noexcept
2312 {
2313     for (size_t ix = 0U; ix < sig1->Params().size(); ++ix) {
2314         std::stringstream s1;
2315         std::stringstream s2;
2316         sig1->Params()[ix]->TsType()->ToAssemblerTypeWithRank(s1);
2317         sig2->Params()[ix]->TsType()->ToAssemblerTypeWithRank(s2);
2318         if (s1.str() != s2.str()) {
2319             return false;
2320             break;
2321         }
2322     }
2323     return true;
2324 }
2325 
HasSameAssemblySignature(Signature const * const sig1,Signature const * const sig2)2326 bool ETSChecker::HasSameAssemblySignature(Signature const *const sig1, Signature const *const sig2) noexcept
2327 {
2328     if (sig1->ArgCount() != sig2->ArgCount()) {
2329         return false;
2330     }
2331 
2332     if (!CmpAssemblerTypesWithRank(sig1, sig2)) {
2333         return false;
2334     }
2335     auto *rv1 = sig1->RestVar();
2336     auto *rv2 = sig2->RestVar();
2337     if (rv1 == nullptr && rv2 == nullptr) {
2338         return true;
2339     }
2340     if (rv1 == nullptr || rv2 == nullptr) {  // exactly one of them is null
2341         return false;
2342     }
2343     std::stringstream s1;
2344     std::stringstream s2;
2345     rv1->TsType()->ToAssemblerTypeWithRank(s1);
2346     rv2->TsType()->ToAssemblerTypeWithRank(s2);
2347     return s1.str() == s2.str();
2348 }
2349 
HasSameAssemblySignatures(ETSFunctionType const * const func1,ETSFunctionType const * const func2)2350 bool ETSChecker::HasSameAssemblySignatures(ETSFunctionType const *const func1,
2351                                            ETSFunctionType const *const func2) noexcept
2352 {
2353     for (auto const *sig1 : func1->CallSignatures()) {
2354         for (auto const *sig2 : func2->CallSignatures()) {
2355             if (HasSameAssemblySignature(sig1, sig2)) {
2356                 return true;
2357             }
2358         }
2359     }
2360     return false;
2361 }
2362 
2363 }  // namespace ark::es2panda::checker
2364