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, ¶ms);
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, ¶ms, &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