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 ¶ms = 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 ¶ms)
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 *> &¶ms,
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 *> ¶ms, 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