/* * Copyright (c) 2021 - 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "checker/ETSchecker.h" #include "varbinder/scope.h" #include "varbinder/declaration.h" #include "varbinder/varbinder.h" #include "varbinder/ETSBinder.h" #include "checker/types/ets/etsDynamicFunctionType.h" #include "ir/base/classProperty.h" #include "ir/base/classStaticBlock.h" #include "ir/base/methodDefinition.h" #include "ir/base/scriptFunction.h" #include "ir/expressions/assignmentExpression.h" #include "ir/expressions/callExpression.h" #include "ir/expressions/functionExpression.h" #include "ir/expressions/identifier.h" #include "ir/expressions/thisExpression.h" #include "ir/expressions/memberExpression.h" #include "ir/ets/etsPrimitiveType.h" #include "ir/ts/tsAsExpression.h" #include "ir/statements/blockStatement.h" #include "ir/statements/classDeclaration.h" #include "ir/statements/expressionStatement.h" #include "ir/statements/returnStatement.h" #include "ir/statements/variableDeclaration.h" #include "ir/statements/variableDeclarator.h" #include "parser/program/program.h" #include "util/helpers.h" #include "util/language.h" #include "generated/signatures.h" #include "ir/ets/etsParameterExpression.h" namespace panda::es2panda::checker { ir::ETSParameterExpression *ETSChecker::AddParam(varbinder::FunctionParamScope *paramScope, util::StringView name, checker::Type *type) { auto paramCtx = varbinder::LexicalScope::Enter(VarBinder(), paramScope, false); auto *paramIdent = AllocNode(name, Allocator()); auto *param = AllocNode(paramIdent, nullptr); auto *paramVar = std::get<1>(VarBinder()->AddParamDecl(param)); paramVar->SetTsType(type); param->Ident()->SetVariable(paramVar); param->Ident()->SetTsType(type); return param; } static bool IsByValueCall(varbinder::ETSBinder *varbinder, ir::Expression *callee) { if (callee->IsMemberExpression()) { return !callee->AsMemberExpression()->ObjType()->IsETSDynamicType(); } if (callee->IsETSTypeReference()) { return false; } auto *var = callee->AsIdentifier()->Variable(); auto *data = varbinder->DynamicImportDataForVar(var); if (data != nullptr) { auto *specifier = data->specifier; if (specifier->IsImportSpecifier()) { return false; } } return true; } template ir::ScriptFunction *ETSChecker::CreateDynamicCallIntrinsic(ir::Expression *callee, const ArenaVector &arguments, Language lang) { auto *name = AllocNode("invoke", Allocator()); auto *paramScope = Allocator()->New(Allocator(), nullptr); auto *scope = Allocator()->New(Allocator(), paramScope); ArenaVector params(Allocator()->Adapter()); auto *info = CreateSignatureInfo(); info->minArgCount = arguments.size() + 2U; auto dynamicType = GlobalBuiltinDynamicType(lang); auto *objParam = AddParam(paramScope, "obj", dynamicType); params.push_back(objParam); info->params.push_back(objParam->Ident()->Variable()->AsLocalVariable()); ir::ETSParameterExpression *param2; if (!IsByValueCall(VarBinder()->AsETSBinder(), callee)) { param2 = AddParam(paramScope, "qname", GlobalETSStringLiteralType()); } else { param2 = AddParam(paramScope, "this", dynamicType); } params.push_back(param2); info->params.push_back(param2->Ident()->Variable()->AsLocalVariable()); for (size_t i = 0; i < arguments.size(); i++) { util::UString paramName("p" + std::to_string(i), Allocator()); Type *paramType = arguments[i]->TsType()->IsLambdaObject() ? GlobalBuiltinJSValueType() : arguments[i]->TsType(); ir::ETSParameterExpression *param = AddParam(paramScope, paramName.View(), paramType); params.push_back(param); info->params.push_back(param->Ident()->Variable()->AsLocalVariable()); } auto *func = AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), nullptr, ir::ScriptFunctionFlags::METHOD, ir::ModifierFlags::NONE, false, Language(Language::Id::ETS)); func->SetScope(scope); scope->BindNode(func); paramScope->BindNode(func); scope->BindParamScope(paramScope); paramScope->BindFunctionScope(scope); func->SetIdent(name); auto *signature = CreateSignature(info, dynamicType, func); signature->AddSignatureFlag(SignatureFlags::STATIC); func->SetSignature(signature); return func; } static void ToString(ETSChecker *checker, const ArenaVector &arguments, std::stringstream &ss) { for (auto *arg : arguments) { auto *type = arg->Check(checker); ss << "-"; type->ToString(ss); } } static void ToString([[maybe_unused]] ETSChecker *checker, const ArenaVector &arguments, std::stringstream &ss) { for (auto *arg : arguments) { auto *type = arg->TsType(); ss << "-"; type->ToString(ss); } } template Signature *ETSChecker::ResolveDynamicCallExpression(ir::Expression *callee, const ArenaVector &arguments, Language lang, bool isConstruct) { auto &dynamicIntrinsics = *DynamicCallIntrinsics(isConstruct); auto mapIt = dynamicIntrinsics.find(lang); if (mapIt == dynamicIntrinsics.cend()) { std::tie(mapIt, std::ignore) = dynamicIntrinsics.emplace(lang, Allocator()->Adapter()); } auto &map = mapIt->second; std::stringstream ss; ss << "dyncall"; if (IsByValueCall(VarBinder()->AsETSBinder(), callee)) { ss << "-byvalue"; } ToString(this, arguments, ss); auto key = ss.str(); auto it = map.find(util::StringView(key)); if (it == map.end()) { auto *func = CreateDynamicCallIntrinsic(callee, arguments, lang); map.emplace(util::UString(key, Allocator()).View(), func); return func->Signature(); } return it->second->Signature(); } template Signature *ETSChecker::ResolveDynamicCallExpression( ir::Expression *callee, const ArenaVector &arguments, Language lang, bool is_construct); template Signature *ETSChecker::ResolveDynamicCallExpression( ir::Expression *callee, const ArenaVector &arguments, Language lang, bool is_construct); template std::conditional_t ETSChecker::CreateClassInitializer( varbinder::ClassScope *classScope, const ClassInitializerBuilder &builder, ETSObjectType *type) { varbinder::LocalScope *methodScope = nullptr; if constexpr (IS_STATIC) { methodScope = classScope->StaticMethodScope(); } else { methodScope = classScope->InstanceMethodScope(); } auto classCtx = varbinder::LexicalScope::Enter(VarBinder(), methodScope); ArenaVector params(Allocator()->Adapter()); auto *paramScope = Allocator()->New(Allocator(), classScope); auto *scope = Allocator()->New(Allocator(), paramScope); ArenaVector statements(Allocator()->Adapter()); ir::ScriptFunction *func = nullptr; ir::Identifier *id = nullptr; if constexpr (IS_STATIC) { builder(scope, &statements, nullptr); auto *body = AllocNode(Allocator(), std::move(statements)); body->SetScope(scope); id = AllocNode(compiler::Signatures::CCTOR, Allocator()); func = AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), body, ir::ScriptFunctionFlags::STATIC_BLOCK | ir::ScriptFunctionFlags::EXPRESSION, ir::ModifierFlags::STATIC, false, Language(Language::Id::ETS)); func->SetScope(scope); } else { builder(scope, &statements, ¶ms); auto *body = AllocNode(Allocator(), std::move(statements)); body->SetScope(scope); id = AllocNode(compiler::Signatures::CTOR, Allocator()); func = AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), body, ir::ScriptFunctionFlags::CONSTRUCTOR | ir::ScriptFunctionFlags::EXPRESSION, ir::ModifierFlags::PUBLIC, false, Language(Language::Id::ETS)); func->SetScope(scope); } scope->BindNode(func); func->SetIdent(id); paramScope->BindNode(func); scope->BindParamScope(paramScope); paramScope->BindFunctionScope(scope); auto *signatureInfo = CreateSignatureInfo(); signatureInfo->restVar = nullptr; auto *signature = CreateSignature(signatureInfo, GlobalVoidType(), func); func->SetSignature(signature); auto *funcExpr = AllocNode(func); VarBinder()->AsETSBinder()->BuildInternalName(func); VarBinder()->AsETSBinder()->BuildFunctionName(func); VarBinder()->Functions().push_back(func->Scope()); if constexpr (IS_STATIC) { auto *staticBlock = AllocNode(funcExpr, Allocator()); staticBlock->AddModifier(ir::ModifierFlags::STATIC); return staticBlock; } else { type->AddConstructSignature(signature); auto *ctor = Allocator()->New(ir::MethodDefinitionKind::CONSTRUCTOR, id, funcExpr, ir::ModifierFlags::NONE, Allocator(), false); auto *funcType = CreateETSFunctionType(signature, id->Name()); ctor->SetTsType(funcType); funcExpr->SetParent(classScope->Node()->AsClassDeclaration()->Definition()); func->SetParent(ctor); return ctor; } } ir::ClassStaticBlock *ETSChecker::CreateDynamicCallClassInitializer(varbinder::ClassScope *classScope, Language lang, bool isConstruct) { return CreateClassInitializer( classScope, [this, lang, isConstruct](varbinder::FunctionScope *scope, ArenaVector *statements, [[maybe_unused]] ArenaVector *params) { auto [builtin_class_name, builtin_method_name] = util::Helpers::SplitSignature(isConstruct ? compiler::Signatures::Dynamic::InitNewClassBuiltin(lang) : compiler::Signatures::Dynamic::InitCallClassBuiltin(lang)); auto *classId = AllocNode(builtin_class_name, Allocator()); auto *methodId = AllocNode(builtin_method_name, Allocator()); auto *callee = AllocNode(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); ArenaVector callParams(Allocator()->Adapter()); std::stringstream ss; auto name = isConstruct ? compiler::Signatures::Dynamic::NewClass(lang) : compiler::Signatures::Dynamic::CallClass(lang); auto package = VarBinder()->Program()->GetPackageName(); ss << compiler::Signatures::CLASS_REF_BEGIN; if (!package.Empty()) { std::string packageStr(package); std::replace(packageStr.begin(), packageStr.end(), *compiler::Signatures::METHOD_SEPARATOR.begin(), *compiler::Signatures::NAMESPACE_SEPARATOR.begin()); ss << packageStr << compiler::Signatures::NAMESPACE_SEPARATOR; } ss << name << compiler::Signatures::MANGLE_SEPARATOR; auto *className = AllocNode(util::UString(ss.str(), Allocator()).View()); callParams.push_back(className); auto *initCall = AllocNode(callee, std::move(callParams), nullptr, false); { ScopeContext ctx(this, scope); initCall->Check(this); } statements->push_back(AllocNode(initCall)); }); } void ETSChecker::BuildClass(util::StringView name, const ClassBuilder &builder) { auto *classId = AllocNode(name, Allocator()); auto [decl, var] = VarBinder()->NewVarDecl(classId->Start(), classId->Name()); classId->SetVariable(var); auto classCtx = varbinder::LexicalScope(VarBinder()); auto *classDef = AllocNode(Allocator(), classId, ir::ClassDefinitionModifiers::DECLARATION, ir::ModifierFlags::NONE, Language(Language::Id::ETS)); classDef->SetScope(classCtx.GetScope()); auto *classDefType = Allocator()->New( Allocator(), classDef->Ident()->Name(), classDef->Ident()->Name(), classDef, checker::ETSObjectFlags::CLASS); classDef->SetTsType(classDefType); auto *classDecl = AllocNode(classDef, Allocator()); classDecl->SetParent(VarBinder()->TopScope()->Node()); classDef->Scope()->BindNode(classDecl); decl->BindNode(classDef); VarBinder()->Program()->Ast()->Statements().push_back(classDecl); varbinder::BoundContext boundCtx(VarBinder()->AsETSBinder()->GetGlobalRecordTable(), classDef); ArenaVector classBody(Allocator()->Adapter()); builder(classCtx.GetScope(), &classBody); classDef->AddProperties(std::move(classBody)); } void ETSChecker::BuildDynamicCallClass(bool isConstruct) { auto &dynamicIntrinsics = *DynamicCallIntrinsics(isConstruct); if (dynamicIntrinsics.empty()) { return; } for (auto &entry : dynamicIntrinsics) { auto lang = entry.first; auto &intrinsics = entry.second; auto className = isConstruct ? compiler::Signatures::Dynamic::NewClass(lang) : compiler::Signatures::Dynamic::CallClass(lang); BuildClass(className, [this, lang, &intrinsics, isConstruct](varbinder::ClassScope *scope, ArenaVector *classBody) { for (auto &[_, func] : intrinsics) { (void)_; func->Scope()->ParamScope()->SetParent(scope); auto *funcExpr = AllocNode(func); auto *method = AllocNode(ir::MethodDefinitionKind::METHOD, func->Id(), funcExpr, ir::ModifierFlags::PUBLIC | ir::ModifierFlags::NATIVE | ir::ModifierFlags::STATIC, Allocator(), false); VarBinder()->AsETSBinder()->BuildInternalName(func); VarBinder()->AsETSBinder()->BuildFunctionName(func); classBody->push_back(method); } classBody->push_back(CreateDynamicCallClassInitializer(scope, lang, isConstruct)); }); } } ir::ClassStaticBlock *ETSChecker::CreateDynamicModuleClassInitializer( varbinder::ClassScope *classScope, const std::vector &imports) { return CreateClassInitializer( classScope, [this, imports](varbinder::FunctionScope *scope, ArenaVector *statements, [[maybe_unused]] ArenaVector *params) { for (auto *import : imports) { auto builtin = compiler::Signatures::Dynamic::LoadModuleBuiltin(import->Language()); auto [builtin_class_name, builtin_method_name] = util::Helpers::SplitSignature(builtin); auto *classId = AllocNode(builtin_class_name, Allocator()); auto *methodId = AllocNode(builtin_method_name, Allocator()); auto *callee = AllocNode(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); ArenaVector callParams(Allocator()->Adapter()); callParams.push_back(import->ResolvedSource()); auto *loadCall = AllocNode(callee, std::move(callParams), nullptr, false); auto *moduleClassId = AllocNode(compiler::Signatures::DYNAMIC_MODULE_CLASS, Allocator()); auto *fieldId = AllocNode(import->AssemblerName(), Allocator()); auto *property = AllocNode( moduleClassId, fieldId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); auto *initializer = AllocNode(property, loadCall, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); { ScopeContext ctx(this, scope); initializer->Check(this); } statements->push_back(AllocNode(initializer)); } }); } template ir::MethodDefinition *ETSChecker::CreateClassMethod(varbinder::ClassScope *classScope, const std::string_view methodName, panda::es2panda::ir::ModifierFlags modifierFlags, const MethodBuilder &builder) { auto classCtx = varbinder::LexicalScope::Enter(VarBinder(), classScope->StaticMethodScope()); ArenaVector params(Allocator()->Adapter()); auto *paramScope = Allocator()->New(Allocator(), classScope); auto *scope = Allocator()->New(Allocator(), paramScope); auto *id = AllocNode(methodName, Allocator()); ArenaVector statements(Allocator()->Adapter()); Type *returnType = nullptr; builder(scope, &statements, ¶ms, &returnType); auto *body = AllocNode(Allocator(), std::move(statements)); body->SetScope(scope); auto *func = AllocNode(ir::FunctionSignature(nullptr, std::move(params), nullptr), body, ir::ScriptFunctionFlags::METHOD, modifierFlags, false, Language(Language::Id::ETS)); func->SetScope(scope); scope->BindNode(func); func->SetIdent(id); paramScope->BindNode(func); scope->BindParamScope(paramScope); paramScope->BindFunctionScope(scope); auto *signatureInfo = CreateSignatureInfo(); signatureInfo->restVar = nullptr; auto *signature = CreateSignature(signatureInfo, returnType, func); if constexpr (IS_STATIC) { signature->AddSignatureFlag(SignatureFlags::STATIC); } func->SetSignature(signature); auto *funcExpr = AllocNode(func); auto *method = AllocNode(ir::MethodDefinitionKind::METHOD, func->Id(), funcExpr, modifierFlags, Allocator(), false); VarBinder()->AsETSBinder()->BuildInternalName(func); VarBinder()->AsETSBinder()->BuildFunctionName(func); VarBinder()->Functions().push_back(func->Scope()); auto *decl = Allocator()->New(id->Name()); decl->BindNode(method); auto *funcType = CreateETSFunctionType(signature, id->Name()); auto *var = scope->AddDecl(Allocator(), decl, VarBinder()->Extension()); var->SetTsType(funcType); method->SetTsType(funcType); var->AddFlag(varbinder::VariableFlags::PROPERTY); func->Id()->SetVariable(var); auto *classType = classScope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType(); if constexpr (IS_STATIC) { classType->AddProperty(var->AsLocalVariable()); } else { classType->AddProperty(var->AsLocalVariable()); } return method; } ir::MethodDefinition *ETSChecker::CreateDynamicModuleClassInitMethod(varbinder::ClassScope *classScope) { return CreateClassMethod(classScope, compiler::Signatures::DYNAMIC_MODULE_CLASS_INIT, ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC, [this]([[maybe_unused]] varbinder::FunctionScope *scope, [[maybe_unused]] ArenaVector *statements, [[maybe_unused]] ArenaVector *params, Type **returnType) { *returnType = GlobalBuiltinVoidType(); }); } ir::MethodDefinition *ETSChecker::CreateLambdaObjectClassInvokeMethod(varbinder::ClassScope *classScope, Signature *invokeSignature, ir::TypeNode *retTypeAnnotation) { return CreateClassMethod( classScope, compiler::Signatures::LAMBDA_OBJECT_INVOKE, ir::ModifierFlags::PUBLIC, [this, classScope, invokeSignature, retTypeAnnotation](varbinder::FunctionScope *scope, ArenaVector *statements, ArenaVector *params, Type **returnType) { util::UString thisParamName(std::string("this"), Allocator()); ir::ETSParameterExpression *thisParam = AddParam(scope->Parent()->AsFunctionParamScope(), thisParamName.View(), classScope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType()); params->push_back(thisParam); ArenaVector callParams(Allocator()->Adapter()); uint32_t idx = 0; for (auto *invokeParam : invokeSignature->Params()) { ir::ETSParameterExpression *param = AddParam( scope->Parent()->AsFunctionParamScope(), util::UString(std::string("p") + std::to_string(idx), Allocator()).View(), invokeParam->TsType()); params->push_back(param); callParams.push_back(param); ++idx; } auto *properyId = AllocNode("jsvalue_lambda", Allocator()); auto *callee = AllocNode(thisParam, properyId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); auto *callLambda = AllocNode(callee, std::move(callParams), nullptr, false); { ScopeContext ctx(this, scope); callLambda->Check(this); } auto *castToRetTypeExpr = Allocator()->New(callLambda, retTypeAnnotation, false); castToRetTypeExpr->SetTsType(invokeSignature->ReturnType()); auto *retStatement = Allocator()->New(castToRetTypeExpr); statements->push_back(retStatement); *returnType = invokeSignature->ReturnType(); }); } void ETSChecker::EmitDynamicModuleClassInitCall() { auto *globalClass = VarBinder()->Program()->GlobalClass(); auto &body = globalClass->Body(); auto it = std::find_if(body.begin(), body.end(), [](ir::AstNode *node) { return node->IsClassStaticBlock(); }); ASSERT(it != body.end()); auto *staticBlock = (*it)->AsClassStaticBlock(); auto *cctorBody = staticBlock->Function()->Body()->AsBlockStatement(); auto *classId = AllocNode(compiler::Signatures::DYNAMIC_MODULE_CLASS, Allocator()); auto *methodId = AllocNode(compiler::Signatures::DYNAMIC_MODULE_CLASS_INIT, Allocator()); auto *callee = AllocNode(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); ArenaVector callParams(Allocator()->Adapter()); auto *initCall = AllocNode(callee, std::move(callParams), nullptr, false); { ScopeContext ctx(this, cctorBody->Scope()); initCall->Check(this); } cctorBody->Statements().push_back(AllocNode(initCall)); } void ETSChecker::BuildDynamicImportClass() { auto dynamicImports = VarBinder()->AsETSBinder()->DynamicImports(); if (dynamicImports.empty()) { return; } // clang-format off BuildClass(compiler::Signatures::DYNAMIC_MODULE_CLASS, [this, dynamicImports](varbinder::ClassScope *scope, ArenaVector *classBody) { std::unordered_set fields; std::vector imports; auto *classType = scope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType(); for (auto *import : dynamicImports) { auto source = import->Source()->Str(); if (fields.find(source) != fields.cend()) { continue; } auto assemblyName = std::string(source); std::replace_if( assemblyName.begin(), assemblyName.end(), [](char c) { return std::isalnum(c) == 0; }, '_'); assemblyName.append(std::to_string(fields.size())); import->AssemblerName() = util::UString(assemblyName, Allocator()).View(); fields.insert(import->AssemblerName()); imports.push_back(import); auto *fieldIdent = AllocNode(import->AssemblerName(), Allocator()); auto *field = AllocNode(fieldIdent, nullptr, nullptr, ir::ModifierFlags::STATIC | ir::ModifierFlags::PUBLIC, Allocator(), false); field->SetTsType(GlobalBuiltinDynamicType(import->Language())); auto *decl = Allocator()->New(fieldIdent->Name()); decl->BindNode(field); auto *var = scope->AddDecl(Allocator(), decl, VarBinder()->Extension()); var->AddFlag(varbinder::VariableFlags::PROPERTY); fieldIdent->SetVariable(var); var->SetTsType(GlobalBuiltinDynamicType(import->Language())); classType->AddProperty(var->AsLocalVariable()); classBody->push_back(field); } classBody->push_back(CreateDynamicModuleClassInitializer(scope, imports)); classBody->push_back(CreateDynamicModuleClassInitMethod(scope)); }); // clang-format on EmitDynamicModuleClassInitCall(); } ir::MethodDefinition *ETSChecker::CreateLambdaObjectClassInitializer(varbinder::ClassScope *classScope, ETSObjectType *functionalInterface) { return CreateClassInitializer( classScope, [this, classScope](varbinder::FunctionScope *scope, ArenaVector *statements, ArenaVector *params) { util::UString thisParamName(std::string("this"), Allocator()); ir::ETSParameterExpression *thisParam = AddParam(scope->Parent()->AsFunctionParamScope(), thisParamName.View(), classScope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType()); params->push_back(thisParam); util::UString jsvalueParamName(std::string("jsvalue_param"), Allocator()); ir::ETSParameterExpression *jsvalueParam = AddParam(scope->Parent()->AsFunctionParamScope(), jsvalueParamName.View(), GlobalBuiltinJSValueType()); params->push_back(jsvalueParam); auto *moduleClassId = AllocNode("this", Allocator()); auto *fieldId = AllocNode("jsvalue_lambda", Allocator()); auto *property = AllocNode(moduleClassId, fieldId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); auto *initializer = AllocNode(property, jsvalueParam, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); { ScopeContext ctx(this, scope); initializer->Check(this); } statements->push_back(AllocNode(initializer)); }, functionalInterface); } void ETSChecker::BuildLambdaObjectClass(ETSObjectType *functionalInterface, ir::TypeNode *retTypeAnnotation) { auto *invokeMethod = functionalInterface->GetOwnProperty("invoke"); auto *invokeSignature = invokeMethod->TsType()->AsETSFunctionType()->CallSignatures()[0]; std::stringstream ss; ss << compiler::Signatures::LAMBDA_OBJECT; for (auto *arg : invokeSignature->Params()) { ss << "-"; arg->TsType()->ToString(ss); } static std::string syntheticLambdaObjName {ss.str()}; if (dynamicLambdaSignatureCache_.find(syntheticLambdaObjName) != dynamicLambdaSignatureCache_.end()) { functionalInterface->AddConstructSignature(dynamicLambdaSignatureCache_[syntheticLambdaObjName]); return; } BuildClass(util::StringView(syntheticLambdaObjName), [this, invokeSignature, retTypeAnnotation, functionalInterface](varbinder::ClassScope *scope, ArenaVector *classBody) { auto *classType = scope->Node()->AsClassDeclaration()->Definition()->TsType()->AsETSObjectType(); classType->AddInterface(functionalInterface); auto assemblyName = "jsvalue_lambda"; auto *fieldIdent = AllocNode(assemblyName, Allocator()); auto *field = AllocNode(fieldIdent, nullptr, nullptr, ir::ModifierFlags::PRIVATE, Allocator(), false); field->SetTsType(GlobalBuiltinJSValueType()); auto *decl = Allocator()->New(fieldIdent->Name()); decl->BindNode(field); auto *var = scope->AddDecl(Allocator(), decl, VarBinder()->Extension()); var->AddFlag(varbinder::VariableFlags::PROPERTY); var->SetTsType(GlobalBuiltinJSValueType()); fieldIdent->SetVariable(var); classType->AddProperty(var->AsLocalVariable()); classBody->push_back(field); classBody->push_back(CreateLambdaObjectClassInitializer(scope, functionalInterface)); classBody->push_back(CreateLambdaObjectClassInvokeMethod(scope, invokeSignature, retTypeAnnotation)); }); dynamicLambdaSignatureCache_[syntheticLambdaObjName] = functionalInterface->ConstructSignatures()[0]; } } // namespace panda::es2panda::checker