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