• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/varbinder.h"
17 #include "varbinder/declaration.h"
18 #include "varbinder/ETSBinder.h"
19 #include "varbinder/scope.h"
20 #include "varbinder/variable.h"
21 #include "varbinder/variableFlags.h"
22 #include "checker/ETSchecker.h"
23 #include "checker/ets/function_helpers.h"
24 #include "checker/ets/typeRelationContext.h"
25 #include "checker/types/ets/etsAsyncFuncReturnType.h"
26 #include "checker/types/ets/etsObjectType.h"
27 #include "checker/types/type.h"
28 #include "checker/types/typeFlag.h"
29 #include "ir/astNode.h"
30 #include "ir/typeNode.h"
31 #include "ir/base/catchClause.h"
32 #include "ir/base/classDefinition.h"
33 #include "ir/base/classProperty.h"
34 #include "ir/base/methodDefinition.h"
35 #include "ir/base/scriptFunction.h"
36 #include "ir/base/spreadElement.h"
37 #include "ir/ets/etsFunctionType.h"
38 #include "ir/ets/etsParameterExpression.h"
39 #include "ir/ets/etsTypeReference.h"
40 #include "ir/ets/etsTypeReferencePart.h"
41 #include "ir/expressions/arrowFunctionExpression.h"
42 #include "ir/expressions/assignmentExpression.h"
43 #include "ir/expressions/callExpression.h"
44 #include "ir/expressions/functionExpression.h"
45 #include "ir/expressions/identifier.h"
46 #include "ir/expressions/literals/numberLiteral.h"
47 #include "ir/expressions/memberExpression.h"
48 #include "ir/expressions/objectExpression.h"
49 #include "ir/expressions/thisExpression.h"
50 #include "ir/statements/blockStatement.h"
51 #include "ir/statements/doWhileStatement.h"
52 #include "ir/statements/expressionStatement.h"
53 #include "ir/statements/forInStatement.h"
54 #include "ir/statements/forOfStatement.h"
55 #include "ir/statements/forUpdateStatement.h"
56 #include "ir/statements/returnStatement.h"
57 #include "ir/statements/switchStatement.h"
58 #include "ir/statements/whileStatement.h"
59 #include "ir/ts/tsArrayType.h"
60 #include "ir/ts/tsInterfaceBody.h"
61 #include "ir/ts/tsTypeAliasDeclaration.h"
62 #include "ir/ts/tsTypeParameter.h"
63 #include "ir/ts/tsTypeParameterInstantiation.h"
64 #include "parser/program/program.h"
65 #include "util/helpers.h"
66 #include "util/language.h"
67 
68 namespace panda::es2panda::checker {
69 
70 // NOTE: #14993 merge with InstantiationContext::ValidateTypeArg
IsCompatibleTypeArgument(ETSTypeParameter * typeParam,Type * typeArgument,const Substitution * substitution)71 bool ETSChecker::IsCompatibleTypeArgument(ETSTypeParameter *typeParam, Type *typeArgument,
72                                           const Substitution *substitution)
73 {
74     if (typeArgument->IsWildcardType()) {
75         return true;
76     }
77     if (!typeArgument->IsETSTypeParameter() && !IsReferenceType(typeArgument)) {
78         return false;
79     }
80     auto *constraint = typeParam->GetConstraintType()->Substitute(Relation(), substitution);
81     return Relation()->IsSupertypeOf(constraint, typeArgument);
82 }
83 
84 /* A very rough and imprecise partial type inference */
EnhanceSubstitutionForType(const ArenaVector<Type * > & typeParams,Type * paramType,Type * argumentType,Substitution * substitution,ArenaUnorderedSet<ETSTypeParameter * > * instantiatedTypeParams)85 bool ETSChecker::EnhanceSubstitutionForType(const ArenaVector<Type *> &typeParams, Type *paramType, Type *argumentType,
86                                             Substitution *substitution,
87                                             ArenaUnorderedSet<ETSTypeParameter *> *instantiatedTypeParams)
88 {
89     if (paramType->IsETSTypeParameter()) {
90         auto *const tparam = paramType->AsETSTypeParameter();
91         auto *const originalTparam = tparam->GetOriginal();
92         if (instantiatedTypeParams->find(tparam) != instantiatedTypeParams->end() &&
93             substitution->at(originalTparam) != argumentType) {
94             ThrowTypeError({"Type parameter already instantiated with another type "}, tparam->GetDeclNode()->Start());
95         }
96         if (std::find(typeParams.begin(), typeParams.end(), originalTparam) != typeParams.end() &&
97             substitution->count(originalTparam) == 0) {
98             if (!IsCompatibleTypeArgument(tparam, argumentType, substitution)) {
99                 return false;
100             }
101             ETSChecker::EmplaceSubstituted(substitution, originalTparam, argumentType);
102             instantiatedTypeParams->insert(tparam);
103             return true;
104         }
105     }
106 
107     if (paramType->IsETSUnionType()) {
108         auto const &constitutent = paramType->AsETSUnionType()->ConstituentTypes();
109         return std::all_of(constitutent.begin(), constitutent.end(),
110                            [this, typeParams, argumentType, substitution, instantiatedTypeParams](Type *member) {
111                                return EnhanceSubstitutionForType(typeParams, member, argumentType, substitution,
112                                                                  instantiatedTypeParams);
113                            });
114     }
115 
116     if (paramType->IsETSObjectType()) {
117         return EnhanceSubstitutionForObject(typeParams, paramType->AsETSObjectType(), argumentType, substitution,
118                                             instantiatedTypeParams);
119     }
120     return true;
121 }
122 
EnhanceSubstitutionForObject(const ArenaVector<Type * > & typeParams,ETSObjectType * paramType,Type * argumentType,Substitution * substitution,ArenaUnorderedSet<ETSTypeParameter * > * instantiatedTypeParams)123 bool ETSChecker::EnhanceSubstitutionForObject(const ArenaVector<Type *> &typeParams, ETSObjectType *paramType,
124                                               Type *argumentType, Substitution *substitution,
125                                               ArenaUnorderedSet<ETSTypeParameter *> *instantiatedTypeParams)
126 {
127     auto *paramObjType = paramType->AsETSObjectType();
128 
129     auto const enhance = [this, typeParams, substitution, instantiatedTypeParams](Type *ptype, Type *atype) {
130         return EnhanceSubstitutionForType(typeParams, ptype, atype, substitution, instantiatedTypeParams);
131     };
132 
133     if (argumentType->IsETSObjectType()) {
134         auto *argObjType = argumentType->AsETSObjectType();
135         if (GetOriginalBaseType(argObjType) != GetOriginalBaseType(paramObjType)) {
136             return true;  // don't attempt anything fancy for now
137         }
138         bool res = true;
139         for (size_t ix = 0; ix < argObjType->TypeArguments().size(); ix++) {
140             res &= enhance(paramObjType->TypeArguments()[ix], argObjType->TypeArguments()[ix]);
141         }
142         return res;
143     }
144 
145     if (argumentType->IsETSFunctionType() && paramObjType->HasObjectFlag(ETSObjectFlags::FUNCTIONAL_INTERFACE)) {
146         auto &parameterSignatures = paramObjType->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>("invoke")
147                                         ->TsType()
148                                         ->AsETSFunctionType()
149                                         ->CallSignatures();
150         auto &argumentSignatures = argumentType->AsETSFunctionType()->CallSignatures();
151         ASSERT(argumentSignatures.size() == 1);
152         ASSERT(parameterSignatures.size() == 1);
153         bool res = true;
154         for (size_t idx = 0; idx < argumentSignatures[0]->GetSignatureInfo()->params.size(); idx++) {
155             res &= enhance(parameterSignatures[0]->GetSignatureInfo()->params[idx]->TsType(),
156                            argumentSignatures[0]->GetSignatureInfo()->params[idx]->TsType());
157         }
158         res &= enhance(parameterSignatures[0]->ReturnType(), argumentSignatures[0]->ReturnType());
159         return res;
160     }
161 
162     return true;
163 }
164 
165 // NOLINTBEGIN(modernize-avoid-c-arrays)
166 static constexpr char const INVALID_CALL_ARGUMENT_1[] = "Call argument at index ";
167 static constexpr char const INVALID_CALL_ARGUMENT_2[] = " is not compatible with the signature's type at that index.";
168 static constexpr char const INVALID_CALL_ARGUMENT_3[] = " is not compatible with the signature's rest parameter type.";
169 // NOLINTEND(modernize-avoid-c-arrays)
ValidateParameterlessConstructor(Signature * signature,const lexer::SourcePosition & pos,TypeRelationFlag flags)170 Signature *ETSChecker::ValidateParameterlessConstructor(Signature *signature, const lexer::SourcePosition &pos,
171                                                         TypeRelationFlag flags)
172 {
173     std::size_t const parameterCount = signature->MinArgCount();
174     auto const throwError = (flags & TypeRelationFlag::NO_THROW) == 0;
175 
176     if (parameterCount != 0) {
177         if (throwError) {
178             ThrowTypeError({"No Matching Parameterless Constructor, parameter count ", parameterCount}, pos);
179         }
180         return nullptr;
181     }
182     return signature;
183 }
184 
ValidateSignature(Signature * signature,const ir::TSTypeParameterInstantiation * typeArguments,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos,TypeRelationFlag flags,const std::vector<bool> & argTypeInferenceRequired)185 Signature *ETSChecker::ValidateSignature(Signature *signature, const ir::TSTypeParameterInstantiation *typeArguments,
186                                          const ArenaVector<ir::Expression *> &arguments,
187                                          const lexer::SourcePosition &pos, TypeRelationFlag flags,
188                                          const std::vector<bool> &argTypeInferenceRequired)
189 {
190     if (signature->Function()->IsDefaultParamProxy() && ((flags & TypeRelationFlag::CHECK_PROXY) == 0)) {
191         return nullptr;
192     }
193 
194     Signature *substitutedSig = MaybeSubstituteTypeParameters(this, signature, typeArguments, arguments, pos, flags);
195     if (substitutedSig == nullptr) {
196         return nullptr;
197     }
198 
199     auto const hasRestParameter = substitutedSig->RestVar() != nullptr;
200     std::size_t const argumentCount = arguments.size();
201     std::size_t const parameterCount = substitutedSig->MinArgCount();
202     auto const throwError = (flags & TypeRelationFlag::NO_THROW) == 0;
203 
204     if (!signature->Function()->IsDefaultParamProxy()) {
205         if (argumentCount < parameterCount || (argumentCount > parameterCount && !hasRestParameter)) {
206             if (throwError) {
207                 ThrowTypeError({"Expected ", parameterCount, " arguments, got ", argumentCount, "."}, pos);
208             }
209             return nullptr;
210         }
211     }
212 
213     // Check all required formal parameter(s) first
214     auto const count = std::min(parameterCount, argumentCount);
215     std::size_t index = 0U;
216     for (; index < count; ++index) {
217         auto &argument = arguments[index];
218 
219         if (argument->IsObjectExpression()) {
220             if (substitutedSig->Params()[index]->TsType()->IsETSObjectType()) {
221                 // No chance to check the argument at this point
222                 continue;
223             }
224             return nullptr;
225         }
226 
227         if (argument->IsMemberExpression()) {
228             SetArrayPreferredTypeForNestedMemberExpressions(arguments[index]->AsMemberExpression(),
229                                                             substitutedSig->Params()[index]->TsType());
230         } else if (argument->IsSpreadElement()) {
231             if (throwError) {
232                 ThrowTypeError("Spread argument cannot be passed for ordinary parameter.", argument->Start());
233             }
234             return nullptr;
235         }
236 
237         if (argTypeInferenceRequired[index]) {
238             ASSERT(argument->IsArrowFunctionExpression());
239             auto *const arrowFuncExpr = argument->AsArrowFunctionExpression();
240             ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
241             if (CheckLambdaAssignable(substitutedSig->Function()->Params()[index], lambda)) {
242                 continue;
243             }
244             return nullptr;
245         }
246 
247         if (argument->IsArrayExpression()) {
248             argument->AsArrayExpression()->GetPrefferedTypeFromFuncParam(
249                 this, substitutedSig->Function()->Params()[index], flags);
250         }
251 
252         auto *const argumentType = argument->Check(this);
253 
254         if (auto const invocationCtx = checker::InvocationContext(
255                 Relation(), argument, argumentType, substitutedSig->Params()[index]->TsType(), argument->Start(),
256                 {INVALID_CALL_ARGUMENT_1, index, INVALID_CALL_ARGUMENT_2}, flags);
257             !invocationCtx.IsInvocable()) {
258             return nullptr;
259         }
260     }
261 
262     // Check rest parameter(s) if any exists
263     if (hasRestParameter && index < argumentCount) {
264         auto const restCount = argumentCount - index;
265 
266         for (; index < argumentCount; ++index) {
267             auto &argument = arguments[index];
268 
269             if (argument->IsSpreadElement()) {
270                 if (restCount > 1U) {
271                     if (throwError) {
272                         ThrowTypeError("Spread argument for the rest parameter can be only one.", argument->Start());
273                     }
274                     return nullptr;
275                 }
276 
277                 auto *const restArgument = argument->AsSpreadElement()->Argument();
278                 auto *const argumentType = restArgument->Check(this);
279 
280                 if (auto const invocationCtx = checker::InvocationContext(
281                         Relation(), restArgument, argumentType, substitutedSig->RestVar()->TsType(), argument->Start(),
282                         {INVALID_CALL_ARGUMENT_1, index, INVALID_CALL_ARGUMENT_3}, flags);
283                     !invocationCtx.IsInvocable()) {
284                     return nullptr;
285                 }
286             } else {
287                 auto *const argumentType = argument->Check(this);
288 
289                 if (auto const invocationCtx = checker::InvocationContext(
290                         Relation(), argument, argumentType,
291                         substitutedSig->RestVar()->TsType()->AsETSArrayType()->ElementType(), argument->Start(),
292                         {INVALID_CALL_ARGUMENT_1, index, INVALID_CALL_ARGUMENT_3}, flags);
293                     !invocationCtx.IsInvocable()) {
294                     return nullptr;
295                 }
296             }
297         }
298     }
299 
300     return substitutedSig;
301 }
302 
ValidateProxySignature(Signature * const signature,const ir::TSTypeParameterInstantiation * typeArguments,const ArenaVector<ir::Expression * > & arguments,const std::vector<bool> & argTypeInferenceRequired)303 bool ETSChecker::ValidateProxySignature(Signature *const signature,
304                                         const ir::TSTypeParameterInstantiation *typeArguments,
305                                         const ArenaVector<ir::Expression *> &arguments,
306                                         const std::vector<bool> &argTypeInferenceRequired)
307 {
308     if (!signature->Function()->IsDefaultParamProxy()) {
309         return false;
310     }
311 
312     auto const *const proxyParam = signature->Function()->Params().back()->AsETSParameterExpression();
313     if (!proxyParam->Ident()->Name().Is(ir::PROXY_PARAMETER_NAME)) {
314         return false;
315     }
316 
317     if (arguments.size() < proxyParam->GetRequiredParams()) {
318         return false;
319     }
320 
321     return ValidateSignature(signature, typeArguments, arguments, signature->Function()->Start(),
322                              TypeRelationFlag::CHECK_PROXY | TypeRelationFlag::NO_THROW |
323                                  TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_BOXING,
324                              argTypeInferenceRequired) != nullptr;
325 }
326 
CollectParameterlessConstructor(ArenaVector<Signature * > & signatures,const lexer::SourcePosition & pos,TypeRelationFlag resolveFlags)327 Signature *ETSChecker::CollectParameterlessConstructor(ArenaVector<Signature *> &signatures,
328                                                        const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
329 {
330     Signature *compatibleSignature = nullptr;
331 
332     auto collectSignatures = [&](TypeRelationFlag relationFlags) {
333         for (auto *sig : signatures) {
334             if (auto *concreteSig = ValidateParameterlessConstructor(sig, pos, relationFlags); concreteSig != nullptr) {
335                 compatibleSignature = concreteSig;
336                 break;
337             }
338         }
339     };
340 
341     // We are able to provide more specific error messages.
342     if (signatures.size() == 1) {
343         collectSignatures(resolveFlags);
344     } else {
345         collectSignatures(resolveFlags | TypeRelationFlag::NO_THROW);
346     }
347 
348     if (compatibleSignature == nullptr) {
349         if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0) {
350             ThrowTypeError({"No matching parameterless constructor"}, pos);
351         } else {
352             return nullptr;
353         }
354     }
355     return compatibleSignature;
356 }
357 
CollectSignatures(ArenaVector<Signature * > & signatures,const ir::TSTypeParameterInstantiation * typeArguments,const ArenaVector<ir::Expression * > & arguments,std::vector<bool> & argTypeInferenceRequired,const lexer::SourcePosition & pos,TypeRelationFlag resolveFlags)358 std::pair<ArenaVector<Signature *>, ArenaVector<Signature *>> ETSChecker::CollectSignatures(
359     ArenaVector<Signature *> &signatures, const ir::TSTypeParameterInstantiation *typeArguments,
360     const ArenaVector<ir::Expression *> &arguments, std::vector<bool> &argTypeInferenceRequired,
361     const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
362 {
363     ArenaVector<Signature *> compatibleSignatures(Allocator()->Adapter());
364     ArenaVector<Signature *> proxySignatures(Allocator()->Adapter());
365 
366     for (auto *sig : signatures) {
367         if (sig->Function()->IsDefaultParamProxy() &&
368             ValidateProxySignature(sig, typeArguments, arguments, argTypeInferenceRequired)) {
369             proxySignatures.push_back(sig);
370         }
371     }
372 
373     auto collectSignatures = [&](TypeRelationFlag relationFlags) {
374         for (auto *sig : signatures) {
375             if (sig->Function()->IsDefaultParamProxy()) {
376                 continue;
377             }
378             auto *concreteSig =
379                 ValidateSignature(sig, typeArguments, arguments, pos, relationFlags, argTypeInferenceRequired);
380             if (concreteSig != nullptr) {
381                 compatibleSignatures.push_back(concreteSig);
382             }
383         }
384     };
385 
386     // If there's only one signature, we don't need special checks for boxing/unboxing/widening.
387     // We are also able to provide more specific error messages.
388     if (signatures.size() == 1) {
389         TypeRelationFlag flags = TypeRelationFlag::WIDENING | resolveFlags;
390         collectSignatures(flags);
391     } else {
392         std::array<TypeRelationFlag, 4U> flagVariants {TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_UNBOXING |
393                                                            TypeRelationFlag::NO_BOXING,
394                                                        TypeRelationFlag::NO_THROW,
395                                                        TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING |
396                                                            TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_BOXING,
397                                                        TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING};
398         for (auto flags : flagVariants) {
399             flags = flags | resolveFlags;
400             collectSignatures(flags);
401             if (!compatibleSignatures.empty()) {
402                 break;
403             }
404         }
405     }
406     return std::make_pair(compatibleSignatures, proxySignatures);
407 }
408 
GetMostSpecificSignature(ArenaVector<Signature * > & compatibleSignatures,ArenaVector<Signature * > & proxySignatures,const ArenaVector<ir::Expression * > & arguments,std::vector<bool> & argTypeInferenceRequired,const lexer::SourcePosition & pos,TypeRelationFlag resolveFlags)409 Signature *ETSChecker::GetMostSpecificSignature(ArenaVector<Signature *> &compatibleSignatures,
410                                                 ArenaVector<Signature *> &proxySignatures,
411                                                 const ArenaVector<ir::Expression *> &arguments,
412                                                 std::vector<bool> &argTypeInferenceRequired,
413                                                 const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
414 {
415     Signature *mostSpecificSignature = ChooseMostSpecificSignature(compatibleSignatures, argTypeInferenceRequired, pos);
416 
417     if (mostSpecificSignature == nullptr) {
418         ThrowTypeError({"Reference to ", compatibleSignatures.front()->Function()->Id()->Name(), " is ambiguous"}, pos);
419     }
420 
421     if (!TypeInference(mostSpecificSignature, arguments, resolveFlags)) {
422         return nullptr;
423     }
424 
425     // Just to avoid extra nesting level
426     auto const checkAmbiguous = [this, mostSpecificSignature, &pos](Signature const *const proxySignature) -> void {
427         auto const *const proxyParam = proxySignature->Function()->Params().back()->AsETSParameterExpression();
428         if (!proxyParam->Ident()->Name().Is(ir::PROXY_PARAMETER_NAME)) {
429             ThrowTypeError({"Proxy parameter '", proxyParam->Ident()->Name(), "' has invalid name."}, pos);
430         }
431 
432         if (mostSpecificSignature->Params().size() == proxyParam->GetRequiredParams()) {
433             ThrowTypeError({"Reference to ", mostSpecificSignature->Function()->Id()->Name(), " is ambiguous"}, pos);
434         }
435     };
436 
437     if (!proxySignatures.empty()) {
438         auto *const proxySignature =
439             ChooseMostSpecificProxySignature(proxySignatures, argTypeInferenceRequired, pos, arguments.size());
440         if (proxySignature != nullptr) {
441             checkAmbiguous(proxySignature);
442         }
443     }
444 
445     return mostSpecificSignature;
446 }
447 
ValidateSignatures(ArenaVector<Signature * > & signatures,const ir::TSTypeParameterInstantiation * typeArguments,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos,std::string_view signatureKind,TypeRelationFlag resolveFlags)448 Signature *ETSChecker::ValidateSignatures(ArenaVector<Signature *> &signatures,
449                                           const ir::TSTypeParameterInstantiation *typeArguments,
450                                           const ArenaVector<ir::Expression *> &arguments,
451                                           const lexer::SourcePosition &pos, std::string_view signatureKind,
452                                           TypeRelationFlag resolveFlags)
453 {
454     std::vector<bool> argTypeInferenceRequired = FindTypeInferenceArguments(arguments);
455     auto [compatibleSignatures, proxySignatures] =
456         CollectSignatures(signatures, typeArguments, arguments, argTypeInferenceRequired, pos, resolveFlags);
457 
458     if (!compatibleSignatures.empty()) {
459         return GetMostSpecificSignature(compatibleSignatures, proxySignatures, arguments, argTypeInferenceRequired, pos,
460                                         resolveFlags);
461     }
462 
463     if (!proxySignatures.empty()) {
464         auto *const proxySignature =
465             ChooseMostSpecificProxySignature(proxySignatures, argTypeInferenceRequired, pos, arguments.size());
466         if (proxySignature != nullptr) {
467             return proxySignature;
468         }
469     }
470 
471     if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0 && !arguments.empty() && !signatures.empty()) {
472         std::stringstream ss;
473 
474         if (signatures[0]->Function()->IsConstructor()) {
475             ss << util::Helpers::GetClassDefiniton(signatures[0]->Function())->PrivateId().Mutf8();
476         } else {
477             ss << signatures[0]->Function()->Id()->Name().Mutf8();
478         }
479 
480         ss << "(";
481 
482         for (uint32_t index = 0; index < arguments.size(); ++index) {
483             if (arguments[index]->IsArrowFunctionExpression()) {
484                 // NOTE(peterseres): Refactor this case and add test case
485                 break;
486             }
487 
488             arguments[index]->Check(this);
489             arguments[index]->TsType()->ToString(ss);
490 
491             if (index == arguments.size() - 1) {
492                 ss << ")";
493                 ThrowTypeError({"No matching ", signatureKind, " signature for ", ss.str().c_str()}, pos);
494             }
495 
496             ss << ", ";
497         }
498     }
499 
500     if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0) {
501         ThrowTypeError({"No matching ", signatureKind, " signature"}, pos);
502     }
503 
504     return nullptr;
505 }
506 
ChooseMostSpecificSignature(ArenaVector<Signature * > & signatures,const std::vector<bool> & argTypeInferenceRequired,const lexer::SourcePosition & pos,size_t argumentsSize)507 Signature *ETSChecker::ChooseMostSpecificSignature(ArenaVector<Signature *> &signatures,
508                                                    const std::vector<bool> &argTypeInferenceRequired,
509                                                    const lexer::SourcePosition &pos, size_t argumentsSize)
510 {
511     ASSERT(signatures.empty() == false);
512 
513     if (signatures.size() == 1) {
514         return signatures.front();
515     }
516 
517     size_t paramCount = signatures.front()->Params().size();
518     if (argumentsSize != ULONG_MAX) {
519         paramCount = argumentsSize;
520     }
521     // Multiple signatures with zero parameter because of inheritance.
522     // Return the closest one in inheritance chain that is defined at the beginning of the vector.
523     if (paramCount == 0) {
524         return signatures.front();
525     }
526 
527     // Collect which signatures are most specific for each parameter.
528     ArenaMultiMap<size_t /* parameter index */, Signature *> bestSignaturesForParameter(Allocator()->Adapter());
529 
530     const checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(Relation(),
531                                                                           TypeRelationFlag::ONLY_CHECK_WIDENING);
532 
533     for (size_t i = 0; i < paramCount; ++i) {
534         if (argTypeInferenceRequired[i]) {
535             for (auto *sig : signatures) {
536                 bestSignaturesForParameter.insert({i, sig});
537             }
538             continue;
539         }
540         // 1st step: check which is the most specific parameter type for i. parameter.
541         Type *mostSpecificType = signatures.front()->Params().at(i)->TsType();
542         Signature *prevSig = signatures.front();
543 
544         auto initMostSpecificType = [&mostSpecificType, &prevSig, i](Signature *sig) {
545             if (Type *sigType = sig->Params().at(i)->TsType();
546                 sigType->IsETSObjectType() && !sigType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
547                 mostSpecificType = sigType;
548                 prevSig = sig;
549                 return true;
550             }
551             return false;
552         };
553 
554         auto evaluateResult = [this, &mostSpecificType, &prevSig, pos](Signature *sig, Type *sigType) {
555             if (Relation()->IsAssignableTo(sigType, mostSpecificType)) {
556                 mostSpecificType = sigType;
557                 prevSig = sig;
558             } else if (sigType->IsETSObjectType() && mostSpecificType->IsETSObjectType() &&
559                        !Relation()->IsAssignableTo(mostSpecificType, sigType)) {
560                 auto funcName = sig->Function()->Id()->Name();
561                 ThrowTypeError({"Call to `", funcName, "` is ambiguous as `2` versions of `", funcName,
562                                 "` are available: `", funcName, prevSig, "` and `", funcName, sig, "`"},
563                                pos);
564             }
565         };
566 
567         auto searchAmongTypes = [this, &mostSpecificType, argumentsSize, paramCount, i,
568                                  &evaluateResult](Signature *sig, const bool lookForClassType) {
569             if (lookForClassType && argumentsSize == ULONG_MAX) {
570                 [[maybe_unused]] const bool equalParamSize = sig->Params().size() == paramCount;
571                 ASSERT(equalParamSize);
572             }
573             Type *sigType = sig->Params().at(i)->TsType();
574             const bool isClassType =
575                 sigType->IsETSObjectType() && !sigType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE);
576             if (isClassType == lookForClassType) {
577                 if (Relation()->IsIdenticalTo(sigType, mostSpecificType)) {
578                     return;
579                 }
580                 evaluateResult(sig, sigType);
581             }
582         };
583 
584         std::any_of(signatures.begin(), signatures.end(), initMostSpecificType);
585         std::for_each(signatures.begin(), signatures.end(),
586                       [&searchAmongTypes](Signature *sig) mutable { searchAmongTypes(sig, true); });
587         std::for_each(signatures.begin(), signatures.end(),
588                       [&searchAmongTypes](Signature *sig) mutable { searchAmongTypes(sig, false); });
589 
590         for (auto *sig : signatures) {
591             Type *sigType = sig->Params().at(i)->TsType();
592             if (Relation()->IsIdenticalTo(sigType, mostSpecificType)) {
593                 bestSignaturesForParameter.insert({i, sig});
594             }
595         }
596     }
597 
598     // Find the signature that are most specific for all parameters.
599     Signature *mostSpecificSignature = nullptr;
600 
601     for (auto *sig : signatures) {
602         bool mostSpecific = true;
603 
604         for (size_t paramIdx = 0; paramIdx < paramCount; ++paramIdx) {
605             const auto range = bestSignaturesForParameter.equal_range(paramIdx);
606             // Check if signature is most specific for i. parameter type.
607             const bool hasSignature =
608                 std::any_of(range.first, range.second, [&sig](auto entry) { return entry.second == sig; });
609             if (!hasSignature) {
610                 mostSpecific = false;
611                 break;
612             }
613         }
614 
615         if (!mostSpecific) {
616             continue;
617         }
618         if (mostSpecificSignature == nullptr) {
619             mostSpecificSignature = sig;
620             continue;
621         }
622         if (mostSpecificSignature->Owner() == sig->Owner()) {
623             // NOTE: audovichenko. Remove this 'if' when #12443 gets resolved
624             if (mostSpecificSignature->Function() == sig->Function()) {
625                 // The same signature
626                 continue;
627             }
628             return nullptr;
629         }
630     }
631 
632     return mostSpecificSignature;
633 }
634 
ChooseMostSpecificProxySignature(ArenaVector<Signature * > & signatures,const std::vector<bool> & argTypeInferenceRequired,const lexer::SourcePosition & pos,size_t argumentsSize)635 Signature *ETSChecker::ChooseMostSpecificProxySignature(ArenaVector<Signature *> &signatures,
636                                                         const std::vector<bool> &argTypeInferenceRequired,
637                                                         const lexer::SourcePosition &pos, size_t argumentsSize)
638 {
639     if (pos.index == 0 && pos.line == 0) {
640         return nullptr;
641     }
642 
643     const auto mostSpecificSignature =
644         ChooseMostSpecificSignature(signatures, argTypeInferenceRequired, pos, argumentsSize);
645     if (mostSpecificSignature == nullptr) {
646         const auto str = signatures.front()->Function()->Id()->Name().Mutf8().substr(
647             0, signatures.front()->Function()->Id()->Name().Length() - 6);
648         ThrowTypeError("Reference to " + str + " is ambiguous", pos);
649     }
650 
651     return mostSpecificSignature;
652 }
653 
ResolveCallExpression(ArenaVector<Signature * > & signatures,const ir::TSTypeParameterInstantiation * typeArguments,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos)654 Signature *ETSChecker::ResolveCallExpression(ArenaVector<Signature *> &signatures,
655                                              const ir::TSTypeParameterInstantiation *typeArguments,
656                                              const ArenaVector<ir::Expression *> &arguments,
657                                              const lexer::SourcePosition &pos)
658 {
659     auto sig = ValidateSignatures(signatures, typeArguments, arguments, pos, "call");
660     ASSERT(sig);
661     return sig;
662 }
663 
ResolveCallExpressionAndTrailingLambda(ArenaVector<Signature * > & signatures,ir::CallExpression * callExpr,const lexer::SourcePosition & pos,const TypeRelationFlag throwFlag)664 Signature *ETSChecker::ResolveCallExpressionAndTrailingLambda(ArenaVector<Signature *> &signatures,
665                                                               ir::CallExpression *callExpr,
666                                                               const lexer::SourcePosition &pos,
667                                                               const TypeRelationFlag throwFlag)
668 {
669     Signature *sig = nullptr;
670 
671     if (callExpr->TrailingBlock() == nullptr) {
672         sig = ValidateSignatures(signatures, callExpr->TypeParams(), callExpr->Arguments(), pos, "call", throwFlag);
673         return sig;
674     }
675 
676     auto arguments = ExtendArgumentsWithFakeLamda(callExpr);
677     sig = ValidateSignatures(signatures, callExpr->TypeParams(), arguments, pos, "call",
678                              TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA);
679     if (sig != nullptr) {
680         TransformTraillingLambda(callExpr);
681         TypeInference(sig, callExpr->Arguments());
682         return sig;
683     }
684 
685     sig = ValidateSignatures(signatures, callExpr->TypeParams(), callExpr->Arguments(), pos, "call", throwFlag);
686     if (sig != nullptr) {
687         EnsureValidCurlyBrace(callExpr);
688     }
689 
690     return sig;
691 }
692 
ResolveConstructExpression(ETSObjectType * type,const ArenaVector<ir::Expression * > & arguments,const lexer::SourcePosition & pos)693 Signature *ETSChecker::ResolveConstructExpression(ETSObjectType *type, const ArenaVector<ir::Expression *> &arguments,
694                                                   const lexer::SourcePosition &pos)
695 {
696     return ValidateSignatures(type->ConstructSignatures(), nullptr, arguments, pos, "construct");
697 }
698 
699 /*
700  * Object literals do not get checked in the process of call resolution; we need to check them separately
701  * afterwards.
702  */
CheckObjectLiteralArguments(Signature * signature,ArenaVector<ir::Expression * > const & arguments)703 void ETSChecker::CheckObjectLiteralArguments(Signature *signature, ArenaVector<ir::Expression *> const &arguments)
704 {
705     for (uint32_t index = 0; index < arguments.size(); index++) {
706         if (!arguments[index]->IsObjectExpression()) {
707             continue;
708         }
709 
710         Type *tp;
711         if (index >= signature->MinArgCount()) {
712             ASSERT(signature->RestVar());
713             tp = signature->RestVar()->TsType();
714         } else {
715             tp = signature->Params()[index]->TsType();
716         }
717 
718         arguments[index]->AsObjectExpression()->SetPreferredType(tp);
719         arguments[index]->Check(this);
720     }
721 }
722 
BuildMethodSignature(ir::MethodDefinition * method)723 checker::ETSFunctionType *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method)
724 {
725     if (method->TsType() != nullptr) {
726         return method->TsType()->AsETSFunctionType();
727     }
728 
729     bool isConstructSig = method->IsConstructor();
730 
731     auto *funcType = BuildFunctionSignature(method->Function(), isConstructSig);
732 
733     std::vector<checker::ETSFunctionType *> overloads;
734     for (ir::MethodDefinition *const currentFunc : method->Overloads()) {
735         auto *const overloadType = BuildFunctionSignature(currentFunc->Function(), isConstructSig);
736         CheckIdenticalOverloads(funcType, overloadType, currentFunc);
737         currentFunc->SetTsType(overloadType);
738         funcType->AddCallSignature(currentFunc->Function()->Signature());
739         overloads.push_back(overloadType);
740     }
741     for (size_t baseFuncCounter = 0; baseFuncCounter < overloads.size(); ++baseFuncCounter) {
742         auto *overloadType = overloads.at(baseFuncCounter);
743         for (size_t compareFuncCounter = baseFuncCounter + 1; compareFuncCounter < overloads.size();
744              compareFuncCounter++) {
745             auto *compareOverloadType = overloads.at(compareFuncCounter);
746             CheckIdenticalOverloads(overloadType, compareOverloadType, method->Overloads()[compareFuncCounter]);
747         }
748     }
749 
750     method->Id()->Variable()->SetTsType(funcType);
751     return funcType;
752 }
753 
CheckIdenticalOverloads(ETSFunctionType * func,ETSFunctionType * overload,const ir::MethodDefinition * const currentFunc)754 void ETSChecker::CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload,
755                                          const ir::MethodDefinition *const currentFunc)
756 {
757     SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK);
758 
759     if (currentFunc->Function()->IsDefaultParamProxy()) {
760         return;
761     }
762 
763     Relation()->IsIdenticalTo(func, overload);
764     if (Relation()->IsTrue()) {
765         ThrowTypeError("Function already declared.", currentFunc->Start());
766     }
767     if (HasSameAssemblySignature(func, overload)) {
768         ThrowTypeError("Function with this assembly signature already declared.", currentFunc->Start());
769     }
770 }
771 
ComposeSignature(ir::ScriptFunction * func,SignatureInfo * signatureInfo,Type * returnType,varbinder::Variable * nameVar)772 Signature *ETSChecker::ComposeSignature(ir::ScriptFunction *func, SignatureInfo *signatureInfo, Type *returnType,
773                                         varbinder::Variable *nameVar)
774 {
775     auto *signature = CreateSignature(signatureInfo, returnType, func);
776     signature->SetOwner(Context().ContainingClass());
777     signature->SetOwnerVar(nameVar);
778 
779     const auto *returnTypeAnnotation = func->ReturnTypeAnnotation();
780     if (returnTypeAnnotation == nullptr && ((func->Flags() & ir::ScriptFunctionFlags::HAS_RETURN) != 0)) {
781         signature->AddSignatureFlag(SignatureFlags::NEED_RETURN_TYPE);
782     }
783 
784     if (returnTypeAnnotation != nullptr && returnTypeAnnotation->IsTSThisType()) {
785         signature->AddSignatureFlag(SignatureFlags::THIS_RETURN_TYPE);
786     }
787 
788     if (func->IsAbstract()) {
789         signature->AddSignatureFlag(SignatureFlags::ABSTRACT);
790         signature->AddSignatureFlag(SignatureFlags::VIRTUAL);
791     }
792 
793     if (func->IsStatic()) {
794         signature->AddSignatureFlag(SignatureFlags::STATIC);
795     }
796 
797     if (func->IsConstructor()) {
798         signature->AddSignatureFlag(SignatureFlags::CONSTRUCTOR);
799     }
800 
801     if (signature->Owner()->GetDeclNode()->IsFinal() || func->IsFinal()) {
802         signature->AddSignatureFlag(SignatureFlags::FINAL);
803     }
804 
805     if (func->IsPublic()) {
806         signature->AddSignatureFlag(SignatureFlags::PUBLIC);
807     } else if (func->IsInternal()) {
808         if (func->IsProtected()) {
809             signature->AddSignatureFlag(SignatureFlags::INTERNAL_PROTECTED);
810         } else {
811             signature->AddSignatureFlag(SignatureFlags::INTERNAL);
812         }
813     } else if (func->IsProtected()) {
814         signature->AddSignatureFlag(SignatureFlags::PROTECTED);
815     } else if (func->IsPrivate()) {
816         signature->AddSignatureFlag(SignatureFlags::PRIVATE);
817     }
818 
819     return signature;
820 }
821 
ComposeReturnType(ir::ScriptFunction * func,util::StringView funcName,bool isConstructSig)822 Type *ETSChecker::ComposeReturnType(ir::ScriptFunction *func, util::StringView funcName, bool isConstructSig)
823 {
824     auto *const returnTypeAnnotation = func->ReturnTypeAnnotation();
825     checker::Type *returnType {};
826 
827     if (returnTypeAnnotation == nullptr) {
828         // implicit void return type
829         returnType = isConstructSig || func->IsEntryPoint() || funcName.Is(compiler::Signatures::CCTOR)
830                          ? GlobalVoidType()
831                          : GlobalBuiltinVoidType();
832         if (returnType == nullptr) {
833             const auto varMap = VarBinder()->TopScope()->Bindings();
834 
835             const auto builtinVoid = varMap.find(compiler::Signatures::BUILTIN_VOID_CLASS);
836             ASSERT(builtinVoid != varMap.end());
837 
838             BuildClassProperties(builtinVoid->second->Declaration()->Node()->AsClassDefinition());
839 
840             ASSERT(GlobalBuiltinVoidType() != nullptr);
841             returnType = GlobalBuiltinVoidType();
842         }
843 
844         if (func->IsAsyncFunc()) {
845             auto implicitPromiseVoid = [this]() {
846                 const auto &promiseGlobal = GlobalBuiltinPromiseType()->AsETSObjectType();
847                 auto promiseType =
848                     promiseGlobal->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsETSObjectType();
849                 promiseType->AddTypeFlag(checker::TypeFlag::GENERIC);
850                 promiseType->TypeArguments().clear();
851                 promiseType->TypeArguments().emplace_back(GlobalBuiltinVoidType());
852                 return promiseType;
853             };
854 
855             returnType = implicitPromiseVoid();
856         }
857     } else if (func->IsEntryPoint() && returnTypeAnnotation->GetType(this) == GlobalBuiltinVoidType()) {
858         returnType = GlobalVoidType();
859     } else {
860         returnType = GetTypeFromTypeAnnotation(returnTypeAnnotation);
861         returnTypeAnnotation->SetTsType(returnType);
862     }
863 
864     return returnType;
865 }
866 
ComposeSignatureInfo(ir::ScriptFunction * func)867 SignatureInfo *ETSChecker::ComposeSignatureInfo(ir::ScriptFunction *func)
868 {
869     auto *signatureInfo = CreateSignatureInfo();
870     signatureInfo->restVar = nullptr;
871     signatureInfo->minArgCount = 0;
872 
873     if ((func->IsConstructor() || !func->IsStatic()) && !func->IsArrow()) {
874         auto *thisVar = func->Scope()->ParamScope()->Params().front();
875         thisVar->SetTsType(Context().ContainingClass());
876     }
877 
878     if (func->TypeParams() != nullptr) {
879         signatureInfo->typeParams = CreateTypeForTypeParameters(func->TypeParams());
880     }
881 
882     for (auto *const it : func->Params()) {
883         auto *const param = it->AsETSParameterExpression();
884 
885         if (param->IsRestParameter()) {
886             auto const *const restIdent = param->Ident();
887 
888             ASSERT(restIdent->Variable());
889             signatureInfo->restVar = restIdent->Variable()->AsLocalVariable();
890 
891             auto *const restParamTypeAnnotation = param->TypeAnnotation();
892             ASSERT(restParamTypeAnnotation);
893 
894             signatureInfo->restVar->SetTsType(GetTypeFromTypeAnnotation(restParamTypeAnnotation));
895             auto arrayType = signatureInfo->restVar->TsType()->AsETSArrayType();
896             CreateBuiltinArraySignature(arrayType, arrayType->Rank());
897         } else {
898             auto const *const paramIdent = param->Ident();
899 
900             varbinder::Variable *const paramVar = paramIdent->Variable();
901             ASSERT(paramVar);
902 
903             auto *const paramTypeAnnotation = param->TypeAnnotation();
904             ASSERT(paramTypeAnnotation);
905 
906             paramVar->SetTsType(GetTypeFromTypeAnnotation(paramTypeAnnotation));
907             signatureInfo->params.push_back(paramVar->AsLocalVariable());
908             ++signatureInfo->minArgCount;
909         }
910     }
911 
912     return signatureInfo;
913 }
914 
ValidateMainSignature(ir::ScriptFunction * func)915 void ETSChecker::ValidateMainSignature(ir::ScriptFunction *func)
916 {
917     if (func->Params().size() >= 2U) {
918         ThrowTypeError("0 or 1 argument are allowed", func->Start());
919     }
920 
921     if (func->Params().size() == 1) {
922         auto const *const param = func->Params()[0]->AsETSParameterExpression();
923 
924         if (param->IsRestParameter()) {
925             ThrowTypeError("Rest parameter is not allowed in the 'main' function.", param->Start());
926         }
927 
928         const auto paramType = param->Variable()->TsType();
929         if (!paramType->IsETSArrayType() || !paramType->AsETSArrayType()->ElementType()->IsETSStringType()) {
930             ThrowTypeError("Only 'string[]' type argument is allowed.", param->Start());
931         }
932     }
933 }
934 
BuildFunctionSignature(ir::ScriptFunction * func,bool isConstructSig)935 checker::ETSFunctionType *ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig)
936 {
937     bool isArrow = func->IsArrow();
938     auto *nameVar = isArrow ? nullptr : func->Id()->Variable();
939     auto funcName = nameVar == nullptr ? util::StringView() : nameVar->Name();
940 
941     auto *signatureInfo = ComposeSignatureInfo(func);
942 
943     if (funcName.Is(compiler::Signatures::MAIN) &&
944         func->Scope()->Name().Utf8().find(compiler::Signatures::ETS_GLOBAL) != std::string::npos) {
945         func->AddFlag(ir::ScriptFunctionFlags::ENTRY_POINT);
946     }
947     if (func->IsEntryPoint()) {
948         ValidateMainSignature(func);
949     }
950 
951     auto *returnType = ComposeReturnType(func, funcName, isConstructSig);
952     auto *signature = ComposeSignature(func, signatureInfo, returnType, nameVar);
953     if (isConstructSig) {
954         signature->AddSignatureFlag(SignatureFlags::CONSTRUCT);
955     } else {
956         signature->AddSignatureFlag(SignatureFlags::CALL);
957     }
958 
959     auto *funcType = CreateETSFunctionType(func, signature, funcName);
960     func->SetSignature(signature);
961     funcType->SetVariable(nameVar);
962     VarBinder()->AsETSBinder()->BuildFunctionName(func);
963 
964     if (func->IsAbstract()) {
965         signature->AddSignatureFlag(SignatureFlags::ABSTRACT);
966         signature->AddSignatureFlag(SignatureFlags::VIRTUAL);
967     }
968 
969     if (func->IsStatic()) {
970         signature->AddSignatureFlag(SignatureFlags::STATIC);
971     }
972 
973     if (func->IsConstructor()) {
974         signature->AddSignatureFlag(SignatureFlags::CONSTRUCTOR);
975     }
976 
977     if (func->Signature()->Owner()->GetDeclNode()->IsFinal() || func->IsFinal()) {
978         signature->AddSignatureFlag(SignatureFlags::FINAL);
979     }
980 
981     if (func->IsPublic()) {
982         signature->AddSignatureFlag(SignatureFlags::PUBLIC);
983     } else if (func->IsInternal()) {
984         if (func->IsProtected()) {
985             signature->AddSignatureFlag(SignatureFlags::INTERNAL_PROTECTED);
986         } else {
987             signature->AddSignatureFlag(SignatureFlags::INTERNAL);
988         }
989     } else if (func->IsProtected()) {
990         signature->AddSignatureFlag(SignatureFlags::PROTECTED);
991     } else if (func->IsPrivate()) {
992         signature->AddSignatureFlag(SignatureFlags::PRIVATE);
993     }
994 
995     if (func->IsSetter()) {
996         signature->AddSignatureFlag(SignatureFlags::SETTER);
997     } else if (func->IsGetter()) {
998         signature->AddSignatureFlag(SignatureFlags::GETTER);
999     }
1000 
1001     if (!isArrow) {
1002         nameVar->SetTsType(funcType);
1003     }
1004 
1005     return funcType;
1006 }
1007 
CheckEveryAbstractSignatureIsOverridden(ETSFunctionType * target,ETSFunctionType * source)1008 Signature *ETSChecker::CheckEveryAbstractSignatureIsOverridden(ETSFunctionType *target, ETSFunctionType *source)
1009 {
1010     for (auto targetSig = target->CallSignatures().begin(); targetSig != target->CallSignatures().end();) {
1011         if (!(*targetSig)->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
1012             continue;
1013         }
1014 
1015         bool isOverridden = false;
1016         for (auto sourceSig : source->CallSignatures()) {
1017             Relation()->IsIdenticalTo(*targetSig, sourceSig);
1018             if (Relation()->IsTrue() && (*targetSig)->Function()->Id()->Name() == sourceSig->Function()->Id()->Name()) {
1019                 target->CallSignatures().erase(targetSig);
1020                 isOverridden = true;
1021                 break;
1022             }
1023             sourceSig++;
1024         }
1025 
1026         if (!isOverridden) {
1027             return *targetSig;
1028         }
1029     }
1030 
1031     return nullptr;
1032 }
1033 
IsOverridableIn(Signature * signature)1034 bool ETSChecker::IsOverridableIn(Signature *signature)
1035 {
1036     if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) {
1037         return false;
1038     }
1039 
1040     // NOTE: #15095 workaround, separate internal visibility check
1041     if (signature->HasSignatureFlag(SignatureFlags::PUBLIC | SignatureFlags::INTERNAL)) {
1042         return true;
1043     }
1044 
1045     return signature->HasSignatureFlag(SignatureFlags::PROTECTED);
1046 }
1047 
IsMethodOverridesOther(Signature * target,Signature * source)1048 bool ETSChecker::IsMethodOverridesOther(Signature *target, Signature *source)
1049 {
1050     if (source->Function()->IsConstructor()) {
1051         return false;
1052     }
1053 
1054     if (target == source) {
1055         return true;
1056     }
1057 
1058     if (IsOverridableIn(target)) {
1059         SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK);
1060         Relation()->IsIdenticalTo(target, source);
1061         if (Relation()->IsTrue()) {
1062             CheckThrowMarkers(source, target);
1063 
1064             if (source->HasSignatureFlag(SignatureFlags::STATIC)) {
1065                 return false;
1066             }
1067 
1068             source->Function()->SetOverride();
1069             return true;
1070         }
1071     }
1072 
1073     return false;
1074 }
1075 
CheckStaticHide(Signature * target,Signature * source)1076 void ETSChecker::CheckStaticHide(Signature *target, Signature *source)
1077 {
1078     if (!target->HasSignatureFlag(SignatureFlags::STATIC) && source->HasSignatureFlag(SignatureFlags::STATIC)) {
1079         ThrowTypeError("A static method hides an instance method.", source->Function()->Body()->Start());
1080     }
1081 
1082     if ((target->HasSignatureFlag(SignatureFlags::STATIC) ||
1083          (source->HasSignatureFlag(SignatureFlags::STATIC) || !source->Function()->IsOverride())) &&
1084         !IsReturnTypeSubstitutable(target, source)) {
1085         ThrowTypeError("Hiding method is not return-type-substitutable for other method.", source->Function()->Start());
1086     }
1087 }
1088 
CheckThrowMarkers(Signature * source,Signature * target)1089 void ETSChecker::CheckThrowMarkers(Signature *source, Signature *target)
1090 {
1091     ir::ScriptFunctionFlags throwMarkers = ir::ScriptFunctionFlags::THROWS | ir::ScriptFunctionFlags::RETHROWS;
1092     auto sourceThrowMarkers = source->Function()->Flags() & throwMarkers;
1093     auto targetThrowMarkers = target->Function()->Flags() & throwMarkers;
1094     if (sourceThrowMarkers != targetThrowMarkers) {
1095         ThrowTypeError(
1096             "A method that overrides or hides another method cannot change throw or rethrow clauses of the "
1097             "overridden "
1098             "or hidden method.",
1099             target->Function()->Body()->Start());
1100     }
1101 }
1102 
CheckOverride(Signature * signature,Signature * other)1103 std::tuple<bool, OverrideErrorCode> ETSChecker::CheckOverride(Signature *signature, Signature *other)
1104 {
1105     if (other->HasSignatureFlag(SignatureFlags::STATIC)) {
1106         if (signature->Function()->IsOverride()) {
1107             return {false, OverrideErrorCode::OVERRIDDEN_STATIC};
1108         }
1109 
1110         ASSERT(signature->HasSignatureFlag(SignatureFlags::STATIC));
1111         return {true, OverrideErrorCode::NO_ERROR};
1112     }
1113 
1114     if (other->IsFinal()) {
1115         return {false, OverrideErrorCode::OVERRIDDEN_FINAL};
1116     }
1117 
1118     if (!IsReturnTypeSubstitutable(signature, other)) {
1119         return {false, OverrideErrorCode::INCOMPATIBLE_RETURN};
1120     }
1121 
1122     if (signature->ProtectionFlag() > other->ProtectionFlag()) {
1123         return {false, OverrideErrorCode::OVERRIDDEN_WEAKER};
1124     }
1125 
1126     return {true, OverrideErrorCode::NO_ERROR};
1127 }
1128 
AdjustForTypeParameters(Signature * source,Signature * target)1129 Signature *ETSChecker::AdjustForTypeParameters(Signature *source, Signature *target)
1130 {
1131     auto &sourceTypeParams = source->GetSignatureInfo()->typeParams;
1132     auto &targetTypeParams = target->GetSignatureInfo()->typeParams;
1133     if (sourceTypeParams.size() != targetTypeParams.size()) {
1134         return nullptr;
1135     }
1136     if (sourceTypeParams.empty()) {
1137         return target;
1138     }
1139     auto *substitution = NewSubstitution();
1140     for (size_t ix = 0; ix < sourceTypeParams.size(); ix++) {
1141         if (!targetTypeParams[ix]->IsETSTypeParameter()) {
1142             continue;
1143         }
1144         ETSChecker::EmplaceSubstituted(substitution, targetTypeParams[ix]->AsETSTypeParameter(), sourceTypeParams[ix]);
1145     }
1146     return target->Substitute(Relation(), substitution);
1147 }
1148 
ThrowOverrideError(Signature * signature,Signature * overriddenSignature,const OverrideErrorCode & errorCode)1149 void ETSChecker::ThrowOverrideError(Signature *signature, Signature *overriddenSignature,
1150                                     const OverrideErrorCode &errorCode)
1151 {
1152     const char *reason {};
1153     switch (errorCode) {
1154         case OverrideErrorCode::OVERRIDDEN_STATIC: {
1155             reason = "overridden method is static.";
1156             break;
1157         }
1158         case OverrideErrorCode::OVERRIDDEN_FINAL: {
1159             reason = "overridden method is final.";
1160             break;
1161         }
1162         case OverrideErrorCode::INCOMPATIBLE_RETURN: {
1163             reason = "overriding return type is not compatible with the other return type.";
1164             break;
1165         }
1166         case OverrideErrorCode::OVERRIDDEN_WEAKER: {
1167             reason = "overridden method has weaker access privilege.";
1168             break;
1169         }
1170         default: {
1171             UNREACHABLE();
1172         }
1173     }
1174 
1175     ThrowTypeError({signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), " cannot override ",
1176                     overriddenSignature->Function()->Id()->Name(), overriddenSignature, " in ",
1177                     overriddenSignature->Owner(), " because ", reason},
1178                    signature->Function()->Start());
1179 }
1180 
CheckOverride(Signature * signature,ETSObjectType * site)1181 bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site)
1182 {
1183     auto *target = site->GetProperty(signature->Function()->Id()->Name(), PropertySearchFlags::SEARCH_METHOD);
1184     bool isOverridingAnySignature = false;
1185 
1186     if (target == nullptr) {
1187         return isOverridingAnySignature;
1188     }
1189 
1190     for (auto *it : target->TsType()->AsETSFunctionType()->CallSignatures()) {
1191         auto *itSubst = AdjustForTypeParameters(signature, it);
1192 
1193         if (signature->Owner()->HasObjectFlag(ETSObjectFlags::INTERFACE) &&
1194             Relation()->IsIdenticalTo(itSubst->Owner(), GlobalETSObjectType()) &&
1195             !itSubst->HasSignatureFlag(SignatureFlags::PRIVATE)) {
1196             ThrowTypeError("Cannot override non-private method of the class Object from an interface.",
1197                            signature->Function()->Start());
1198         }
1199 
1200         if (itSubst == nullptr) {
1201             continue;
1202         }
1203 
1204         if (itSubst->HasSignatureFlag(SignatureFlags::ABSTRACT) || site->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
1205             if (site->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
1206                 CheckThrowMarkers(itSubst, signature);
1207             }
1208             if ((itSubst->Function()->IsSetter() && !signature->Function()->IsSetter()) ||
1209                 (itSubst->Function()->IsGetter() && !signature->Function()->IsGetter())) {
1210                 continue;
1211             }
1212         }
1213         if (!IsMethodOverridesOther(itSubst, signature)) {
1214             continue;
1215         }
1216 
1217         auto [success, errorCode] = CheckOverride(signature, itSubst);
1218 
1219         if (!success) {
1220             ThrowOverrideError(signature, it, errorCode);
1221         }
1222 
1223         isOverridingAnySignature = true;
1224         it->AddSignatureFlag(SignatureFlags::VIRTUAL);
1225     }
1226 
1227     return isOverridingAnySignature;
1228 }
1229 
CheckOverride(Signature * signature)1230 void ETSChecker::CheckOverride(Signature *signature)
1231 {
1232     auto *owner = signature->Owner();
1233     bool isOverriding = false;
1234 
1235     if (!owner->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE)) {
1236         return;
1237     }
1238 
1239     for (auto *const interface : owner->Interfaces()) {
1240         isOverriding |= CheckInterfaceOverride(this, interface, signature);
1241     }
1242 
1243     ETSObjectType *iter = owner->SuperType();
1244     while (iter != nullptr) {
1245         isOverriding |= CheckOverride(signature, iter);
1246 
1247         for (auto *const interface : iter->Interfaces()) {
1248             isOverriding |= CheckInterfaceOverride(this, interface, signature);
1249         }
1250 
1251         iter = iter->SuperType();
1252     }
1253 
1254     if (!isOverriding && signature->Function()->IsOverride()) {
1255         ThrowTypeError({"Method ", signature->Function()->Id()->Name(), signature, " in ", signature->Owner(),
1256                         " not overriding any method"},
1257                        signature->Function()->Start());
1258     }
1259 }
1260 
GetSignatureFromMethodDefinition(const ir::MethodDefinition * methodDef)1261 Signature *ETSChecker::GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef)
1262 {
1263     ASSERT(methodDef->TsType() && methodDef->TsType()->IsETSFunctionType());
1264 
1265     for (auto *it : methodDef->TsType()->AsETSFunctionType()->CallSignatures()) {
1266         if (it->Function() == methodDef->Function()) {
1267             return it;
1268         }
1269     }
1270 
1271     return nullptr;
1272 }
1273 
ValidateSignatureAccessibility(ETSObjectType * callee,const ir::CallExpression * callExpr,Signature * signature,const lexer::SourcePosition & pos,char const * errorMessage)1274 void ETSChecker::ValidateSignatureAccessibility(ETSObjectType *callee, const ir::CallExpression *callExpr,
1275                                                 Signature *signature, const lexer::SourcePosition &pos,
1276                                                 char const *errorMessage)
1277 {
1278     if ((Context().Status() & CheckerStatus::IGNORE_VISIBILITY) != 0U ||
1279         (!signature->HasSignatureFlag(SignatureFlags::PRIVATE) &&
1280          !signature->HasSignatureFlag(SignatureFlags::PROTECTED))) {
1281         return;
1282     }
1283     const auto *declNode = callee->GetDeclNode();
1284     auto *containingClass = Context().ContainingClass();
1285     bool isContainingSignatureInherited = containingClass->IsSignatureInherited(signature);
1286     ASSERT(declNode && (declNode->IsClassDefinition() || declNode->IsTSInterfaceDeclaration()));
1287 
1288     if (declNode->IsTSInterfaceDeclaration()) {
1289         const auto *enclosingFunc =
1290             util::Helpers::FindAncestorGivenByType(callExpr, ir::AstNodeType::SCRIPT_FUNCTION)->AsScriptFunction();
1291         if (callExpr->Callee()->IsMemberExpression() &&
1292             callExpr->Callee()->AsMemberExpression()->Object()->IsThisExpression() &&
1293             signature->Function()->IsPrivate() && !enclosingFunc->IsPrivate()) {
1294             ThrowTypeError({"Cannot reference 'this' in this context."}, enclosingFunc->Start());
1295         }
1296 
1297         if (containingClass == declNode->AsTSInterfaceDeclaration()->TsType() && isContainingSignatureInherited) {
1298             return;
1299         }
1300     }
1301     if (containingClass == declNode->AsClassDefinition()->TsType() && isContainingSignatureInherited) {
1302         return;
1303     }
1304 
1305     bool isSignatureInherited = callee->IsSignatureInherited(signature);
1306     const auto *currentOutermost = containingClass->OutermostClass();
1307     if (((signature->HasSignatureFlag(SignatureFlags::PROTECTED) && containingClass->IsDescendantOf(callee)) ||
1308          (currentOutermost != nullptr && currentOutermost == callee->OutermostClass())) &&
1309         isSignatureInherited) {
1310         return;
1311     }
1312 
1313     if (errorMessage == nullptr) {
1314         ThrowTypeError({"Signature ", signature->Function()->Id()->Name(), signature, " is not visible here."}, pos);
1315     }
1316     ThrowTypeError(errorMessage, pos);
1317 }
1318 
CheckCapturedVariable(ir::AstNode * const node,varbinder::Variable * const var)1319 void ETSChecker::CheckCapturedVariable(ir::AstNode *const node, varbinder::Variable *const var)
1320 {
1321     if (node->IsIdentifier()) {
1322         const auto *const parent = node->Parent();
1323 
1324         if (parent->IsUpdateExpression() ||
1325             (parent->IsAssignmentExpression() && parent->AsAssignmentExpression()->Left() == node)) {
1326             const auto *const identNode = node->AsIdentifier();
1327 
1328             const auto *resolved = identNode->Variable();
1329 
1330             if (resolved == nullptr) {
1331                 resolved = FindVariableInFunctionScope(identNode->Name());
1332             }
1333 
1334             if (resolved == nullptr) {
1335                 resolved = FindVariableInGlobal(identNode);
1336             }
1337 
1338             if (resolved == var) {
1339                 var->AddFlag(varbinder::VariableFlags::BOXED);
1340             }
1341         }
1342     }
1343 
1344     CheckCapturedVariableInSubnodes(node, var);
1345 }
1346 
CheckCapturedVariableInSubnodes(ir::AstNode * node,varbinder::Variable * var)1347 void ETSChecker::CheckCapturedVariableInSubnodes(ir::AstNode *node, varbinder::Variable *var)
1348 {
1349     node->Iterate([this, var](ir::AstNode *childNode) { CheckCapturedVariable(childNode, var); });
1350 }
1351 
CheckCapturedVariables()1352 void ETSChecker::CheckCapturedVariables()
1353 {
1354     // If we want to capture non constant local variables, we should wrap them in a generic reference class
1355     for (auto [var, _] : Context().CapturedVars()) {
1356         (void)_;
1357         if ((var->Declaration() == nullptr) || var->Declaration()->IsConstDecl() ||
1358             !var->HasFlag(varbinder::VariableFlags::LOCAL) || var->GetScope()->Node()->IsArrowFunctionExpression()) {
1359             continue;
1360         }
1361 
1362         auto *searchNode = var->Declaration()->Node()->Parent();
1363 
1364         if (searchNode->IsVariableDeclarator()) {
1365             searchNode = searchNode->Parent()->Parent();
1366         }
1367 
1368         CheckCapturedVariableInSubnodes(searchNode, var);
1369     }
1370 }
1371 
BuildFunctionalInterfaceName(ir::ETSFunctionType * funcType)1372 void ETSChecker::BuildFunctionalInterfaceName(ir::ETSFunctionType *funcType)
1373 {
1374     VarBinder()->AsETSBinder()->BuildFunctionalInterfaceName(funcType);
1375 }
1376 
CreateFunctionalInterfaceForFunctionType(ir::ETSFunctionType * funcType)1377 void ETSChecker::CreateFunctionalInterfaceForFunctionType(ir::ETSFunctionType *funcType)
1378 {
1379     auto *identNode = Allocator()->New<ir::Identifier>(util::StringView("FunctionalInterface"), Allocator());
1380 
1381     auto interfaceCtx = varbinder::LexicalScope<varbinder::ClassScope>(VarBinder());
1382     auto *interfaceScope = interfaceCtx.GetScope();
1383 
1384     ArenaVector<ir::AstNode *> members(Allocator()->Adapter());
1385     ir::MethodDefinition *invokeFunc = CreateInvokeFunction(funcType);
1386     members.push_back(invokeFunc);
1387 
1388     auto methodCtx =
1389         varbinder::LexicalScope<varbinder::LocalScope>::Enter(VarBinder(), interfaceScope->InstanceMethodScope());
1390     auto [_, var] = VarBinder()->NewVarDecl<varbinder::FunctionDecl>(invokeFunc->Start(), Allocator(),
1391                                                                      invokeFunc->Id()->Name(), invokeFunc);
1392     (void)_;
1393     var->AddFlag(varbinder::VariableFlags::METHOD);
1394     invokeFunc->Function()->Id()->SetVariable(var);
1395 
1396     if (funcType->IsThrowing()) {
1397         invokeFunc->Function()->AddFlag(ir::ScriptFunctionFlags::THROWS);
1398     }
1399 
1400     auto *body = Allocator()->New<ir::TSInterfaceBody>(std::move(members));
1401 
1402     ArenaVector<ir::TSInterfaceHeritage *> extends(Allocator()->Adapter());
1403     auto *interfaceDecl = Allocator()->New<ir::TSInterfaceDeclaration>(
1404         Allocator(), identNode, nullptr, body, std::move(extends), false, false, Language(Language::Id::ETS));
1405     interfaceDecl->SetScope(interfaceScope);
1406     interfaceDecl->AddModifier(ir::ModifierFlags::FUNCTIONAL);
1407     funcType->SetFunctionalInterface(interfaceDecl);
1408     invokeFunc->SetParent(interfaceDecl);
1409 
1410     VarBinder()->AsETSBinder()->BuildFunctionType(funcType);
1411 }
1412 
CreateInvokeFunction(ir::ETSFunctionType * funcType)1413 ir::MethodDefinition *ETSChecker::CreateInvokeFunction(ir::ETSFunctionType *funcType)
1414 {
1415     auto *identNode = Allocator()->New<ir::Identifier>(util::StringView("invoke"), Allocator());
1416 
1417     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
1418     auto *funcParamScope = CopyParams(funcType->Params(), params);
1419 
1420     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), funcParamScope, false);
1421     auto functionCtx = varbinder::LexicalScope<varbinder::FunctionScope>(VarBinder());
1422     auto *functionScope = functionCtx.GetScope();
1423     functionScope->BindParamScope(funcParamScope);
1424     funcParamScope->BindFunctionScope(functionScope);
1425 
1426     ir::ModifierFlags flags = ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::PUBLIC;
1427     auto *func = Allocator()->New<ir::ScriptFunction>(
1428         ir::FunctionSignature(nullptr, std::move(params), funcType->ReturnType()), nullptr,
1429         ir::ScriptFunctionFlags::METHOD, flags, false, Language(Language::Id::ETS));
1430 
1431     func->SetScope(functionScope);
1432     functionScope->BindNode(func);
1433     funcParamScope->BindNode(func);
1434 
1435     auto *funcExpr = Allocator()->New<ir::FunctionExpression>(func);
1436     func->SetIdent(identNode);
1437 
1438     auto *method = Allocator()->New<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, identNode, funcExpr, flags,
1439                                                           Allocator(), false);
1440 
1441     funcExpr->SetParent(method);
1442     func->SetParent(funcExpr);
1443 
1444     return method;
1445 }
1446 
1447 // Lambda creation for Lambda expressions
1448 
CreateLambdaObjectForLambdaReference(ir::ArrowFunctionExpression * lambda,ETSObjectType * functionalInterface)1449 void ETSChecker::CreateLambdaObjectForLambdaReference(ir::ArrowFunctionExpression *lambda,
1450                                                       ETSObjectType *functionalInterface)
1451 {
1452     if (VarBinder()->AsETSBinder()->LambdaObjects().count(lambda) != 0) {
1453         return;
1454     }
1455 
1456     bool saveThis = false;
1457     size_t idx = 0;
1458     const auto &capturedVars = lambda->CapturedVars();
1459     auto *currentClassDef = Context().ContainingClass()->GetDeclNode()->AsClassDefinition();
1460 
1461     // Create the class scope for the synthetic lambda class node
1462     auto classCtx = varbinder::LexicalScope<varbinder::ClassScope>(VarBinder());
1463     auto *classScope = classCtx.GetScope();
1464 
1465     // Create the synthetic class property nodes for the captured variables
1466     ArenaVector<ir::AstNode *> properties(Allocator()->Adapter());
1467     for (const auto *it : capturedVars) {
1468         if (it->HasFlag(varbinder::VariableFlags::LOCAL)) {
1469             properties.push_back(CreateLambdaCapturedField(it, classScope, idx, lambda->Start()));
1470             idx++;
1471         } else if (!it->HasFlag(varbinder::VariableFlags::STATIC) &&
1472                    !Context().ContainingClass()->HasObjectFlag(ETSObjectFlags::GLOBAL)) {
1473             saveThis = true;
1474         }
1475     }
1476 
1477     // If the lambda captured a property in the current class, we have to make a synthetic class property to store
1478     // 'this' in it
1479     if (saveThis) {
1480         properties.push_back(CreateLambdaCapturedThis(classScope, idx, lambda->Start()));
1481         idx++;
1482     }
1483 
1484     // Create the synthetic proxy method node for the current class definiton, which we will use in the lambda
1485     // 'invoke' method to propagate the function call to the current class
1486     auto *proxyMethod = CreateProxyMethodForLambda(currentClassDef, lambda, properties, !saveThis);
1487 
1488     // Create the synthetic constructor node for the lambda class, to be able to save captured variables
1489     auto *ctor = CreateLambdaImplicitCtor(properties);
1490     properties.push_back(ctor);
1491 
1492     // Create the synthetic invoke node for the lambda class, which will propagate the call to the proxy method
1493     auto *invokeFunc = CreateLambdaInvokeProto();
1494 
1495     properties.push_back(invokeFunc);
1496 
1497     // Create the declarations for the synthetic constructor and invoke method
1498     CreateLambdaFuncDecl(ctor, classScope->StaticMethodScope());
1499     CreateLambdaFuncDecl(invokeFunc, classScope->InstanceMethodScope());
1500 
1501     // Create the synthetic lambda class node
1502     ArenaVector<ir::TSClassImplements *> implements(Allocator()->Adapter());
1503     auto *identNode = Allocator()->New<ir::Identifier>(util::StringView("LambdaObject"), Allocator());
1504     auto *lambdaObject =
1505         Allocator()->New<ir::ClassDefinition>(Allocator(), identNode, std::move(properties),
1506                                               ir::ClassDefinitionModifiers::DECLARATION, Language(Language::Id::ETS));
1507     lambda->SetResolvedLambda(lambdaObject);
1508     lambda->SetTsType(functionalInterface);
1509     lambdaObject->SetScope(classScope);
1510     lambdaObject->SetParent(currentClassDef);
1511 
1512     // if we should save 'this', then propagate this information to the lambda node, so when we are compiling it,
1513     // and calling the lambda object ctor, we can pass the 'this' as argument
1514     if (saveThis) {
1515         lambda->SetPropagateThis();
1516     }
1517 
1518     // Set the parent nodes
1519     ctor->SetParent(lambdaObject);
1520     invokeFunc->SetParent(lambdaObject);
1521     classScope->BindNode(lambdaObject);
1522 
1523     // Build the lambda object in the binder
1524     VarBinder()->AsETSBinder()->BuildLambdaObject(lambda, lambdaObject, proxyMethod->Function()->Signature());
1525 
1526     // Resolve the proxy method
1527     ResolveProxyMethod(proxyMethod, lambda);
1528     if (lambda->Function()->IsAsyncFunc()) {
1529         ir::MethodDefinition *asyncImpl = CreateAsyncProxy(proxyMethod, currentClassDef);
1530         ir::ScriptFunction *asyncImplFunc = asyncImpl->Function();
1531         currentClassDef->Body().push_back(asyncImpl);
1532         ReplaceIdentifierReferencesInProxyMethod(asyncImplFunc->Body(), asyncImplFunc->Params(),
1533                                                  lambda->Function()->Params(), lambda->CapturedVars());
1534         Signature *implSig = CreateSignature(proxyMethod->Function()->Signature()->GetSignatureInfo(),
1535                                              GlobalETSObjectType(), asyncImplFunc);
1536         asyncImplFunc->SetSignature(implSig);
1537         VarBinder()->AsETSBinder()->BuildFunctionName(asyncImpl->Function());
1538     }
1539 
1540     // Resolve the lambda object
1541     ResolveLambdaObject(lambdaObject, functionalInterface, lambda, proxyMethod, saveThis);
1542 }
1543 
ResolveLambdaObject(ir::ClassDefinition * lambdaObject,ETSObjectType * functionalInterface,ir::ArrowFunctionExpression * lambda,ir::MethodDefinition * proxyMethod,bool saveThis)1544 void ETSChecker::ResolveLambdaObject(ir::ClassDefinition *lambdaObject, ETSObjectType *functionalInterface,
1545                                      ir::ArrowFunctionExpression *lambda, ir::MethodDefinition *proxyMethod,
1546                                      bool saveThis)
1547 {
1548     // Create the class type for the lambda
1549     auto *lambdaObjectType = Allocator()->New<checker::ETSObjectType>(Allocator(), lambdaObject->Ident()->Name(),
1550                                                                       lambdaObject->Ident()->Name(), lambdaObject,
1551                                                                       checker::ETSObjectFlags::CLASS);
1552 
1553     // Add the target function type to the implementing interfaces, this way, we can call the functional interface
1554     // virtual 'invoke' method and it will propagate the call to the currently stored lambda class 'invoke' function
1555     // which was assigned to the variable
1556     lambdaObjectType->AddInterface(functionalInterface);
1557     lambdaObject->SetTsType(lambdaObjectType);
1558 
1559     // Add the captured fields to the lambda class type
1560     for (auto *it : lambdaObject->Body()) {
1561         if (!it->IsClassProperty()) {
1562             continue;
1563         }
1564 
1565         auto *prop = it->AsClassProperty();
1566         lambdaObjectType->AddProperty<checker::PropertyType::INSTANCE_FIELD>(
1567             prop->Key()->AsIdentifier()->Variable()->AsLocalVariable());
1568     }
1569     VarBinder()->AsETSBinder()->BuildLambdaObjectName(lambda);
1570 
1571     // Resolve the constructor
1572     ResolveLambdaObjectCtor(lambdaObject);
1573 
1574     // Resolve the invoke function
1575     ResolveLambdaObjectInvoke(lambdaObject, lambda, proxyMethod, !saveThis);
1576 }
1577 
ResolveLambdaObjectInvoke(ir::ClassDefinition * lambdaObject,ir::ArrowFunctionExpression * lambda,ir::MethodDefinition * proxyMethod,bool isStatic)1578 void ETSChecker::ResolveLambdaObjectInvoke(ir::ClassDefinition *lambdaObject, ir::ArrowFunctionExpression *lambda,
1579                                            ir::MethodDefinition *proxyMethod, bool isStatic)
1580 {
1581     const auto &lambdaBody = lambdaObject->Body();
1582     auto *invokeFunc = lambdaBody[lambdaBody.size() - 1]->AsMethodDefinition()->Function();
1583     ETSObjectType *lambdaObjectType = lambdaObject->TsType()->AsETSObjectType();
1584 
1585     // Set the implicit 'this' parameters type to the lambda object
1586     auto *thisVar = invokeFunc->Scope()->ParamScope()->Params().front();
1587     thisVar->SetTsType(lambdaObjectType);
1588 
1589     // Create the signature for the invoke function type
1590     auto *invokeSignatureInfo = CreateSignatureInfo();
1591     invokeSignatureInfo->restVar = nullptr;
1592 
1593     // Create the parameters for the invoke function, based on the lambda function's parameters
1594     for (auto *it : lambda->Function()->Params()) {
1595         auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(
1596             VarBinder(), invokeFunc->Scope()->ParamScope(), false);
1597 
1598         auto *const param = it->AsETSParameterExpression();
1599         auto [_, var] = VarBinder()->AddParamDecl(param);
1600         (void)_;
1601         var->SetTsType(param->Variable()->TsType());
1602         param->Ident()->SetVariable(var);
1603         invokeFunc->Params().push_back(param);
1604         invokeSignatureInfo->minArgCount++;
1605         invokeSignatureInfo->params.push_back(var->AsLocalVariable());
1606     }
1607 
1608     // Create the function type for the invoke method
1609     auto *invokeSignature =
1610         CreateSignature(invokeSignatureInfo, lambda->Function()->Signature()->ReturnType(), invokeFunc);
1611     invokeSignature->SetOwner(lambdaObjectType);
1612     invokeSignature->AddSignatureFlag(checker::SignatureFlags::CALL);
1613 
1614     auto *invokeType = CreateETSFunctionType(invokeSignature);
1615     invokeFunc->SetSignature(invokeSignature);
1616     invokeFunc->Id()->Variable()->SetTsType(invokeType);
1617     VarBinder()->AsETSBinder()->BuildFunctionName(invokeFunc);
1618     lambdaObjectType->AddProperty<checker::PropertyType::INSTANCE_METHOD>(
1619         invokeFunc->Id()->Variable()->AsLocalVariable());
1620 
1621     // Fill out the type information for the body of the invoke function
1622     auto *resolvedLambdaInvokeFunctionBody = ResolveLambdaObjectInvokeFuncBody(lambdaObject, proxyMethod, isStatic);
1623     if (invokeFunc->IsAsyncFunc()) {
1624         return;
1625     }
1626     invokeFunc->Body()->AsBlockStatement()->Statements().push_back(resolvedLambdaInvokeFunctionBody);
1627     if (resolvedLambdaInvokeFunctionBody->IsExpressionStatement()) {
1628         invokeFunc->Body()->AsBlockStatement()->Statements().push_back(Allocator()->New<ir::ReturnStatement>(nullptr));
1629     }
1630 }
1631 
ResolveLambdaObjectInvokeFuncBody(ir::ClassDefinition * lambdaObject,ir::MethodDefinition * proxyMethod,bool isStatic)1632 ir::Statement *ETSChecker::ResolveLambdaObjectInvokeFuncBody(ir::ClassDefinition *lambdaObject,
1633                                                              ir::MethodDefinition *proxyMethod, bool isStatic)
1634 {
1635     const auto &lambdaBody = lambdaObject->Body();
1636     auto *proxySignature = proxyMethod->Function()->Signature();
1637     ir::Identifier *fieldIdent {};
1638     ETSObjectType *fieldPropType {};
1639 
1640     // If the proxy method is static, we should call it through the owner class itself
1641     if (isStatic) {
1642         fieldIdent = Allocator()->New<ir::Identifier>(proxySignature->Owner()->Name(), Allocator());
1643         fieldPropType = proxySignature->Owner();
1644         fieldIdent->SetVariable(proxySignature->Owner()->Variable());
1645         fieldIdent->SetTsType(fieldPropType);
1646     } else {
1647         // Otherwise, we call the proxy method through the saved 'this' field
1648         auto *savedThis = lambdaBody[lambdaBody.size() - 3]->AsClassProperty();
1649         auto *fieldProp = savedThis->Key()->AsIdentifier()->Variable();
1650         fieldPropType = fieldProp->TsType()->AsETSObjectType();
1651         fieldIdent = Allocator()->New<ir::Identifier>(savedThis->Key()->AsIdentifier()->Name(), Allocator());
1652         fieldIdent->SetVariable(fieldProp);
1653         fieldIdent->SetTsType(fieldPropType);
1654     }
1655 
1656     // Set the type information for the proxy function call
1657     auto *funcIdent = Allocator()->New<ir::Identifier>(proxyMethod->Function()->Id()->Name(), Allocator());
1658     auto *callee = Allocator()->New<ir::MemberExpression>(fieldIdent, funcIdent,
1659                                                           ir::MemberExpressionKind::ELEMENT_ACCESS, false, false);
1660     callee->SetPropVar(proxySignature->OwnerVar()->AsLocalVariable());
1661     callee->SetObjectType(fieldPropType);
1662     callee->SetTsType(proxySignature->OwnerVar()->TsType());
1663 
1664     // Resolve the proxy method call arguments, first we add the captured fields to the call
1665     auto *invokeFunc = lambdaBody[lambdaBody.size() - 1]->AsMethodDefinition()->Function();
1666     ArenaVector<ir::Expression *> callParams(Allocator()->Adapter());
1667     size_t counter = isStatic ? lambdaBody.size() - 2 : lambdaBody.size() - 3;
1668     for (size_t i = 0; i < counter; i++) {
1669         if (lambdaBody[i]->IsMethodDefinition()) {
1670             break;
1671         }
1672 
1673         auto *classProp = lambdaBody[i]->AsClassProperty();
1674         auto *param = Allocator()->New<ir::Identifier>(classProp->Key()->AsIdentifier()->Name(), Allocator());
1675         param->SetVariable(classProp->Key()->AsIdentifier()->Variable());
1676         param->SetIgnoreBox();
1677         param->SetTsType(MaybeBoxedType(param->Variable()));
1678         callParams.push_back(param);
1679     }
1680 
1681     // Then we add the lambda functions parameters to the call
1682     for (auto const *const it : invokeFunc->Params()) {
1683         auto const *const param = it->AsETSParameterExpression();
1684         auto *const paramIdent = Allocator()->New<ir::Identifier>(param->Ident()->Name(), Allocator());
1685         paramIdent->SetVariable(param->Variable());
1686         paramIdent->SetTsType(param->Variable()->TsType());
1687         callParams.push_back(paramIdent);
1688     }
1689 
1690     // Create the synthetic call expression to the proxy method
1691     auto *resolvedCall = Allocator()->New<ir::CallExpression>(callee, std::move(callParams), nullptr, false);
1692     resolvedCall->SetTsType(proxySignature->ReturnType());
1693     resolvedCall->SetSignature(proxySignature);
1694 
1695     if (proxySignature->ReturnType()->IsETSVoidType()) {
1696         return Allocator()->New<ir::ExpressionStatement>(resolvedCall);
1697     }
1698     return Allocator()->New<ir::ReturnStatement>(resolvedCall);
1699 }
1700 
ResolveLambdaObjectCtor(ir::ClassDefinition * lambdaObject)1701 void ETSChecker::ResolveLambdaObjectCtor(ir::ClassDefinition *lambdaObject)
1702 {
1703     const auto &lambdaBody = lambdaObject->Body();
1704     auto *lambdaObjectType = lambdaObject->TsType()->AsETSObjectType();
1705     auto *ctorFunc = lambdaBody[lambdaBody.size() - 2]->AsMethodDefinition()->Function();
1706 
1707     // Set the implicit 'this' parameters type to the lambda object
1708     auto *thisVar = ctorFunc->Scope()->ParamScope()->Params().front();
1709     thisVar->SetTsType(lambdaObjectType);
1710 
1711     // Create the signature for the constructor function type
1712     auto *ctorSignatureInfo = CreateSignatureInfo();
1713     ctorSignatureInfo->restVar = nullptr;
1714 
1715     for (auto const *const it : ctorFunc->Params()) {
1716         ++ctorSignatureInfo->minArgCount;
1717         ctorSignatureInfo->params.push_back(it->AsETSParameterExpression()->Variable()->AsLocalVariable());
1718     }
1719 
1720     // Create the function type for the constructor
1721     auto *ctorSignature = CreateSignature(ctorSignatureInfo, GlobalVoidType(), ctorFunc);
1722     ctorSignature->SetOwner(lambdaObjectType);
1723     ctorSignature->AddSignatureFlag(checker::SignatureFlags::CONSTRUCTOR | checker::SignatureFlags::CONSTRUCT);
1724     lambdaObjectType->AddConstructSignature(ctorSignature);
1725 
1726     auto *ctorType = CreateETSFunctionType(ctorSignature);
1727     ctorFunc->SetSignature(ctorSignature);
1728     ctorFunc->Id()->Variable()->SetTsType(ctorType);
1729     VarBinder()->AsETSBinder()->BuildFunctionName(ctorFunc);
1730 
1731     // Add the type information for the lambda field initializers in the constructor
1732     auto &initializers = ctorFunc->Body()->AsBlockStatement()->Statements();
1733     for (size_t i = 0; i < initializers.size(); i++) {
1734         auto *fieldinit = initializers[i]->AsExpressionStatement()->GetExpression()->AsAssignmentExpression();
1735         auto *ctorParamVar = ctorFunc->Params()[i]->AsETSParameterExpression()->Variable();
1736         auto *fieldVar = lambdaBody[i]->AsClassProperty()->Key()->AsIdentifier()->Variable();
1737         auto *leftHandSide = fieldinit->Left();
1738         leftHandSide->AsMemberExpression()->SetObjectType(lambdaObjectType);
1739         leftHandSide->AsMemberExpression()->SetPropVar(fieldVar->AsLocalVariable());
1740         leftHandSide->AsMemberExpression()->SetIgnoreBox();
1741         leftHandSide->AsMemberExpression()->SetTsType(fieldVar->TsType());
1742         leftHandSide->AsMemberExpression()->Object()->SetTsType(lambdaObjectType);
1743         fieldinit->Right()->AsIdentifier()->SetVariable(ctorParamVar);
1744         fieldinit->Right()->SetTsType(ctorParamVar->TsType());
1745     }
1746 }
1747 
ResolveProxyMethod(ir::MethodDefinition * proxyMethod,ir::ArrowFunctionExpression * lambda)1748 void ETSChecker::ResolveProxyMethod(ir::MethodDefinition *proxyMethod, ir::ArrowFunctionExpression *lambda)
1749 {
1750     auto *func = proxyMethod->Function();
1751     bool isStatic = func->IsStatic();
1752     auto *currentClassType = Context().ContainingClass();
1753 
1754     // Build the proxy method in the binder
1755     VarBinder()->AsETSBinder()->BuildProxyMethod(
1756         func, currentClassType->GetDeclNode()->AsClassDefinition()->InternalName(), isStatic);
1757 
1758     // If the proxy method is not static, set the implicit 'this' parameters type to the current class
1759     if (!isStatic) {
1760         auto *thisVar = func->Scope()->ParamScope()->Params().front();
1761         thisVar->SetTsType(currentClassType);
1762     }
1763 
1764     // Fill out the type information for the proxy method
1765     auto *signature = func->Signature();
1766     auto *signatureInfo = signature->GetSignatureInfo();
1767     signatureInfo->restVar = nullptr;
1768 
1769     for (auto const *const it : proxyMethod->Function()->Params()) {
1770         signatureInfo->params.push_back(it->AsETSParameterExpression()->Variable()->AsLocalVariable());
1771         ++signatureInfo->minArgCount;
1772     }
1773 
1774     signature->SetReturnType(lambda->Function()->Signature()->ReturnType());
1775     signature->SetOwner(currentClassType);
1776 
1777     // Add the proxy method to the current class methods
1778     if (isStatic) {
1779         currentClassType->AddProperty<checker::PropertyType::STATIC_METHOD>(func->Id()->Variable()->AsLocalVariable());
1780     } else {
1781         currentClassType->AddProperty<checker::PropertyType::INSTANCE_METHOD>(
1782             func->Id()->Variable()->AsLocalVariable());
1783     }
1784     VarBinder()->AsETSBinder()->BuildFunctionName(func);
1785 }
1786 
ComputeProxyMethods(ir::ClassDefinition * klass)1787 size_t ETSChecker::ComputeProxyMethods(ir::ClassDefinition *klass)
1788 {
1789     // Compute how many proxy methods are present in the current class, to be able to create a name for the proxy
1790     // method which doesn't conflict with any of the other ones
1791     size_t idx = 0;
1792     for (auto *it : klass->Body()) {
1793         if (!it->IsMethodDefinition()) {
1794             continue;
1795         }
1796 
1797         if (it->AsMethodDefinition()->Function()->IsProxy()) {
1798             idx++;
1799         }
1800     }
1801     return idx;
1802 }
1803 
GetFlagsForProxyLambda(bool isStatic)1804 ir::ModifierFlags ETSChecker::GetFlagsForProxyLambda(bool isStatic)
1805 {
1806     // If every captured variable in the lambda is local variable, the proxy method can be 'static' since it doesn't
1807     // use any of the classes properties
1808     ir::ModifierFlags flags = ir::ModifierFlags::PUBLIC;
1809 
1810     if (isStatic) {
1811         flags |= ir::ModifierFlags::STATIC;
1812     }
1813 
1814     return flags;
1815 }
1816 
CreateProxyFunc(ir::ArrowFunctionExpression * lambda,ArenaVector<ir::AstNode * > & captured,bool isStatic)1817 ir::ScriptFunction *ETSChecker::CreateProxyFunc(ir::ArrowFunctionExpression *lambda,
1818                                                 ArenaVector<ir::AstNode *> &captured, bool isStatic)
1819 {
1820     // Create the synthetic parameters for the proxy method
1821     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
1822     auto *funcParamScope = CreateProxyMethodParams(lambda, params, captured, isStatic);
1823 
1824     // Create the scopes for the proxy method
1825     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), funcParamScope, false);
1826     auto *scope = VarBinder()->Allocator()->New<varbinder::FunctionScope>(Allocator(), funcParamScope);
1827     auto *body = lambda->Function()->Body();
1828     body->AsBlockStatement()->SetScope(scope);
1829 
1830     ir::ScriptFunctionFlags funcFlags = ir::ScriptFunctionFlags::METHOD | ir::ScriptFunctionFlags::PROXY;
1831     if (lambda->Function()->IsAsyncFunc()) {
1832         funcFlags |= ir::ScriptFunctionFlags::ASYNC;
1833     }
1834     auto *func = Allocator()->New<ir::ScriptFunction>(
1835         ir::FunctionSignature(nullptr, std::move(params), lambda->Function()->ReturnTypeAnnotation()), body, funcFlags,
1836         GetFlagsForProxyLambda(isStatic), false, Language(Language::Id::ETS));
1837 
1838     func->SetScope(scope);
1839     if (!func->IsAsyncFunc()) {
1840         // Replace the variable binding in the lambda body where an identifier refers to a lambda parameter or a
1841         // captured variable to the newly created proxy parameters
1842         ReplaceIdentifierReferencesInProxyMethod(body, func->Params(), lambda->Function()->Params(),
1843                                                  lambda->CapturedVars());
1844     }
1845 
1846     // Bind the scopes
1847     scope->BindNode(func);
1848     funcParamScope->BindNode(func);
1849     scope->BindParamScope(funcParamScope);
1850     funcParamScope->BindFunctionScope(scope);
1851 
1852     // Copy the bindings from the original function scope
1853     for (const auto &binding : lambda->Function()->Scope()->Bindings()) {
1854         scope->InsertBinding(binding.first, binding.second);
1855     }
1856 
1857     ReplaceScope(body, lambda->Function(), scope);
1858     return func;
1859 }
1860 
CreateProxyMethodForLambda(ir::ClassDefinition * klass,ir::ArrowFunctionExpression * lambda,ArenaVector<ir::AstNode * > & captured,bool isStatic)1861 ir::MethodDefinition *ETSChecker::CreateProxyMethodForLambda(ir::ClassDefinition *klass,
1862                                                              ir::ArrowFunctionExpression *lambda,
1863                                                              ArenaVector<ir::AstNode *> &captured, bool isStatic)
1864 {
1865     auto *func = CreateProxyFunc(lambda, captured, isStatic);
1866 
1867     // Create the synthetic proxy method
1868     auto *funcExpr = Allocator()->New<ir::FunctionExpression>(func);
1869     util::UString funcName(util::StringView("lambda$invoke$"), Allocator());
1870     funcName.Append(std::to_string(ComputeProxyMethods(klass)));
1871     auto *identNode = Allocator()->New<ir::Identifier>(funcName.View(), Allocator());
1872     func->SetIdent(identNode);
1873     auto *proxy = Allocator()->New<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, identNode, funcExpr,
1874                                                          GetFlagsForProxyLambda(isStatic), Allocator(), false);
1875     klass->Body().push_back(proxy);
1876     proxy->SetParent(klass);
1877 
1878     // Add the proxy method to the current class declarations
1879     CreateLambdaFuncDecl(proxy, klass->Scope()->AsClassScope()->InstanceMethodScope());
1880 
1881     // Set the parent nodes
1882     func->SetParent(funcExpr);
1883     funcExpr->SetParent(proxy);
1884 
1885     // Create the signature template for the proxy method to be able to save this signatures pointer in the binder
1886     // lambdaObjects_ to be able to compute the lambda object invoke functions internal name later
1887     auto *proxySignatureInfo = CreateSignatureInfo();
1888     auto *proxySignature = CreateSignature(proxySignatureInfo, GlobalVoidType(), func);
1889 
1890     SignatureFlags signatureFlags = SignatureFlags::CALL;
1891     if (isStatic) {
1892         signatureFlags |= SignatureFlags::STATIC;
1893     }
1894 
1895     proxySignature->AddSignatureFlag(signatureFlags | SignatureFlags::PROXY);
1896     proxySignature->SetOwnerVar(func->Id()->Variable());
1897     auto *proxyType = CreateETSFunctionType(proxySignature);
1898     func->SetSignature(proxySignature);
1899     func->Id()->Variable()->SetTsType(proxyType);
1900 
1901     return proxy;
1902 }
1903 
ReplaceIdentifierReferencesInProxyMethod(ir::AstNode * body,const ArenaVector<ir::Expression * > & proxyParams,const ArenaVector<ir::Expression * > & lambdaParams,ArenaVector<varbinder::Variable * > & captured)1904 void ETSChecker::ReplaceIdentifierReferencesInProxyMethod(ir::AstNode *body,
1905                                                           const ArenaVector<ir::Expression *> &proxyParams,
1906                                                           const ArenaVector<ir::Expression *> &lambdaParams,
1907                                                           ArenaVector<varbinder::Variable *> &captured)
1908 {
1909     if (proxyParams.empty()) {
1910         return;
1911     }
1912 
1913     // First, create a merged list of all of the potential references which we will replace. These references are
1914     // the original lambda expression parameters and the references to the captured variables inside the lambda
1915     // expression body. The order is crucial, thats why we save the index, because in the synthetic proxy method,
1916     // the first n number of parameters are which came from the lambda expression parameter list, and the last
1917     // parameters are which came from the captured variables
1918     std::unordered_map<varbinder::Variable *, size_t> mergedTargetReferences;
1919     size_t idx = 0;
1920 
1921     for (auto *it : captured) {
1922         if (it->HasFlag(varbinder::VariableFlags::LOCAL)) {
1923             mergedTargetReferences.insert({it, idx});
1924             idx++;
1925         }
1926     }
1927 
1928     for (auto const *const it : lambdaParams) {
1929         mergedTargetReferences.insert({it->AsETSParameterExpression()->Variable(), idx});
1930         idx++;
1931     }
1932 
1933     ReplaceIdentifierReferencesInProxyMethod(body, proxyParams, mergedTargetReferences);
1934 }
1935 
ReplaceIdentifierReferencesInProxyMethod(ir::AstNode * node,const ArenaVector<ir::Expression * > & proxyParams,std::unordered_map<varbinder::Variable *,size_t> & mergedTargetReferences)1936 void ETSChecker::ReplaceIdentifierReferencesInProxyMethod(
1937     ir::AstNode *node, const ArenaVector<ir::Expression *> &proxyParams,
1938     std::unordered_map<varbinder::Variable *, size_t> &mergedTargetReferences)
1939 {
1940     if (node->IsMemberExpression()) {
1941         auto *memberExpr = node->AsMemberExpression();
1942         if (memberExpr->Kind() == ir::MemberExpressionKind::PROPERTY_ACCESS) {
1943             ReplaceIdentifierReferenceInProxyMethod(memberExpr->Object(), proxyParams, mergedTargetReferences);
1944             return;
1945         }
1946     }
1947     node->Iterate([this, &proxyParams, &mergedTargetReferences](ir::AstNode *childNode) {
1948         ReplaceIdentifierReferenceInProxyMethod(childNode, proxyParams, mergedTargetReferences);
1949     });
1950 }
1951 
ReplaceIdentifierReferenceInProxyMethod(ir::AstNode * node,const ArenaVector<ir::Expression * > & proxyParams,std::unordered_map<varbinder::Variable *,size_t> & mergedTargetReferences)1952 void ETSChecker::ReplaceIdentifierReferenceInProxyMethod(
1953     ir::AstNode *node, const ArenaVector<ir::Expression *> &proxyParams,
1954     std::unordered_map<varbinder::Variable *, size_t> &mergedTargetReferences)
1955 {
1956     // If we see an identifier reference
1957     if (node->IsIdentifier()) {
1958         auto *identNode = node->AsIdentifier();
1959         ASSERT(identNode->Variable());
1960 
1961         // Then check if that reference is present in the target references which we want to replace
1962         auto found = mergedTargetReferences.find(identNode->Variable());
1963         if (found != mergedTargetReferences.end()) {
1964             // If it is present in the target references, replace it with the proper proxy parameter reference
1965             identNode->SetVariable(proxyParams[found->second]->AsETSParameterExpression()->Variable());
1966         }
1967     }
1968 
1969     ReplaceIdentifierReferencesInProxyMethod(node, proxyParams, mergedTargetReferences);
1970 }
1971 
CreateProxyMethodParams(ir::ArrowFunctionExpression * lambda,ArenaVector<ir::Expression * > & proxyParams,ArenaVector<ir::AstNode * > & captured,bool isStatic)1972 varbinder::FunctionParamScope *ETSChecker::CreateProxyMethodParams(ir::ArrowFunctionExpression *lambda,
1973                                                                    ArenaVector<ir::Expression *> &proxyParams,
1974                                                                    ArenaVector<ir::AstNode *> &captured, bool isStatic)
1975 {
1976     const auto &params = lambda->Function()->Params();
1977     // Create a param scope for the proxy method parameters
1978     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder());
1979 
1980     // First add the parameters to the proxy method, based on how many variables have been captured, if this
1981     // is NOT a static method, we doesn't need the last captured parameter, which is the 'this' reference, because
1982     // this proxy method is bound to the class itself which the 'this' capture is referred to
1983     if (!captured.empty()) {
1984         size_t counter = isStatic ? captured.size() : (captured.size() - 1);
1985         for (size_t i = 0; i < counter; i++) {
1986             auto *capturedVar = captured[i]->AsClassProperty()->Key()->AsIdentifier()->Variable();
1987             ir::Identifier *paramIdent = nullptr;
1988 
1989             // When a lambda is defined inside an instance extension function, if "this" is captured inside the lambda,
1990             // "this" should be binded with the parameter of the proxy method
1991             if (this->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD) &&
1992                 lambda->CapturedVars()[i]->Name() == varbinder::VarBinder::MANDATORY_PARAM_THIS) {
1993                 paramIdent = Allocator()->New<ir::Identifier>(varbinder::VarBinder::MANDATORY_PARAM_THIS, Allocator());
1994             } else {
1995                 paramIdent = Allocator()->New<ir::Identifier>(capturedVar->Name(), Allocator());
1996             }
1997 
1998             auto *param = Allocator()->New<ir::ETSParameterExpression>(paramIdent, nullptr);
1999             auto [_, var] = VarBinder()->AddParamDecl(param);
2000             (void)_;
2001             var->SetTsType(capturedVar->TsType());
2002             if (capturedVar->HasFlag(varbinder::VariableFlags::BOXED)) {
2003                 var->AddFlag(varbinder::VariableFlags::BOXED);
2004             }
2005             param->SetTsType(capturedVar->TsType());
2006             param->SetVariable(var);
2007             proxyParams.push_back(param);
2008         }
2009     }
2010 
2011     // Then add the lambda function parameters to the proxy method's parameter vector, and set the type from the
2012     // already computed types for the lambda parameters
2013     for (auto const *const it : params) {
2014         auto *const oldParamExprIdent = it->AsETSParameterExpression()->Ident();
2015         auto *const paramIdent = Allocator()->New<ir::Identifier>(oldParamExprIdent->Name(), Allocator());
2016         auto *param = Allocator()->New<ir::ETSParameterExpression>(paramIdent, nullptr);
2017         auto [_, var] = VarBinder()->AddParamDecl(param);
2018         (void)_;
2019         var->SetTsType(oldParamExprIdent->Variable()->TsType());
2020         param->SetVariable(var);
2021         param->SetTsType(oldParamExprIdent->Variable()->TsType());
2022         proxyParams.push_back(param);
2023     }
2024 
2025     return paramCtx.GetScope();
2026 }
2027 
CreateLambdaCapturedThis(varbinder::ClassScope * scope,size_t & idx,const lexer::SourcePosition & pos)2028 ir::ClassProperty *ETSChecker::CreateLambdaCapturedThis(varbinder::ClassScope *scope, size_t &idx,
2029                                                         const lexer::SourcePosition &pos)
2030 {
2031     // Enter the lambda class instance field scope, every property will be bound to the lambda instance itself
2032     auto fieldCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(VarBinder(), scope->InstanceFieldScope());
2033 
2034     // Create the name for the synthetic property node
2035     util::UString fieldName(util::StringView("field"), Allocator());
2036     fieldName.Append(std::to_string(idx));
2037     auto *fieldIdent = Allocator()->New<ir::Identifier>(fieldName.View(), Allocator());
2038 
2039     // Create the synthetic class property node
2040     auto *field =
2041         Allocator()->New<ir::ClassProperty>(fieldIdent, nullptr, nullptr, ir::ModifierFlags::NONE, Allocator(), false);
2042 
2043     // Add the declaration to the scope, and set the type based on the current class type, to be able to store the
2044     // 'this' reference
2045     auto [decl, var] = VarBinder()->NewVarDecl<varbinder::LetDecl>(pos, fieldIdent->Name());
2046     var->AddFlag(varbinder::VariableFlags::PROPERTY);
2047     var->SetTsType(Context().ContainingClass());
2048     fieldIdent->SetVariable(var);
2049     field->SetTsType(Context().ContainingClass());
2050     decl->BindNode(field);
2051     return field;
2052 }
2053 
CreateLambdaCapturedField(const varbinder::Variable * capturedVar,varbinder::ClassScope * scope,size_t & idx,const lexer::SourcePosition & pos)2054 ir::ClassProperty *ETSChecker::CreateLambdaCapturedField(const varbinder::Variable *capturedVar,
2055                                                          varbinder::ClassScope *scope, size_t &idx,
2056                                                          const lexer::SourcePosition &pos)
2057 {
2058     // Enter the lambda class instance field scope, every property will be bound to the lambda instance itself
2059     auto fieldCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(VarBinder(), scope->InstanceFieldScope());
2060 
2061     // Create the name for the synthetic property node
2062     util::UString fieldName(util::StringView("field"), Allocator());
2063     fieldName.Append(std::to_string(idx));
2064     auto *fieldIdent = Allocator()->New<ir::Identifier>(fieldName.View(), Allocator());
2065 
2066     // Create the synthetic class property node
2067     auto *field =
2068         Allocator()->New<ir::ClassProperty>(fieldIdent, nullptr, nullptr, ir::ModifierFlags::NONE, Allocator(), false);
2069 
2070     // Add the declaration to the scope, and set the type based on the captured variable's scope
2071     auto [decl, var] = VarBinder()->NewVarDecl<varbinder::LetDecl>(pos, fieldIdent->Name());
2072     var->AddFlag(varbinder::VariableFlags::PROPERTY);
2073     var->SetTsType(capturedVar->TsType());
2074     if (capturedVar->HasFlag(varbinder::VariableFlags::BOXED)) {
2075         var->AddFlag(varbinder::VariableFlags::BOXED);
2076     }
2077     fieldIdent->SetVariable(var);
2078     field->SetTsType(MaybeBoxedType(capturedVar));
2079     decl->BindNode(field);
2080     return field;
2081 }
2082 
CreateLambdaImplicitCtor(ArenaVector<ir::AstNode * > & properties)2083 ir::MethodDefinition *ETSChecker::CreateLambdaImplicitCtor(ArenaVector<ir::AstNode *> &properties)
2084 {
2085     // Create the parameters for the synthetic constructor node for the lambda class
2086     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
2087     auto *funcParamScope = CreateLambdaCtorImplicitParams(params, properties);
2088 
2089     // Create the scopes for the synthetic constructor node
2090     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), funcParamScope, false);
2091     auto *scope = VarBinder()->Allocator()->New<varbinder::FunctionScope>(Allocator(), funcParamScope);
2092 
2093     // Complete the synthetic constructor node's body, to be able to initialize every field by copying every
2094     // captured variables value
2095     ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
2096     for (auto *it : properties) {
2097         auto *field = it->AsClassProperty()->Key()->AsIdentifier();
2098         statements.push_back(CreateLambdaCtorFieldInit(field->Name(), field->Variable()));
2099     }
2100 
2101     // Create the synthetic constructor node
2102     auto *body = Allocator()->New<ir::BlockStatement>(Allocator(), std::move(statements));
2103     body->SetScope(scope);
2104     auto *func =
2105         Allocator()->New<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), nullptr), body,
2106                                              ir::ScriptFunctionFlags::CONSTRUCTOR, false, Language(Language::Id::ETS));
2107     func->SetScope(scope);
2108     // Set the scopes
2109     scope->BindNode(func);
2110     funcParamScope->BindNode(func);
2111     scope->BindParamScope(funcParamScope);
2112     funcParamScope->BindFunctionScope(scope);
2113 
2114     // Create the name for the synthetic constructor
2115     auto *funcExpr = Allocator()->New<ir::FunctionExpression>(func);
2116     auto *key = Allocator()->New<ir::Identifier>("constructor", Allocator());
2117     func->SetIdent(key);
2118     auto *ctor = Allocator()->New<ir::MethodDefinition>(ir::MethodDefinitionKind::CONSTRUCTOR, key, funcExpr,
2119                                                         ir::ModifierFlags::NONE, Allocator(), false);
2120 
2121     // Set the parent nodes
2122     func->SetParent(funcExpr);
2123     funcExpr->SetParent(ctor);
2124 
2125     return ctor;
2126 }
2127 
CreateLambdaCtorImplicitParams(ArenaVector<ir::Expression * > & params,ArenaVector<ir::AstNode * > & properties)2128 varbinder::FunctionParamScope *ETSChecker::CreateLambdaCtorImplicitParams(ArenaVector<ir::Expression *> &params,
2129                                                                           ArenaVector<ir::AstNode *> &properties)
2130 {
2131     // Create the scope for the synthetic constructor parameters
2132     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder());
2133 
2134     // Create every parameter based on the synthetic field which was created for the lambda class to store the
2135     // captured variables
2136     for (auto *it : properties) {
2137         auto *field = it->AsClassProperty()->Key()->AsIdentifier();
2138         auto *paramField = Allocator()->New<ir::Identifier>(field->Name(), Allocator());
2139         auto *param = Allocator()->New<ir::ETSParameterExpression>(paramField, nullptr);
2140         auto [_, var] = VarBinder()->AddParamDecl(param);
2141         (void)_;
2142         auto *type = MaybeBoxedType(field->Variable());
2143         var->SetTsType(type);
2144         param->Ident()->SetTsType(type);
2145         param->Ident()->SetVariable(var);
2146         params.push_back(param);
2147     }
2148 
2149     return paramCtx.GetScope();
2150 }
2151 
CreateLambdaCtorFieldInit(util::StringView name,varbinder::Variable * var)2152 ir::Statement *ETSChecker::CreateLambdaCtorFieldInit(util::StringView name, varbinder::Variable *var)
2153 {
2154     // Create synthetic field initializers for the lambda class fields
2155     // The node structure is the following: this.field0 = field0, where the left hand side refers to the lambda
2156     // classes field, and the right hand side is refers to the constructors parameter
2157     auto *thisExpr = Allocator()->New<ir::ThisExpression>();
2158     auto *fieldAccessExpr = Allocator()->New<ir::Identifier>(name, Allocator());
2159     auto *leftHandSide = Allocator()->New<ir::MemberExpression>(
2160         thisExpr, fieldAccessExpr, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
2161     auto *rightHandSide = Allocator()->New<ir::Identifier>(name, Allocator());
2162     rightHandSide->SetVariable(var);
2163     auto *initializer = Allocator()->New<ir::AssignmentExpression>(leftHandSide, rightHandSide,
2164                                                                    lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
2165     return Allocator()->New<ir::ExpressionStatement>(initializer);
2166 }
2167 
2168 // Lambda creation for Function references
2169 
CreateLambdaObjectForFunctionReference(ir::AstNode * refNode,Signature * signature,ETSObjectType * functionalInterface)2170 void ETSChecker::CreateLambdaObjectForFunctionReference(ir::AstNode *refNode, Signature *signature,
2171                                                         ETSObjectType *functionalInterface)
2172 {
2173     if (VarBinder()->AsETSBinder()->LambdaObjects().count(refNode) != 0) {
2174         return;
2175     }
2176 
2177     // Create the class scope for the synthetic lambda class node
2178     auto classCtx = varbinder::LexicalScope<varbinder::ClassScope>(VarBinder());
2179     auto *classScope = classCtx.GetScope();
2180     bool isStaticReference = signature->HasSignatureFlag(SignatureFlags::STATIC);
2181 
2182     // Create the synthetic field where we will store the instance object which we are trying to obtain the function
2183     // reference through, if the referenced function is static, we won't need to store the instance object
2184     ArenaVector<ir::AstNode *> properties(Allocator()->Adapter());
2185     if (!isStaticReference) {
2186         properties.push_back(CreateLambdaImplicitField(classScope, refNode->Start()));
2187     }
2188 
2189     // Create the synthetic constructor node, where we will initialize the synthetic field (if present) to the
2190     // instance object
2191     auto *ctor = CreateLambdaImplicitCtor(refNode->Range(), isStaticReference);
2192     properties.push_back(ctor);
2193 
2194     // Create the template for the synthetic invoke function which will propagate the function call to the saved
2195     // instance's referenced function, or the class static function, if this is a static reference
2196     auto *invokeFunc = CreateLambdaInvokeProto();
2197     properties.push_back(invokeFunc);
2198 
2199     // Create the declarations for the synthetic constructor and invoke method
2200     CreateLambdaFuncDecl(ctor, classScope->StaticMethodScope());
2201     CreateLambdaFuncDecl(invokeFunc, classScope->InstanceMethodScope());
2202 
2203     // Create the synthetic lambda class node
2204     ArenaVector<ir::TSClassImplements *> implements(Allocator()->Adapter());
2205     auto *identNode = Allocator()->New<ir::Identifier>(util::StringView("LambdaObject"), Allocator());
2206     auto *lambdaObject =
2207         Allocator()->New<ir::ClassDefinition>(Allocator(), identNode, std::move(properties),
2208                                               ir::ClassDefinitionModifiers::DECLARATION, Language(Language::Id::ETS));
2209     lambdaObject->SetScope(classScope);
2210     // Set the parent nodes
2211     ctor->SetParent(lambdaObject);
2212     invokeFunc->SetParent(lambdaObject);
2213     classScope->BindNode(lambdaObject);
2214 
2215     // Build the lambda object in the binder
2216     VarBinder()->AsETSBinder()->BuildLambdaObject(refNode, lambdaObject, signature);
2217 
2218     // Resolve the lambda object
2219     ResolveLambdaObject(lambdaObject, signature, functionalInterface, refNode);
2220 }
2221 
CreateLambdaImplicitField(varbinder::ClassScope * scope,const lexer::SourcePosition & pos)2222 ir::AstNode *ETSChecker::CreateLambdaImplicitField(varbinder::ClassScope *scope, const lexer::SourcePosition &pos)
2223 {
2224     // Enter the lambda class instance field scope, every property will be bound to the lambda instance itself
2225     auto fieldCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(VarBinder(), scope->InstanceFieldScope());
2226 
2227     // Create the synthetic class property node
2228     auto *fieldIdent = Allocator()->New<ir::Identifier>("field0", Allocator());
2229     auto *field =
2230         Allocator()->New<ir::ClassProperty>(fieldIdent, nullptr, nullptr, ir::ModifierFlags::NONE, Allocator(), false);
2231 
2232     // Add the declaration to the scope
2233     auto [decl, var] = VarBinder()->NewVarDecl<varbinder::LetDecl>(pos, fieldIdent->Name());
2234     var->AddFlag(varbinder::VariableFlags::PROPERTY);
2235     fieldIdent->SetVariable(var);
2236     decl->BindNode(field);
2237     return field;
2238 }
2239 
CreateLambdaImplicitCtor(const lexer::SourceRange & pos,bool isStaticReference)2240 ir::MethodDefinition *ETSChecker::CreateLambdaImplicitCtor(const lexer::SourceRange &pos, bool isStaticReference)
2241 {
2242     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
2243     ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
2244 
2245     // Create the parameters for the synthetic constructor
2246     auto [funcParamScope, var] = CreateLambdaCtorImplicitParam(params, pos, isStaticReference);
2247 
2248     // Create the scopes
2249     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), funcParamScope, false);
2250     auto *scope = VarBinder()->Allocator()->New<varbinder::FunctionScope>(Allocator(), funcParamScope);
2251 
2252     // If the reference refers to a static function, the constructor will be empty, otherwise, we have to make a
2253     // synthetic initializer to initialize the lambda class field
2254     if (!isStaticReference) {
2255         statements.push_back(CreateLambdaCtorFieldInit(util::StringView("field0"), var));
2256     }
2257 
2258     auto *body = Allocator()->New<ir::BlockStatement>(Allocator(), std::move(statements));
2259     body->SetScope(scope);
2260     auto *func =
2261         Allocator()->New<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), nullptr), body,
2262                                              ir::ScriptFunctionFlags::CONSTRUCTOR, false, Language(Language::Id::ETS));
2263     func->SetScope(scope);
2264     // Bind the scopes
2265     scope->BindNode(func);
2266     funcParamScope->BindNode(func);
2267     scope->BindParamScope(funcParamScope);
2268     funcParamScope->BindFunctionScope(scope);
2269 
2270     // Create the synthetic constructor
2271     auto *funcExpr = Allocator()->New<ir::FunctionExpression>(func);
2272     auto *key = Allocator()->New<ir::Identifier>("constructor", Allocator());
2273     func->SetIdent(key);
2274     auto *ctor = Allocator()->New<ir::MethodDefinition>(ir::MethodDefinitionKind::CONSTRUCTOR, key, funcExpr,
2275                                                         ir::ModifierFlags::NONE, Allocator(), false);
2276 
2277     // Set the parent nodes
2278     func->SetParent(funcExpr);
2279     funcExpr->SetParent(ctor);
2280 
2281     return ctor;
2282 }
2283 
CreateLambdaCtorImplicitParam(ArenaVector<ir::Expression * > & params,const lexer::SourceRange & pos,bool isStaticReference)2284 std::tuple<varbinder::FunctionParamScope *, varbinder::Variable *> ETSChecker::CreateLambdaCtorImplicitParam(
2285     ArenaVector<ir::Expression *> &params, const lexer::SourceRange &pos, bool isStaticReference)
2286 {
2287     // Create the function parameter scope
2288     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder());
2289 
2290     // Create the synthetic constructors parameter, if this is a static reference, we don't need any parameter,
2291     // since when initializing the lambda class, we don't need to save the instance object which we tried to get the
2292     // function reference through
2293     if (!isStaticReference) {
2294         auto *paramIdent = Allocator()->New<ir::Identifier>("field0", Allocator());
2295         auto *param = Allocator()->New<ir::ETSParameterExpression>(paramIdent, nullptr);
2296         paramIdent->SetRange(pos);
2297         auto [_, var] = VarBinder()->AddParamDecl(param);
2298         (void)_;
2299         paramIdent->SetVariable(var);
2300         params.push_back(param);
2301         return {paramCtx.GetScope(), var};
2302     }
2303 
2304     return {paramCtx.GetScope(), nullptr};
2305 }
2306 
CreateLambdaInvokeProto()2307 ir::MethodDefinition *ETSChecker::CreateLambdaInvokeProto()
2308 {
2309     // Create the template for the synthetic 'invoke' method, which will be used when the function type will be
2310     // called
2311     auto *name = Allocator()->New<ir::Identifier>("invoke", Allocator());
2312     auto *paramScope =
2313         VarBinder()->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), VarBinder()->GetScope());
2314     auto *scope = VarBinder()->Allocator()->New<varbinder::FunctionScope>(Allocator(), paramScope);
2315 
2316     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
2317     ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
2318     auto *body = Allocator()->New<ir::BlockStatement>(Allocator(), std::move(statements));
2319     body->SetScope(scope);
2320     auto *func = Allocator()->New<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), nullptr), body,
2321                                                       ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::PUBLIC, false,
2322                                                       Language(Language::Id::ETS));
2323     func->SetScope(scope);
2324 
2325     scope->BindNode(func);
2326     paramScope->BindNode(func);
2327     scope->BindParamScope(paramScope);
2328     paramScope->BindFunctionScope(scope);
2329 
2330     auto *funcExpr = Allocator()->New<ir::FunctionExpression>(func);
2331     func->SetIdent(name);
2332 
2333     auto *method = Allocator()->New<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, name, funcExpr,
2334                                                           ir::ModifierFlags::PUBLIC, Allocator(), false);
2335 
2336     funcExpr->SetParent(method);
2337     func->SetParent(funcExpr);
2338 
2339     return method;
2340 }
2341 
CreateLambdaFuncDecl(ir::MethodDefinition * func,varbinder::LocalScope * scope)2342 void ETSChecker::CreateLambdaFuncDecl(ir::MethodDefinition *func, varbinder::LocalScope *scope)
2343 {
2344     // Add the function declarations to the lambda class scope
2345     auto ctx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(VarBinder(), scope);
2346     auto [_, var] =
2347         VarBinder()->NewVarDecl<varbinder::FunctionDecl>(func->Start(), Allocator(), func->Id()->Name(), func);
2348     (void)_;
2349     var->AddFlag(varbinder::VariableFlags::METHOD);
2350     func->Function()->Id()->SetVariable(var);
2351 }
2352 
ResolveLambdaObject(ir::ClassDefinition * lambdaObject,Signature * signature,ETSObjectType * functionalInterface,ir::AstNode * refNode)2353 void ETSChecker::ResolveLambdaObject(ir::ClassDefinition *lambdaObject, Signature *signature,
2354                                      ETSObjectType *functionalInterface, ir::AstNode *refNode)
2355 {
2356     // Set the type information for the lambda class, which will be required by the compiler
2357     Type *targetType = signature->Owner();
2358     bool isStaticReference = signature->HasSignatureFlag(SignatureFlags::STATIC);
2359     varbinder::Variable *fieldVar {};
2360 
2361     // If this is NOT a static function reference, we have to set the field's type to the referenced signatures
2362     // owner type, because that will be the type of the instance object which will be saved in that field
2363     if (!isStaticReference) {
2364         auto *field = lambdaObject->Body()[0]->AsClassProperty();
2365         fieldVar = field->Key()->AsIdentifier()->Variable();
2366         field->SetTsType(targetType);
2367         fieldVar->SetTsType(targetType);
2368         auto *ctorFunc = lambdaObject->Body()[1]->AsMethodDefinition()->Function();
2369         ctorFunc->Params()[0]->AsETSParameterExpression()->Variable()->SetTsType(targetType);
2370     }
2371 
2372     // Create the class type for the lambda
2373     auto *lambdaObjectType = Allocator()->New<checker::ETSObjectType>(Allocator(), lambdaObject->Ident()->Name(),
2374                                                                       lambdaObject->Ident()->Name(), lambdaObject,
2375                                                                       checker::ETSObjectFlags::CLASS);
2376 
2377     // Add the target function type to the implementing interfaces, this way, we can call the functional interface
2378     // virtual 'invoke' method and it will propagate the call to the currently stored lambda class 'invoke' function
2379     // which was assigned to the variable
2380     lambdaObjectType->AddInterface(functionalInterface);
2381     lambdaObject->SetTsType(lambdaObjectType);
2382 
2383     // Add the field if this is not a static reference to the lambda class type
2384     if (!isStaticReference) {
2385         lambdaObjectType->AddProperty<checker::PropertyType::INSTANCE_FIELD>(fieldVar->AsLocalVariable());
2386     }
2387     VarBinder()->AsETSBinder()->BuildLambdaObjectName(refNode);
2388 
2389     // Resolve the constructor
2390     ResolveLambdaObjectCtor(lambdaObject, isStaticReference);
2391 
2392     // Resolve the invoke function
2393     ResolveLambdaObjectInvoke(lambdaObject, signature);
2394 }
2395 
ResolveLambdaObjectCtor(ir::ClassDefinition * lambdaObject,bool isStaticReference)2396 void ETSChecker::ResolveLambdaObjectCtor(ir::ClassDefinition *lambdaObject, bool isStaticReference)
2397 {
2398     const auto &lambdaBody = lambdaObject->Body();
2399     auto *ctorFunc = lambdaBody[lambdaBody.size() - 2]->AsMethodDefinition()->Function();
2400     ETSObjectType *lambdaObjectType = lambdaObject->TsType()->AsETSObjectType();
2401     varbinder::Variable *fieldVar {};
2402 
2403     if (!isStaticReference) {
2404         auto *field = lambdaBody[0]->AsClassProperty();
2405         fieldVar = field->Key()->AsIdentifier()->Variable();
2406     }
2407 
2408     // Set the implicit 'this' parameters type to the lambda object
2409     auto *thisVar = ctorFunc->Scope()->ParamScope()->Params().front();
2410     thisVar->SetTsType(lambdaObjectType);
2411 
2412     // Create the signature for the constructor function type
2413     auto *ctorSignatureInfo = CreateSignatureInfo();
2414     ctorSignatureInfo->restVar = nullptr;
2415 
2416     if (isStaticReference) {
2417         ctorSignatureInfo->minArgCount = 0;
2418     } else {
2419         ctorSignatureInfo->minArgCount = 1;
2420         ctorSignatureInfo->params.push_back(
2421             ctorFunc->Params()[0]->AsETSParameterExpression()->Variable()->AsLocalVariable());
2422     }
2423 
2424     // Create the function type for the constructor
2425     auto *ctorSignature = CreateSignature(ctorSignatureInfo, GlobalVoidType(), ctorFunc);
2426     ctorSignature->SetOwner(lambdaObjectType);
2427     ctorSignature->AddSignatureFlag(checker::SignatureFlags::CONSTRUCTOR | checker::SignatureFlags::CONSTRUCT);
2428     lambdaObjectType->AddConstructSignature(ctorSignature);
2429 
2430     auto *ctorType = CreateETSFunctionType(ctorSignature);
2431     ctorFunc->SetSignature(ctorSignature);
2432     ctorFunc->Id()->Variable()->SetTsType(ctorType);
2433     VarBinder()->AsETSBinder()->BuildFunctionName(ctorFunc);
2434 
2435     // If this is a static function reference, we are done, since the constructor body is empty
2436     if (isStaticReference) {
2437         return;
2438     }
2439 
2440     // Otherwise, set the type information for the field initializer
2441     auto *fieldinit = ctorFunc->Body()
2442                           ->AsBlockStatement()
2443                           ->Statements()[0]
2444                           ->AsExpressionStatement()
2445                           ->GetExpression()
2446                           ->AsAssignmentExpression();
2447 
2448     auto *leftHandSide = fieldinit->Left();
2449     leftHandSide->AsMemberExpression()->SetObjectType(lambdaObjectType);
2450     leftHandSide->AsMemberExpression()->SetPropVar(fieldVar->AsLocalVariable());
2451     leftHandSide->AsMemberExpression()->SetTsType(fieldVar->TsType());
2452     leftHandSide->AsMemberExpression()->Object()->SetTsType(lambdaObjectType);
2453     fieldinit->Right()->AsIdentifier()->SetVariable(ctorSignature->Params()[0]);
2454     fieldinit->Right()->SetTsType(ctorSignature->Params()[0]->TsType());
2455 }
2456 
ResolveLambdaObjectInvoke(ir::ClassDefinition * lambdaObject,Signature * signatureRef)2457 void ETSChecker::ResolveLambdaObjectInvoke(ir::ClassDefinition *lambdaObject, Signature *signatureRef)
2458 {
2459     const auto &lambdaBody = lambdaObject->Body();
2460     auto *invokeFunc = lambdaBody[lambdaBody.size() - 1]->AsMethodDefinition()->Function();
2461     ETSObjectType *lambdaObjectType = lambdaObject->TsType()->AsETSObjectType();
2462 
2463     // Set the implicit 'this' parameters type to the lambda object
2464     auto *thisVar = invokeFunc->Scope()->ParamScope()->Params().front();
2465     thisVar->SetTsType(lambdaObjectType);
2466 
2467     // Create the signature for the invoke function type
2468     auto *invokeSignatureInfo = CreateSignatureInfo();
2469     invokeSignatureInfo->restVar = nullptr;
2470 
2471     // Create the parameters for the invoke function, based on the referenced function's signature
2472     for (auto *it : signatureRef->Params()) {
2473         auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(
2474             VarBinder(), invokeFunc->Scope()->ParamScope(), false);
2475 
2476         auto *paramIdent = Allocator()->New<ir::Identifier>(it->Name(), Allocator());
2477         auto *param = Allocator()->New<ir::ETSParameterExpression>(paramIdent, nullptr);
2478         auto [_, var] = VarBinder()->AddParamDecl(param);
2479         (void)_;
2480         var->SetTsType(it->TsType());
2481         paramIdent->SetVariable(var);
2482         invokeFunc->Params().push_back(param);
2483         invokeSignatureInfo->minArgCount++;
2484         invokeSignatureInfo->params.push_back(var->AsLocalVariable());
2485     }
2486 
2487     // Create the function type for the constructor
2488     auto *invokeSignature = CreateSignature(invokeSignatureInfo, signatureRef->ReturnType(), invokeFunc);
2489     invokeSignature->SetOwner(lambdaObjectType);
2490     invokeSignature->AddSignatureFlag(checker::SignatureFlags::CALL);
2491 
2492     auto *invokeType = CreateETSFunctionType(invokeSignature);
2493     invokeFunc->SetSignature(invokeSignature);
2494     invokeFunc->Id()->Variable()->SetTsType(invokeType);
2495     VarBinder()->AsETSBinder()->BuildFunctionName(invokeFunc);
2496     lambdaObjectType->AddProperty<checker::PropertyType::INSTANCE_METHOD>(
2497         invokeFunc->Id()->Variable()->AsLocalVariable());
2498 
2499     // Fill out the type information for the body of the invoke function
2500 
2501     auto *resolvedLambdaInvokeFunctionBody = ResolveLambdaObjectInvokeFuncBody(lambdaObject, signatureRef);
2502 
2503     invokeFunc->Body()->AsBlockStatement()->Statements().push_back(resolvedLambdaInvokeFunctionBody);
2504     if (resolvedLambdaInvokeFunctionBody->IsExpressionStatement()) {
2505         invokeFunc->Body()->AsBlockStatement()->Statements().push_back(Allocator()->New<ir::ReturnStatement>(nullptr));
2506     }
2507 }
2508 
ResolveLambdaObjectInvokeFuncBody(ir::ClassDefinition * lambdaObject,Signature * signatureRef)2509 ir::Statement *ETSChecker::ResolveLambdaObjectInvokeFuncBody(ir::ClassDefinition *lambdaObject, Signature *signatureRef)
2510 {
2511     const auto &lambdaBody = lambdaObject->Body();
2512     bool isStaticReference = signatureRef->HasSignatureFlag(SignatureFlags::STATIC);
2513     ir::Identifier *fieldIdent {};
2514     ETSObjectType *fieldPropType {};
2515 
2516     // If this is a static function reference, we have to call the referenced function through the class itself
2517     if (isStaticReference) {
2518         fieldIdent = Allocator()->New<ir::Identifier>(signatureRef->Owner()->Name(), Allocator());
2519         fieldPropType = signatureRef->Owner();
2520         fieldIdent->SetVariable(signatureRef->Owner()->Variable());
2521         fieldIdent->SetTsType(fieldPropType);
2522     } else {
2523         // Otherwise, we should call the referenced function through the saved field, which hold the object instance
2524         // reference
2525         auto *fieldProp = lambdaBody[0]->AsClassProperty()->Key()->AsIdentifier()->Variable();
2526         fieldPropType = fieldProp->TsType()->AsETSObjectType();
2527         fieldIdent = Allocator()->New<ir::Identifier>("field0", Allocator());
2528         fieldIdent->SetVariable(fieldProp);
2529         fieldIdent->SetTsType(fieldPropType);
2530     }
2531 
2532     // Set the type information for the function reference call
2533     auto *funcIdent = Allocator()->New<ir::Identifier>(signatureRef->Function()->Id()->Name(), Allocator());
2534     auto *callee = Allocator()->New<ir::MemberExpression>(fieldIdent, funcIdent,
2535                                                           ir::MemberExpressionKind::ELEMENT_ACCESS, false, false);
2536     callee->SetPropVar(signatureRef->OwnerVar()->AsLocalVariable());
2537     callee->SetObjectType(fieldPropType);
2538     callee->SetTsType(signatureRef->OwnerVar()->TsType());
2539 
2540     // Create the parameters for the referenced function call
2541     auto *invokeFunc = lambdaBody[lambdaBody.size() - 1]->AsMethodDefinition()->Function();
2542     ArenaVector<ir::Expression *> callParams(Allocator()->Adapter());
2543     for (size_t idx = 0; idx != signatureRef->Params().size(); idx++) {
2544         auto *paramIdent = Allocator()->New<ir::Identifier>(signatureRef->Params()[idx]->Name(), Allocator());
2545         paramIdent->SetVariable(invokeFunc->Params()[idx]->AsETSParameterExpression()->Variable());
2546         paramIdent->SetTsType(invokeFunc->Params()[idx]->AsETSParameterExpression()->Variable()->TsType());
2547         callParams.push_back(paramIdent);
2548     }
2549 
2550     // Create the synthetic call expression to the referenced function
2551     auto *resolvedCall = Allocator()->New<ir::CallExpression>(callee, std::move(callParams), nullptr, false);
2552     resolvedCall->SetTsType(signatureRef->ReturnType());
2553     resolvedCall->SetSignature(signatureRef);
2554 
2555     if (signatureRef->ReturnType()->IsETSVoidType()) {
2556         return Allocator()->New<ir::ExpressionStatement>(resolvedCall);
2557     }
2558 
2559     return Allocator()->New<ir::ReturnStatement>(resolvedCall);
2560 }
2561 
AreOverrideEquivalent(Signature * const s1,Signature * const s2)2562 bool ETSChecker::AreOverrideEquivalent(Signature *const s1, Signature *const s2)
2563 {
2564     // Two functions, methods or constructors M and N have the same signature if
2565     // their names and type parameters (if any) are the same, and their formal parameter
2566     // types are also the same (after the formal parameter types of N are adapted to the type parameters of M).
2567     // Signatures s1 and s2 are override-equivalent only if s1 and s2 are the same.
2568 
2569     return s1->Function()->Id()->Name() == s2->Function()->Id()->Name() && Relation()->IsIdenticalTo(s1, s2);
2570 }
2571 
IsReturnTypeSubstitutable(Signature * const s1,Signature * const s2)2572 bool ETSChecker::IsReturnTypeSubstitutable(Signature *const s1, Signature *const s2)
2573 {
2574     auto *const r1 = s1->ReturnType();
2575     auto *const r2 = s2->ReturnType();
2576 
2577     // A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return
2578     // type R2 if any of the following is true:
2579 
2580     // - If R1 is a primitive type then R2 is identical to R1.
2581     if (r1->HasTypeFlag(TypeFlag::ETS_PRIMITIVE | TypeFlag::ETS_ENUM | TypeFlag::ETS_STRING_ENUM)) {
2582         return Relation()->IsIdenticalTo(r2, r1);
2583     }
2584 
2585     // - If R1 is a reference type then R1, adapted to the type parameters of d2 (link to generic methods), is a
2586     // subtype of R2.
2587     ASSERT(r1->HasTypeFlag(TypeFlag::ETS_ARRAY_OR_OBJECT) || r1->IsETSTypeParameter());
2588     return Relation()->IsSupertypeOf(r2, r1);
2589 }
2590 
GetAsyncImplName(const util::StringView & name)2591 std::string ETSChecker::GetAsyncImplName(const util::StringView &name)
2592 {
2593     std::string implName(name);
2594     implName += "$asyncimpl";
2595     return implName;
2596 }
2597 
GetAsyncImplName(ir::MethodDefinition * asyncMethod)2598 std::string ETSChecker::GetAsyncImplName(ir::MethodDefinition *asyncMethod)
2599 {
2600     ir::Identifier *asyncName = asyncMethod->Function()->Id();
2601     ASSERT(asyncName != nullptr);
2602     return GetAsyncImplName(asyncName->Name());
2603 }
2604 
CreateAsyncImplMethod(ir::MethodDefinition * asyncMethod,ir::ClassDefinition * classDef)2605 ir::MethodDefinition *ETSChecker::CreateAsyncImplMethod(ir::MethodDefinition *asyncMethod,
2606                                                         ir::ClassDefinition *classDef)
2607 {
2608     util::UString implName(GetAsyncImplName(asyncMethod), Allocator());
2609     ir::ModifierFlags modifiers = asyncMethod->Modifiers();
2610     // clear ASYNC flag for implementation
2611     modifiers &= ~ir::ModifierFlags::ASYNC;
2612     ir::ScriptFunction *asyncFunc = asyncMethod->Function();
2613     ir::ScriptFunctionFlags flags = ir::ScriptFunctionFlags::METHOD;
2614     if (asyncFunc->IsProxy()) {
2615         flags |= ir::ScriptFunctionFlags::PROXY;
2616     }
2617     asyncMethod->AddModifier(ir::ModifierFlags::NATIVE);
2618     asyncFunc->AddModifier(ir::ModifierFlags::NATIVE);
2619     // Create async_impl method copied from CreateInvokeFunction
2620     auto scopeCtx =
2621         varbinder::LexicalScope<varbinder::ClassScope>::Enter(VarBinder(), classDef->Scope()->AsClassScope());
2622     auto *body = asyncFunc->Body();
2623     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
2624     varbinder::FunctionParamScope *paramScope = CopyParams(asyncFunc->Params(), params);
2625 
2626     // Set impl method return type "Object" because it may return Promise as well as Promise parameter's type
2627     auto *objectId = Allocator()->New<ir::Identifier>(compiler::Signatures::BUILTIN_OBJECT_CLASS, Allocator());
2628     objectId->SetReference();
2629     VarBinder()->AsETSBinder()->LookupTypeReference(objectId, false);
2630     auto *returnTypeAnn =
2631         Allocator()->New<ir::ETSTypeReference>(Allocator()->New<ir::ETSTypeReferencePart>(objectId, nullptr, nullptr));
2632     objectId->SetParent(returnTypeAnn->Part());
2633     returnTypeAnn->Part()->SetParent(returnTypeAnn);
2634     auto *asyncFuncRetTypeAnn = asyncFunc->ReturnTypeAnnotation();
2635     auto *promiseType = [this](ir::TypeNode *type) {
2636         if (type != nullptr) {
2637             return GetTypeFromTypeAnnotation(type)->AsETSObjectType();
2638         }
2639 
2640         return GlobalBuiltinPromiseType()->AsETSObjectType();
2641     }(asyncFuncRetTypeAnn);
2642 
2643     auto *retType = Allocator()->New<ETSAsyncFuncReturnType>(Allocator(), promiseType);
2644     returnTypeAnn->SetTsType(retType);
2645 
2646     ir::MethodDefinition *implMethod =
2647         CreateMethod(implName.View(), modifiers, flags, std::move(params), paramScope, returnTypeAnn, body);
2648     asyncFunc->SetBody(nullptr);
2649     returnTypeAnn->SetParent(implMethod->Function());
2650     implMethod->SetParent(asyncMethod->Parent());
2651     std::for_each(implMethod->Function()->Params().begin(), implMethod->Function()->Params().end(),
2652                   [implMethod](ir::Expression *param) { param->SetParent(implMethod->Function()); });
2653     return implMethod;
2654 }
2655 
CreateAsyncProxy(ir::MethodDefinition * asyncMethod,ir::ClassDefinition * classDef,bool createDecl)2656 ir::MethodDefinition *ETSChecker::CreateAsyncProxy(ir::MethodDefinition *asyncMethod, ir::ClassDefinition *classDef,
2657                                                    bool createDecl)
2658 {
2659     ir::ScriptFunction *asyncFunc = asyncMethod->Function();
2660     VarBinder()->AsETSBinder()->GetRecordTable()->Signatures().push_back(asyncFunc->Scope());
2661 
2662     ir::MethodDefinition *implMethod = CreateAsyncImplMethod(asyncMethod, classDef);
2663     varbinder::FunctionScope *implFuncScope = implMethod->Function()->Scope();
2664     for (auto *decl : asyncFunc->Scope()->Decls()) {
2665         auto res = asyncFunc->Scope()->Bindings().find(decl->Name());
2666         ASSERT(res != asyncFunc->Scope()->Bindings().end());
2667         auto *const var = std::get<1>(*res);
2668         var->SetScope(implFuncScope);
2669         implFuncScope->Decls().push_back(decl);
2670         implFuncScope->InsertBinding(decl->Name(), var);
2671     }
2672     for (const auto &entry : asyncFunc->Scope()->Bindings()) {
2673         auto *var = entry.second;
2674         var->SetScope(implFuncScope);
2675         implFuncScope->InsertBinding(entry.first, entry.second);
2676     }
2677     ReplaceScope(implMethod->Function()->Body(), asyncFunc, implFuncScope);
2678 
2679     ArenaVector<varbinder::Variable *> captured(Allocator()->Adapter());
2680 
2681     bool isStatic = asyncMethod->IsStatic();
2682     if (createDecl) {
2683         if (isStatic) {
2684             CreateLambdaFuncDecl(implMethod, classDef->Scope()->AsClassScope()->StaticMethodScope());
2685         } else {
2686             CreateLambdaFuncDecl(implMethod, classDef->Scope()->AsClassScope()->InstanceMethodScope());
2687         }
2688     }
2689     VarBinder()->AsETSBinder()->BuildProxyMethod(implMethod->Function(), classDef->InternalName(), isStatic);
2690     implMethod->SetParent(asyncMethod->Parent());
2691 
2692     return implMethod;
2693 }
2694 
CreateMethod(const util::StringView & name,ir::ModifierFlags modifiers,ir::ScriptFunctionFlags flags,ArenaVector<ir::Expression * > && params,varbinder::FunctionParamScope * paramScope,ir::TypeNode * returnType,ir::AstNode * body)2695 ir::MethodDefinition *ETSChecker::CreateMethod(const util::StringView &name, ir::ModifierFlags modifiers,
2696                                                ir::ScriptFunctionFlags flags, ArenaVector<ir::Expression *> &&params,
2697                                                varbinder::FunctionParamScope *paramScope, ir::TypeNode *returnType,
2698                                                ir::AstNode *body)
2699 {
2700     auto *nameId = Allocator()->New<ir::Identifier>(name, Allocator());
2701     auto *scope = VarBinder()->Allocator()->New<varbinder::FunctionScope>(Allocator(), paramScope);
2702     ir::ScriptFunction *func =
2703         Allocator()->New<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), returnType), body, flags,
2704                                              modifiers, false, Language(Language::Id::ETS));
2705     func->SetScope(scope);
2706     func->SetIdent(nameId);
2707     body->SetParent(func);
2708     if (body->IsBlockStatement()) {
2709         body->AsBlockStatement()->SetScope(scope);
2710     }
2711     scope->BindNode(func);
2712     paramScope->BindNode(func);
2713     scope->BindParamScope(paramScope);
2714     paramScope->BindFunctionScope(scope);
2715     auto *funcExpr = Allocator()->New<ir::FunctionExpression>(func);
2716     auto *method = Allocator()->New<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, nameId, funcExpr, modifiers,
2717                                                           Allocator(), false);
2718     funcExpr->SetParent(method);
2719     func->SetParent(funcExpr);
2720     nameId->SetParent(method);
2721 
2722     return method;
2723 }
2724 
CopyParams(const ArenaVector<ir::Expression * > & params,ArenaVector<ir::Expression * > & outParams)2725 varbinder::FunctionParamScope *ETSChecker::CopyParams(const ArenaVector<ir::Expression *> &params,
2726                                                       ArenaVector<ir::Expression *> &outParams)
2727 {
2728     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder());
2729 
2730     for (auto *const it : params) {
2731         auto *const paramOld = it->AsETSParameterExpression();
2732         auto *const paramNew = paramOld->Clone(Allocator(), paramOld->Parent())->AsETSParameterExpression();
2733 
2734         auto *const var = std::get<1>(VarBinder()->AddParamDecl(paramNew));
2735         var->SetTsType(paramOld->Ident()->Variable()->TsType());
2736         var->SetScope(paramCtx.GetScope());
2737         paramNew->SetVariable(var);
2738 
2739         paramNew->SetTsType(paramOld->TsType());
2740 
2741         outParams.emplace_back(paramNew);
2742     }
2743 
2744     return paramCtx.GetScope();
2745 }
2746 
ReplaceScope(ir::AstNode * root,ir::AstNode * oldNode,varbinder::Scope * newScope)2747 void ETSChecker::ReplaceScope(ir::AstNode *root, ir::AstNode *oldNode, varbinder::Scope *newScope)
2748 {
2749     root->Iterate([this, oldNode, newScope](ir::AstNode *child) {
2750         auto *scope = NodeScope(child);
2751         if (scope != nullptr) {
2752             while (scope->Parent() != nullptr && scope->Parent()->Node() != oldNode) {
2753                 scope = scope->Parent();
2754             }
2755             scope->SetParent(newScope);
2756         } else {
2757             ReplaceScope(child, oldNode, newScope);
2758         }
2759     });
2760 }
2761 
MoveTrailingBlockToEnclosingBlockStatement(ir::CallExpression * callExpr)2762 void ETSChecker::MoveTrailingBlockToEnclosingBlockStatement(ir::CallExpression *callExpr)
2763 {
2764     if (callExpr == nullptr) {
2765         return;
2766     }
2767 
2768     ir::AstNode *parent = callExpr->Parent();
2769     ir::AstNode *current = callExpr;
2770     while (parent != nullptr) {
2771         if (!parent->IsBlockStatement()) {
2772             current = parent;
2773             parent = parent->Parent();
2774         } else {
2775             // Collect trailing block, insert it only when block statements traversal ends to avoid order mismatch.
2776             parent->AsBlockStatement()->AddTrailingBlock(current, callExpr->TrailingBlock());
2777             callExpr->TrailingBlock()->SetParent(parent);
2778             callExpr->SetTrailingBlock(nullptr);
2779             break;
2780         }
2781     }
2782 }
2783 
TransformTraillingLambda(ir::CallExpression * callExpr)2784 void ETSChecker::TransformTraillingLambda(ir::CallExpression *callExpr)
2785 {
2786     auto *trailingBlock = callExpr->TrailingBlock();
2787     ASSERT(trailingBlock != nullptr);
2788 
2789     auto *funcParamScope = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder()).GetScope();
2790     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), funcParamScope, false);
2791 
2792     auto funcCtx = varbinder::LexicalScope<varbinder::FunctionScope>(VarBinder());
2793     auto *funcScope = funcCtx.GetScope();
2794     funcScope->BindParamScope(funcParamScope);
2795     funcParamScope->BindFunctionScope(funcScope);
2796     funcParamScope->SetParent(trailingBlock->Scope()->Parent());
2797 
2798     for (auto [_, var] : trailingBlock->Scope()->Bindings()) {
2799         (void)_;
2800         if (var->GetScope() == trailingBlock->Scope()) {
2801             var->SetScope(funcScope);
2802         }
2803     }
2804     funcScope->ReplaceBindings(trailingBlock->Scope()->Bindings());
2805 
2806     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
2807     auto *funcNode =
2808         AllocNode<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), nullptr), trailingBlock,
2809                                       ir::ScriptFunctionFlags::ARROW, false, Language(Language::Id::ETS));
2810     funcNode->SetScope(funcScope);
2811     funcScope->BindNode(funcNode);
2812     funcParamScope->BindNode(funcNode);
2813 
2814     trailingBlock->SetScope(funcScope);
2815     ReplaceScope(funcNode->Body(), trailingBlock, funcScope);
2816     callExpr->SetTrailingBlock(nullptr);
2817 
2818     auto *arrowFuncNode = AllocNode<ir::ArrowFunctionExpression>(Allocator(), funcNode);
2819     arrowFuncNode->SetRange(trailingBlock->Range());
2820     arrowFuncNode->SetParent(callExpr);
2821 
2822     callExpr->Arguments().push_back(arrowFuncNode);
2823 }
2824 
ExtendArgumentsWithFakeLamda(ir::CallExpression * callExpr)2825 ArenaVector<ir::Expression *> ETSChecker::ExtendArgumentsWithFakeLamda(ir::CallExpression *callExpr)
2826 {
2827     auto funcCtx = varbinder::LexicalScope<varbinder::FunctionScope>(VarBinder());
2828     auto *funcScope = funcCtx.GetScope();
2829     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
2830 
2831     ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
2832     auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
2833     body->SetScope(funcScope);
2834 
2835     auto *funcNode = AllocNode<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), nullptr), body,
2836                                                    ir::ScriptFunctionFlags::ARROW, false, Language(Language::Id::ETS));
2837     funcNode->SetScope(funcScope);
2838     funcScope->BindNode(funcNode);
2839     auto *arrowFuncNode = AllocNode<ir::ArrowFunctionExpression>(Allocator(), funcNode);
2840     arrowFuncNode->SetParent(callExpr);
2841 
2842     ArenaVector<ir::Expression *> fakeArguments = callExpr->Arguments();
2843     fakeArguments.push_back(arrowFuncNode);
2844     return fakeArguments;
2845 }
2846 
EnsureValidCurlyBrace(ir::CallExpression * callExpr)2847 void ETSChecker::EnsureValidCurlyBrace(ir::CallExpression *callExpr)
2848 {
2849     if (callExpr->TrailingBlock() == nullptr) {
2850         return;
2851     }
2852 
2853     if (callExpr->IsTrailingBlockInNewLine()) {
2854         MoveTrailingBlockToEnclosingBlockStatement(callExpr);
2855         return;
2856     }
2857 
2858     ThrowTypeError({"No matching call signature with trailing lambda"}, callExpr->Start());
2859 }
2860 }  // namespace panda::es2panda::checker
2861