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