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