• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 - 2023 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 "checker/ETSchecker.h"
17 
18 #include "varbinder/scope.h"
19 #include "varbinder/declaration.h"
20 #include "varbinder/varbinder.h"
21 #include "varbinder/ETSBinder.h"
22 #include "checker/types/ets/etsDynamicFunctionType.h"
23 #include "ir/base/classProperty.h"
24 #include "ir/base/classStaticBlock.h"
25 #include "ir/base/methodDefinition.h"
26 #include "ir/base/scriptFunction.h"
27 #include "ir/expressions/assignmentExpression.h"
28 #include "ir/expressions/callExpression.h"
29 #include "ir/expressions/functionExpression.h"
30 #include "ir/expressions/identifier.h"
31 #include "ir/expressions/thisExpression.h"
32 #include "ir/expressions/memberExpression.h"
33 #include "ir/ets/etsPrimitiveType.h"
34 #include "ir/ts/tsAsExpression.h"
35 #include "ir/statements/blockStatement.h"
36 #include "ir/statements/classDeclaration.h"
37 #include "ir/statements/expressionStatement.h"
38 #include "ir/statements/returnStatement.h"
39 #include "ir/statements/variableDeclaration.h"
40 #include "ir/statements/variableDeclarator.h"
41 #include "parser/program/program.h"
42 #include "util/helpers.h"
43 #include "util/language.h"
44 #include "generated/signatures.h"
45 #include "ir/ets/etsParameterExpression.h"
46 
47 namespace panda::es2panda::checker {
48 
AddParam(varbinder::FunctionParamScope * paramScope,util::StringView name,checker::Type * type)49 ir::ETSParameterExpression *ETSChecker::AddParam(varbinder::FunctionParamScope *paramScope, util::StringView name,
50                                                  checker::Type *type)
51 {
52     auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), paramScope, false);
53     auto *paramIdent = AllocNode<ir::Identifier>(name, Allocator());
54     auto *param = AllocNode<ir::ETSParameterExpression>(paramIdent, nullptr);
55     auto *paramVar = std::get<1>(VarBinder()->AddParamDecl(param));
56     paramVar->SetTsType(type);
57     param->Ident()->SetVariable(paramVar);
58     param->Ident()->SetTsType(type);
59     return param;
60 }
61 
IsByValueCall(varbinder::ETSBinder * varbinder,ir::Expression * callee)62 static bool IsByValueCall(varbinder::ETSBinder *varbinder, ir::Expression *callee)
63 {
64     if (callee->IsMemberExpression()) {
65         return !callee->AsMemberExpression()->ObjType()->IsETSDynamicType();
66     }
67 
68     if (callee->IsETSTypeReference()) {
69         return false;
70     }
71 
72     auto *var = callee->AsIdentifier()->Variable();
73     auto *data = varbinder->DynamicImportDataForVar(var);
74     if (data != nullptr) {
75         auto *specifier = data->specifier;
76         if (specifier->IsImportSpecifier()) {
77             return false;
78         }
79     }
80 
81     return true;
82 }
83 
84 template <typename T>
CreateDynamicCallIntrinsic(ir::Expression * callee,const ArenaVector<T * > & arguments,Language lang)85 ir::ScriptFunction *ETSChecker::CreateDynamicCallIntrinsic(ir::Expression *callee, const ArenaVector<T *> &arguments,
86                                                            Language lang)
87 {
88     auto *name = AllocNode<ir::Identifier>("invoke", Allocator());
89     auto *paramScope = Allocator()->New<varbinder::FunctionParamScope>(Allocator(), nullptr);
90     auto *scope = Allocator()->New<varbinder::FunctionScope>(Allocator(), paramScope);
91 
92     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
93 
94     auto *info = CreateSignatureInfo();
95     info->minArgCount = arguments.size() + 2U;
96 
97     auto dynamicType = GlobalBuiltinDynamicType(lang);
98 
99     auto *objParam = AddParam(paramScope, "obj", dynamicType);
100     params.push_back(objParam);
101     info->params.push_back(objParam->Ident()->Variable()->AsLocalVariable());
102 
103     ir::ETSParameterExpression *param2;
104     if (!IsByValueCall(VarBinder()->AsETSBinder(), callee)) {
105         param2 = AddParam(paramScope, "qname", GlobalETSStringLiteralType());
106     } else {
107         param2 = AddParam(paramScope, "this", dynamicType);
108     }
109 
110     params.push_back(param2);
111     info->params.push_back(param2->Ident()->Variable()->AsLocalVariable());
112 
113     for (size_t i = 0; i < arguments.size(); i++) {
114         util::UString paramName("p" + std::to_string(i), Allocator());
115         Type *paramType =
116             arguments[i]->TsType()->IsLambdaObject() ? GlobalBuiltinJSValueType() : arguments[i]->TsType();
117         ir::ETSParameterExpression *param = AddParam(paramScope, paramName.View(), paramType);
118         params.push_back(param);
119         info->params.push_back(param->Ident()->Variable()->AsLocalVariable());
120     }
121 
122     auto *func = AllocNode<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), nullptr), nullptr,
123                                                ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::NONE, false,
124                                                Language(Language::Id::ETS));
125     func->SetScope(scope);
126 
127     scope->BindNode(func);
128     paramScope->BindNode(func);
129     scope->BindParamScope(paramScope);
130     paramScope->BindFunctionScope(scope);
131 
132     func->SetIdent(name);
133 
134     auto *signature = CreateSignature(info, dynamicType, func);
135     signature->AddSignatureFlag(SignatureFlags::STATIC);
136 
137     func->SetSignature(signature);
138 
139     return func;
140 }
141 
ToString(ETSChecker * checker,const ArenaVector<ir::Expression * > & arguments,std::stringstream & ss)142 static void ToString(ETSChecker *checker, const ArenaVector<ir::Expression *> &arguments, std::stringstream &ss)
143 {
144     for (auto *arg : arguments) {
145         auto *type = arg->Check(checker);
146         ss << "-";
147         type->ToString(ss);
148     }
149 }
150 
ToString(ETSChecker * checker,const ArenaVector<varbinder::LocalVariable * > & arguments,std::stringstream & ss)151 static void ToString([[maybe_unused]] ETSChecker *checker, const ArenaVector<varbinder::LocalVariable *> &arguments,
152                      std::stringstream &ss)
153 {
154     for (auto *arg : arguments) {
155         auto *type = arg->TsType();
156         ss << "-";
157         type->ToString(ss);
158     }
159 }
160 
161 template <typename T>
ResolveDynamicCallExpression(ir::Expression * callee,const ArenaVector<T * > & arguments,Language lang,bool isConstruct)162 Signature *ETSChecker::ResolveDynamicCallExpression(ir::Expression *callee, const ArenaVector<T *> &arguments,
163                                                     Language lang, bool isConstruct)
164 {
165     auto &dynamicIntrinsics = *DynamicCallIntrinsics(isConstruct);
166 
167     auto mapIt = dynamicIntrinsics.find(lang);
168     if (mapIt == dynamicIntrinsics.cend()) {
169         std::tie(mapIt, std::ignore) = dynamicIntrinsics.emplace(lang, Allocator()->Adapter());
170     }
171 
172     auto &map = mapIt->second;
173 
174     std::stringstream ss;
175     ss << "dyncall";
176     if (IsByValueCall(VarBinder()->AsETSBinder(), callee)) {
177         ss << "-byvalue";
178     }
179 
180     ToString(this, arguments, ss);
181 
182     auto key = ss.str();
183     auto it = map.find(util::StringView(key));
184     if (it == map.end()) {
185         auto *func = CreateDynamicCallIntrinsic(callee, arguments, lang);
186         map.emplace(util::UString(key, Allocator()).View(), func);
187         return func->Signature();
188     }
189 
190     return it->second->Signature();
191 }
192 
193 template Signature *ETSChecker::ResolveDynamicCallExpression<ir::Expression>(
194     ir::Expression *callee, const ArenaVector<ir::Expression *> &arguments, Language lang, bool is_construct);
195 
196 template Signature *ETSChecker::ResolveDynamicCallExpression<varbinder::LocalVariable>(
197     ir::Expression *callee, const ArenaVector<varbinder::LocalVariable *> &arguments, Language lang, bool is_construct);
198 
199 template <bool IS_STATIC>
CreateClassInitializer(varbinder::ClassScope * classScope,const ClassInitializerBuilder & builder,ETSObjectType * type)200 std::conditional_t<IS_STATIC, ir::ClassStaticBlock *, ir::MethodDefinition *> ETSChecker::CreateClassInitializer(
201     varbinder::ClassScope *classScope, const ClassInitializerBuilder &builder, ETSObjectType *type)
202 {
203     varbinder::LocalScope *methodScope = nullptr;
204     if constexpr (IS_STATIC) {
205         methodScope = classScope->StaticMethodScope();
206     } else {
207         methodScope = classScope->InstanceMethodScope();
208     }
209     auto classCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(VarBinder(), methodScope);
210 
211     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
212 
213     auto *paramScope = Allocator()->New<varbinder::FunctionParamScope>(Allocator(), classScope);
214     auto *scope = Allocator()->New<varbinder::FunctionScope>(Allocator(), paramScope);
215 
216     ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
217 
218     ir::ScriptFunction *func = nullptr;
219     ir::Identifier *id = nullptr;
220 
221     if constexpr (IS_STATIC) {
222         builder(scope, &statements, nullptr);
223         auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
224         body->SetScope(scope);
225         id = AllocNode<ir::Identifier>(compiler::Signatures::CCTOR, Allocator());
226         func =
227             AllocNode<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), nullptr), body,
228                                           ir::ScriptFunctionFlags::STATIC_BLOCK | ir::ScriptFunctionFlags::EXPRESSION,
229                                           ir::ModifierFlags::STATIC, false, Language(Language::Id::ETS));
230         func->SetScope(scope);
231     } else {
232         builder(scope, &statements, &params);
233         auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
234         body->SetScope(scope);
235         id = AllocNode<ir::Identifier>(compiler::Signatures::CTOR, Allocator());
236         func = AllocNode<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), nullptr), body,
237                                              ir::ScriptFunctionFlags::CONSTRUCTOR | ir::ScriptFunctionFlags::EXPRESSION,
238                                              ir::ModifierFlags::PUBLIC, false, Language(Language::Id::ETS));
239         func->SetScope(scope);
240     }
241 
242     scope->BindNode(func);
243     func->SetIdent(id);
244     paramScope->BindNode(func);
245     scope->BindParamScope(paramScope);
246     paramScope->BindFunctionScope(scope);
247 
248     auto *signatureInfo = CreateSignatureInfo();
249     signatureInfo->restVar = nullptr;
250     auto *signature = CreateSignature(signatureInfo, GlobalVoidType(), func);
251     func->SetSignature(signature);
252 
253     auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
254 
255     VarBinder()->AsETSBinder()->BuildInternalName(func);
256     VarBinder()->AsETSBinder()->BuildFunctionName(func);
257     VarBinder()->Functions().push_back(func->Scope());
258 
259     if constexpr (IS_STATIC) {
260         auto *staticBlock = AllocNode<ir::ClassStaticBlock>(funcExpr, Allocator());
261         staticBlock->AddModifier(ir::ModifierFlags::STATIC);
262         return staticBlock;
263     } else {
264         type->AddConstructSignature(signature);
265 
266         auto *ctor = Allocator()->New<ir::MethodDefinition>(ir::MethodDefinitionKind::CONSTRUCTOR, id, funcExpr,
267                                                             ir::ModifierFlags::NONE, Allocator(), false);
268         auto *funcType = CreateETSFunctionType(signature, id->Name());
269         ctor->SetTsType(funcType);
270         funcExpr->SetParent(classScope->Node()->AsClassDeclaration()->Definition());
271         func->SetParent(ctor);
272         return ctor;
273     }
274 }
275 
CreateDynamicCallClassInitializer(varbinder::ClassScope * classScope,Language lang,bool isConstruct)276 ir::ClassStaticBlock *ETSChecker::CreateDynamicCallClassInitializer(varbinder::ClassScope *classScope, Language lang,
277                                                                     bool isConstruct)
278 {
279     return CreateClassInitializer<true>(
280         classScope, [this, lang, isConstruct](varbinder::FunctionScope *scope, ArenaVector<ir::Statement *> *statements,
281                                               [[maybe_unused]] ArenaVector<ir::Expression *> *params) {
282             auto [builtin_class_name, builtin_method_name] =
283                 util::Helpers::SplitSignature(isConstruct ? compiler::Signatures::Dynamic::InitNewClassBuiltin(lang)
284                                                           : compiler::Signatures::Dynamic::InitCallClassBuiltin(lang));
285             auto *classId = AllocNode<ir::Identifier>(builtin_class_name, Allocator());
286             auto *methodId = AllocNode<ir::Identifier>(builtin_method_name, Allocator());
287             auto *callee = AllocNode<ir::MemberExpression>(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS,
288                                                            false, false);
289 
290             ArenaVector<ir::Expression *> callParams(Allocator()->Adapter());
291 
292             std::stringstream ss;
293             auto name = isConstruct ? compiler::Signatures::Dynamic::NewClass(lang)
294                                     : compiler::Signatures::Dynamic::CallClass(lang);
295             auto package = VarBinder()->Program()->GetPackageName();
296 
297             ss << compiler::Signatures::CLASS_REF_BEGIN;
298             if (!package.Empty()) {
299                 std::string packageStr(package);
300                 std::replace(packageStr.begin(), packageStr.end(), *compiler::Signatures::METHOD_SEPARATOR.begin(),
301                              *compiler::Signatures::NAMESPACE_SEPARATOR.begin());
302                 ss << packageStr << compiler::Signatures::NAMESPACE_SEPARATOR;
303             }
304             ss << name << compiler::Signatures::MANGLE_SEPARATOR;
305 
306             auto *className = AllocNode<ir::StringLiteral>(util::UString(ss.str(), Allocator()).View());
307             callParams.push_back(className);
308 
309             auto *initCall = AllocNode<ir::CallExpression>(callee, std::move(callParams), nullptr, false);
310 
311             {
312                 ScopeContext ctx(this, scope);
313                 initCall->Check(this);
314             }
315 
316             statements->push_back(AllocNode<ir::ExpressionStatement>(initCall));
317         });
318 }
319 
BuildClass(util::StringView name,const ClassBuilder & builder)320 void ETSChecker::BuildClass(util::StringView name, const ClassBuilder &builder)
321 {
322     auto *classId = AllocNode<ir::Identifier>(name, Allocator());
323     auto [decl, var] = VarBinder()->NewVarDecl<varbinder::ClassDecl>(classId->Start(), classId->Name());
324     classId->SetVariable(var);
325 
326     auto classCtx = varbinder::LexicalScope<varbinder::ClassScope>(VarBinder());
327 
328     auto *classDef = AllocNode<ir::ClassDefinition>(Allocator(), classId, ir::ClassDefinitionModifiers::DECLARATION,
329                                                     ir::ModifierFlags::NONE, Language(Language::Id::ETS));
330     classDef->SetScope(classCtx.GetScope());
331 
332     auto *classDefType = Allocator()->New<checker::ETSObjectType>(
333         Allocator(), classDef->Ident()->Name(), classDef->Ident()->Name(), classDef, checker::ETSObjectFlags::CLASS);
334     classDef->SetTsType(classDefType);
335 
336     auto *classDecl = AllocNode<ir::ClassDeclaration>(classDef, Allocator());
337     classDecl->SetParent(VarBinder()->TopScope()->Node());
338     classDef->Scope()->BindNode(classDecl);
339     decl->BindNode(classDef);
340 
341     VarBinder()->Program()->Ast()->Statements().push_back(classDecl);
342 
343     varbinder::BoundContext boundCtx(VarBinder()->AsETSBinder()->GetGlobalRecordTable(), classDef);
344 
345     ArenaVector<ir::AstNode *> classBody(Allocator()->Adapter());
346 
347     builder(classCtx.GetScope(), &classBody);
348 
349     classDef->AddProperties(std::move(classBody));
350 }
351 
BuildDynamicCallClass(bool isConstruct)352 void ETSChecker::BuildDynamicCallClass(bool isConstruct)
353 {
354     auto &dynamicIntrinsics = *DynamicCallIntrinsics(isConstruct);
355 
356     if (dynamicIntrinsics.empty()) {
357         return;
358     }
359 
360     for (auto &entry : dynamicIntrinsics) {
361         auto lang = entry.first;
362         auto &intrinsics = entry.second;
363         auto className = isConstruct ? compiler::Signatures::Dynamic::NewClass(lang)
364                                      : compiler::Signatures::Dynamic::CallClass(lang);
365         BuildClass(className, [this, lang, &intrinsics, isConstruct](varbinder::ClassScope *scope,
366                                                                      ArenaVector<ir::AstNode *> *classBody) {
367             for (auto &[_, func] : intrinsics) {
368                 (void)_;
369 
370                 func->Scope()->ParamScope()->SetParent(scope);
371 
372                 auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
373 
374                 auto *method = AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, func->Id(), funcExpr,
375                                                                ir::ModifierFlags::PUBLIC | ir::ModifierFlags::NATIVE |
376                                                                    ir::ModifierFlags::STATIC,
377                                                                Allocator(), false);
378 
379                 VarBinder()->AsETSBinder()->BuildInternalName(func);
380                 VarBinder()->AsETSBinder()->BuildFunctionName(func);
381 
382                 classBody->push_back(method);
383             }
384 
385             classBody->push_back(CreateDynamicCallClassInitializer(scope, lang, isConstruct));
386         });
387     }
388 }
389 
CreateDynamicModuleClassInitializer(varbinder::ClassScope * classScope,const std::vector<ir::ETSImportDeclaration * > & imports)390 ir::ClassStaticBlock *ETSChecker::CreateDynamicModuleClassInitializer(
391     varbinder::ClassScope *classScope, const std::vector<ir::ETSImportDeclaration *> &imports)
392 {
393     return CreateClassInitializer<true>(
394         classScope, [this, imports](varbinder::FunctionScope *scope, ArenaVector<ir::Statement *> *statements,
395                                     [[maybe_unused]] ArenaVector<ir::Expression *> *params) {
396             for (auto *import : imports) {
397                 auto builtin = compiler::Signatures::Dynamic::LoadModuleBuiltin(import->Language());
398                 auto [builtin_class_name, builtin_method_name] = util::Helpers::SplitSignature(builtin);
399 
400                 auto *classId = AllocNode<ir::Identifier>(builtin_class_name, Allocator());
401                 auto *methodId = AllocNode<ir::Identifier>(builtin_method_name, Allocator());
402                 auto *callee = AllocNode<ir::MemberExpression>(classId, methodId,
403                                                                ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
404 
405                 ArenaVector<ir::Expression *> callParams(Allocator()->Adapter());
406                 callParams.push_back(import->ResolvedSource());
407 
408                 auto *loadCall = AllocNode<ir::CallExpression>(callee, std::move(callParams), nullptr, false);
409 
410                 auto *moduleClassId =
411                     AllocNode<ir::Identifier>(compiler::Signatures::DYNAMIC_MODULE_CLASS, Allocator());
412                 auto *fieldId = AllocNode<ir::Identifier>(import->AssemblerName(), Allocator());
413                 auto *property = AllocNode<ir::MemberExpression>(
414                     moduleClassId, fieldId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
415 
416                 auto *initializer =
417                     AllocNode<ir::AssignmentExpression>(property, loadCall, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
418 
419                 {
420                     ScopeContext ctx(this, scope);
421                     initializer->Check(this);
422                 }
423 
424                 statements->push_back(AllocNode<ir::ExpressionStatement>(initializer));
425             }
426         });
427 }
428 
429 template <bool IS_STATIC>
CreateClassMethod(varbinder::ClassScope * classScope,const std::string_view methodName,panda::es2panda::ir::ModifierFlags modifierFlags,const MethodBuilder & builder)430 ir::MethodDefinition *ETSChecker::CreateClassMethod(varbinder::ClassScope *classScope,
431                                                     const std::string_view methodName,
432                                                     panda::es2panda::ir::ModifierFlags modifierFlags,
433                                                     const MethodBuilder &builder)
434 {
435     auto classCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(VarBinder(), classScope->StaticMethodScope());
436     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
437     auto *paramScope = Allocator()->New<varbinder::FunctionParamScope>(Allocator(), classScope);
438     auto *scope = Allocator()->New<varbinder::FunctionScope>(Allocator(), paramScope);
439     auto *id = AllocNode<ir::Identifier>(methodName, Allocator());
440 
441     ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
442     Type *returnType = nullptr;
443 
444     builder(scope, &statements, &params, &returnType);
445 
446     auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
447     body->SetScope(scope);
448 
449     auto *func = AllocNode<ir::ScriptFunction>(ir::FunctionSignature(nullptr, std::move(params), nullptr), body,
450                                                ir::ScriptFunctionFlags::METHOD, modifierFlags, false,
451                                                Language(Language::Id::ETS));
452     func->SetScope(scope);
453     scope->BindNode(func);
454     func->SetIdent(id);
455     paramScope->BindNode(func);
456     scope->BindParamScope(paramScope);
457     paramScope->BindFunctionScope(scope);
458 
459     auto *signatureInfo = CreateSignatureInfo();
460     signatureInfo->restVar = nullptr;
461     auto *signature = CreateSignature(signatureInfo, returnType, func);
462     if constexpr (IS_STATIC) {
463         signature->AddSignatureFlag(SignatureFlags::STATIC);
464     }
465     func->SetSignature(signature);
466 
467     auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
468     auto *method = AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, func->Id(), funcExpr,
469                                                    modifierFlags, Allocator(), false);
470 
471     VarBinder()->AsETSBinder()->BuildInternalName(func);
472     VarBinder()->AsETSBinder()->BuildFunctionName(func);
473     VarBinder()->Functions().push_back(func->Scope());
474 
475     auto *decl = Allocator()->New<varbinder::LetDecl>(id->Name());
476     decl->BindNode(method);
477 
478     auto *funcType = CreateETSFunctionType(signature, id->Name());
479     auto *var = scope->AddDecl(Allocator(), decl, VarBinder()->Extension());
480     var->SetTsType(funcType);
481     method->SetTsType(funcType);
482     var->AddFlag(varbinder::VariableFlags::PROPERTY);
483     func->Id()->SetVariable(var);
484 
485     auto *classType = classScope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType();
486     if constexpr (IS_STATIC) {
487         classType->AddProperty<PropertyType::STATIC_METHOD>(var->AsLocalVariable());
488     } else {
489         classType->AddProperty<PropertyType::INSTANCE_METHOD>(var->AsLocalVariable());
490     }
491 
492     return method;
493 }
494 
CreateDynamicModuleClassInitMethod(varbinder::ClassScope * classScope)495 ir::MethodDefinition *ETSChecker::CreateDynamicModuleClassInitMethod(varbinder::ClassScope *classScope)
496 {
497     return CreateClassMethod<true>(classScope, compiler::Signatures::DYNAMIC_MODULE_CLASS_INIT,
498                                    ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC,
499                                    [this]([[maybe_unused]] varbinder::FunctionScope *scope,
500                                           [[maybe_unused]] ArenaVector<ir::Statement *> *statements,
501                                           [[maybe_unused]] ArenaVector<ir::Expression *> *params,
502                                           Type **returnType) { *returnType = GlobalBuiltinVoidType(); });
503 }
504 
CreateLambdaObjectClassInvokeMethod(varbinder::ClassScope * classScope,Signature * invokeSignature,ir::TypeNode * retTypeAnnotation)505 ir::MethodDefinition *ETSChecker::CreateLambdaObjectClassInvokeMethod(varbinder::ClassScope *classScope,
506                                                                       Signature *invokeSignature,
507                                                                       ir::TypeNode *retTypeAnnotation)
508 {
509     return CreateClassMethod<true>(
510         classScope, compiler::Signatures::LAMBDA_OBJECT_INVOKE, ir::ModifierFlags::PUBLIC,
511         [this, classScope, invokeSignature,
512          retTypeAnnotation](varbinder::FunctionScope *scope, ArenaVector<ir::Statement *> *statements,
513                             ArenaVector<ir::Expression *> *params, Type **returnType) {
514             util::UString thisParamName(std::string("this"), Allocator());
515             ir::ETSParameterExpression *thisParam =
516                 AddParam(scope->Parent()->AsFunctionParamScope(), thisParamName.View(),
517                          classScope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType());
518             params->push_back(thisParam);
519 
520             ArenaVector<ir::Expression *> callParams(Allocator()->Adapter());
521             uint32_t idx = 0;
522             for (auto *invokeParam : invokeSignature->Params()) {
523                 ir::ETSParameterExpression *param = AddParam(
524                     scope->Parent()->AsFunctionParamScope(),
525                     util::UString(std::string("p") + std::to_string(idx), Allocator()).View(), invokeParam->TsType());
526                 params->push_back(param);
527                 callParams.push_back(param);
528                 ++idx;
529             }
530 
531             auto *properyId = AllocNode<ir::Identifier>("jsvalue_lambda", Allocator());
532             auto *callee = AllocNode<ir::MemberExpression>(thisParam, properyId,
533                                                            ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
534             auto *callLambda = AllocNode<ir::CallExpression>(callee, std::move(callParams), nullptr, false);
535 
536             {
537                 ScopeContext ctx(this, scope);
538                 callLambda->Check(this);
539             }
540 
541             auto *castToRetTypeExpr = Allocator()->New<ir::TSAsExpression>(callLambda, retTypeAnnotation, false);
542             castToRetTypeExpr->SetTsType(invokeSignature->ReturnType());
543             auto *retStatement = Allocator()->New<ir::ReturnStatement>(castToRetTypeExpr);
544             statements->push_back(retStatement);
545 
546             *returnType = invokeSignature->ReturnType();
547         });
548 }
549 
EmitDynamicModuleClassInitCall()550 void ETSChecker::EmitDynamicModuleClassInitCall()
551 {
552     auto *globalClass = VarBinder()->Program()->GlobalClass();
553     auto &body = globalClass->Body();
554     auto it = std::find_if(body.begin(), body.end(), [](ir::AstNode *node) { return node->IsClassStaticBlock(); });
555 
556     ASSERT(it != body.end());
557 
558     auto *staticBlock = (*it)->AsClassStaticBlock();
559     auto *cctorBody = staticBlock->Function()->Body()->AsBlockStatement();
560 
561     auto *classId = AllocNode<ir::Identifier>(compiler::Signatures::DYNAMIC_MODULE_CLASS, Allocator());
562     auto *methodId = AllocNode<ir::Identifier>(compiler::Signatures::DYNAMIC_MODULE_CLASS_INIT, Allocator());
563     auto *callee =
564         AllocNode<ir::MemberExpression>(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
565 
566     ArenaVector<ir::Expression *> callParams(Allocator()->Adapter());
567     auto *initCall = AllocNode<ir::CallExpression>(callee, std::move(callParams), nullptr, false);
568 
569     {
570         ScopeContext ctx(this, cctorBody->Scope());
571         initCall->Check(this);
572     }
573 
574     cctorBody->Statements().push_back(AllocNode<ir::ExpressionStatement>(initCall));
575 }
576 
BuildDynamicImportClass()577 void ETSChecker::BuildDynamicImportClass()
578 {
579     auto dynamicImports = VarBinder()->AsETSBinder()->DynamicImports();
580     if (dynamicImports.empty()) {
581         return;
582     }
583 
584     // clang-format off
585     BuildClass(compiler::Signatures::DYNAMIC_MODULE_CLASS,
586                 [this, dynamicImports](varbinder::ClassScope *scope, ArenaVector<ir::AstNode *> *classBody) {
587                     std::unordered_set<util::StringView> fields;
588                     std::vector<ir::ETSImportDeclaration *> imports;
589 
590                     auto *classType = scope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType();
591 
592                     for (auto *import : dynamicImports) {
593                         auto source = import->Source()->Str();
594                         if (fields.find(source) != fields.cend()) {
595                             continue;
596                         }
597 
598                         auto assemblyName = std::string(source);
599                         std::replace_if(
600                             assemblyName.begin(), assemblyName.end(), [](char c) { return std::isalnum(c) == 0; }, '_');
601                         assemblyName.append(std::to_string(fields.size()));
602 
603                         import->AssemblerName() = util::UString(assemblyName, Allocator()).View();
604                         fields.insert(import->AssemblerName());
605                         imports.push_back(import);
606 
607                         auto *fieldIdent = AllocNode<ir::Identifier>(import->AssemblerName(), Allocator());
608                         auto *field = AllocNode<ir::ClassProperty>(fieldIdent, nullptr, nullptr,
609                                                                    ir::ModifierFlags::STATIC | ir::ModifierFlags::PUBLIC,
610                                                                    Allocator(), false);
611                         field->SetTsType(GlobalBuiltinDynamicType(import->Language()));
612 
613                         auto *decl = Allocator()->New<varbinder::LetDecl>(fieldIdent->Name());
614                         decl->BindNode(field);
615 
616                         auto *var = scope->AddDecl(Allocator(), decl, VarBinder()->Extension());
617                         var->AddFlag(varbinder::VariableFlags::PROPERTY);
618                         fieldIdent->SetVariable(var);
619                         var->SetTsType(GlobalBuiltinDynamicType(import->Language()));
620 
621                         classType->AddProperty<PropertyType::STATIC_FIELD>(var->AsLocalVariable());
622 
623                         classBody->push_back(field);
624                     }
625 
626                     classBody->push_back(CreateDynamicModuleClassInitializer(scope, imports));
627                     classBody->push_back(CreateDynamicModuleClassInitMethod(scope));
628                 });
629     // clang-format on
630 
631     EmitDynamicModuleClassInitCall();
632 }
633 
CreateLambdaObjectClassInitializer(varbinder::ClassScope * classScope,ETSObjectType * functionalInterface)634 ir::MethodDefinition *ETSChecker::CreateLambdaObjectClassInitializer(varbinder::ClassScope *classScope,
635                                                                      ETSObjectType *functionalInterface)
636 {
637     return CreateClassInitializer<false>(
638         classScope,
639         [this, classScope](varbinder::FunctionScope *scope, ArenaVector<ir::Statement *> *statements,
640                            ArenaVector<ir::Expression *> *params) {
641             util::UString thisParamName(std::string("this"), Allocator());
642             ir::ETSParameterExpression *thisParam =
643                 AddParam(scope->Parent()->AsFunctionParamScope(), thisParamName.View(),
644                          classScope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType());
645             params->push_back(thisParam);
646 
647             util::UString jsvalueParamName(std::string("jsvalue_param"), Allocator());
648             ir::ETSParameterExpression *jsvalueParam =
649                 AddParam(scope->Parent()->AsFunctionParamScope(), jsvalueParamName.View(), GlobalBuiltinJSValueType());
650             params->push_back(jsvalueParam);
651 
652             auto *moduleClassId = AllocNode<ir::Identifier>("this", Allocator());
653             auto *fieldId = AllocNode<ir::Identifier>("jsvalue_lambda", Allocator());
654             auto *property = AllocNode<ir::MemberExpression>(moduleClassId, fieldId,
655                                                              ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
656             auto *initializer =
657                 AllocNode<ir::AssignmentExpression>(property, jsvalueParam, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
658             {
659                 ScopeContext ctx(this, scope);
660                 initializer->Check(this);
661             }
662 
663             statements->push_back(AllocNode<ir::ExpressionStatement>(initializer));
664         },
665         functionalInterface);
666 }
667 
BuildLambdaObjectClass(ETSObjectType * functionalInterface,ir::TypeNode * retTypeAnnotation)668 void ETSChecker::BuildLambdaObjectClass(ETSObjectType *functionalInterface, ir::TypeNode *retTypeAnnotation)
669 {
670     auto *invokeMethod = functionalInterface->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>("invoke");
671     auto *invokeSignature = invokeMethod->TsType()->AsETSFunctionType()->CallSignatures()[0];
672 
673     std::stringstream ss;
674     ss << compiler::Signatures::LAMBDA_OBJECT;
675     for (auto *arg : invokeSignature->Params()) {
676         ss << "-";
677         arg->TsType()->ToString(ss);
678     }
679     static std::string syntheticLambdaObjName {ss.str()};
680 
681     if (dynamicLambdaSignatureCache_.find(syntheticLambdaObjName) != dynamicLambdaSignatureCache_.end()) {
682         functionalInterface->AddConstructSignature(dynamicLambdaSignatureCache_[syntheticLambdaObjName]);
683         return;
684     }
685 
686     BuildClass(util::StringView(syntheticLambdaObjName),
687                [this, invokeSignature, retTypeAnnotation, functionalInterface](varbinder::ClassScope *scope,
688                                                                                ArenaVector<ir::AstNode *> *classBody) {
689                    auto *classType = scope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType();
690                    classType->AddInterface(functionalInterface);
691 
692                    auto assemblyName = "jsvalue_lambda";
693                    auto *fieldIdent = AllocNode<ir::Identifier>(assemblyName, Allocator());
694                    auto *field = AllocNode<ir::ClassProperty>(fieldIdent, nullptr, nullptr, ir::ModifierFlags::PRIVATE,
695                                                               Allocator(), false);
696                    field->SetTsType(GlobalBuiltinJSValueType());
697 
698                    auto *decl = Allocator()->New<varbinder::LetDecl>(fieldIdent->Name());
699                    decl->BindNode(field);
700 
701                    auto *var = scope->AddDecl(Allocator(), decl, VarBinder()->Extension());
702                    var->AddFlag(varbinder::VariableFlags::PROPERTY);
703                    var->SetTsType(GlobalBuiltinJSValueType());
704                    fieldIdent->SetVariable(var);
705 
706                    classType->AddProperty<PropertyType::INSTANCE_FIELD>(var->AsLocalVariable());
707 
708                    classBody->push_back(field);
709 
710                    classBody->push_back(CreateLambdaObjectClassInitializer(scope, functionalInterface));
711 
712                    classBody->push_back(CreateLambdaObjectClassInvokeMethod(scope, invokeSignature, retTypeAnnotation));
713                });
714 
715     dynamicLambdaSignatureCache_[syntheticLambdaObjName] = functionalInterface->ConstructSignatures()[0];
716 }
717 
718 }  // namespace panda::es2panda::checker
719