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