1 /**
2 * Copyright (c) 2021-2025 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 "arrowFunctionExpression.h"
17
18 #include "compiler/core/pandagen.h"
19 #include "compiler/core/ETSGen.h"
20 #include "checker/ETSchecker.h"
21 #include "checker/TSchecker.h"
22
23 namespace ark::es2panda::ir {
TransformChildren(const NodeTransformer & cb,std::string_view const transformationName)24 void ArrowFunctionExpression::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
25 {
26 if (auto *transformedNode = cb(func_); func_ != transformedNode) {
27 func_->SetTransformedNode(transformationName, transformedNode);
28 func_ = transformedNode->AsScriptFunction();
29 }
30
31 for (auto *&it : VectorIterationGuard(Annotations())) {
32 if (auto *transformedNode = cb(it); it != transformedNode) {
33 it->SetTransformedNode(transformationName, transformedNode);
34 it = transformedNode->AsAnnotationUsage();
35 }
36 }
37 }
38
Iterate(const NodeTraverser & cb) const39 void ArrowFunctionExpression::Iterate(const NodeTraverser &cb) const
40 {
41 cb(func_);
42
43 for (auto *it : VectorIterationGuard(Annotations())) {
44 cb(it);
45 }
46 }
47
Dump(ir::AstDumper * dumper) const48 void ArrowFunctionExpression::Dump(ir::AstDumper *dumper) const
49 {
50 dumper->Add({{"type", "ArrowFunctionExpression"},
51 {"function", func_},
52 {"annotations", AstDumper::Optional(Annotations())}});
53 }
54
Dump(ir::SrcDumper * dumper) const55 void ArrowFunctionExpression::Dump(ir::SrcDumper *dumper) const
56 {
57 for (auto *anno : Annotations()) {
58 anno->Dump(dumper);
59 }
60 dumper->Add("(");
61 if (func_->IsScriptFunction() && func_->AsScriptFunction()->IsAsyncFunc()) {
62 dumper->Add("async ");
63 }
64 func_->Dump(dumper);
65 dumper->Add(")");
66 }
67
Compile(compiler::PandaGen * pg) const68 void ArrowFunctionExpression::Compile(compiler::PandaGen *pg) const
69 {
70 pg->GetAstCompiler()->Compile(this);
71 }
72
Compile(compiler::ETSGen * etsg) const73 void ArrowFunctionExpression::Compile(compiler::ETSGen *etsg) const
74 {
75 etsg->GetAstCompiler()->Compile(this);
76 }
77
Check(checker::TSChecker * checker)78 checker::Type *ArrowFunctionExpression::Check(checker::TSChecker *checker)
79 {
80 return checker->GetAnalyzer()->Check(this);
81 }
82
Check(checker::ETSChecker * checker)83 checker::VerifiedType ArrowFunctionExpression::Check(checker::ETSChecker *checker)
84 {
85 return {this, checker->GetAnalyzer()->Check(this)};
86 }
87
ArrowFunctionExpression(ArrowFunctionExpression const & other,ArenaAllocator * const allocator)88 ArrowFunctionExpression::ArrowFunctionExpression(ArrowFunctionExpression const &other, ArenaAllocator *const allocator)
89 : JsDocAllowed<AnnotationAllowed<Expression>>(static_cast<Expression const &>(other), allocator)
90 {
91 ES2PANDA_ASSERT(other.func_->Clone(allocator, this));
92 func_ = other.func_->Clone(allocator, this)->AsScriptFunction();
93 }
94
Clone(ArenaAllocator * const allocator,AstNode * const parent)95 ArrowFunctionExpression *ArrowFunctionExpression::Clone(ArenaAllocator *const allocator, AstNode *const parent)
96 {
97 auto *const clone = allocator->New<ArrowFunctionExpression>(*this, allocator);
98 ES2PANDA_ASSERT(clone);
99
100 if (parent != nullptr) {
101 clone->SetParent(parent);
102 }
103
104 if (!Annotations().empty()) {
105 ArenaVector<AnnotationUsage *> annotationUsages {allocator->Adapter()};
106 for (auto *annotationUsage : Annotations()) {
107 annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage());
108 }
109 clone->SetAnnotations(std::move(annotationUsages));
110 }
111
112 clone->SetRange(Range());
113 return clone;
114 }
115
CreateReturnNodeFromType(checker::ETSChecker * checker,checker::Type * returnType)116 ir::TypeNode *ArrowFunctionExpression::CreateReturnNodeFromType(checker::ETSChecker *checker, checker::Type *returnType)
117 {
118 /*
119 Construct a synthetic Node with the correct ts_type_.
120 */
121 ES2PANDA_ASSERT(returnType != nullptr);
122 auto *ident = checker->AllocNode<ir::Identifier>(util::StringView(""), checker->Allocator());
123 auto *const part = checker->AllocNode<ir::ETSTypeReferencePart>(ident, checker->Allocator());
124 auto *returnNode = checker->AllocNode<ir::ETSTypeReference>(part, checker->Allocator());
125 ES2PANDA_ASSERT(returnNode);
126 returnNode->SetTsType(returnType);
127 return returnNode;
128 }
129
CreateTypeAnnotation(checker::ETSChecker * checker)130 ir::TypeNode *ArrowFunctionExpression::CreateTypeAnnotation(checker::ETSChecker *checker)
131 {
132 ir::TypeNode *returnNode = nullptr;
133 /*
134 There are two scenarios for lambda type inference: defined or undefined return type.
135 example code:
136 ```
137 enum Color { Red, Blue}
138 // has Return Type Color
139 let x = () : Color => {return Color.Red}
140 // No Return Type Color
141 let y = () => {return Color.Red}
142 ```
143 */
144 if (Function()->ReturnTypeAnnotation() == nullptr) {
145 /*
146 When lambda expression does not declare a return type, we need to construct the
147 declaration node of lambda according to the Function()->Signature()->ReturnType().
148 */
149 returnNode = CreateReturnNodeFromType(checker, Function()->Signature()->ReturnType());
150 } else {
151 returnNode = Function()->ReturnTypeAnnotation()->Clone(checker->Allocator(), nullptr);
152 returnNode->SetTsType(Function()->ReturnTypeAnnotation()->TsType());
153 }
154
155 ArenaVector<ir::Expression *> params {checker->Allocator()->Adapter()};
156 checker->CopyParams(Function()->Params(), params, nullptr);
157
158 auto signature = ir::FunctionSignature(nullptr, std::move(params), returnNode);
159 auto *funcType = checker->AllocNode<ir::ETSFunctionType>(std::move(signature), ir::ScriptFunctionFlags::NONE,
160 checker->Allocator());
161 return funcType;
162 }
163
IsVarFromSubscope(const varbinder::Variable * var) const164 bool ArrowFunctionExpression::IsVarFromSubscope(const varbinder::Variable *var) const
165 {
166 // The parameter scope's and the function scope's common ancestor lives outside the function, so we have to check
167 // them separetely.
168 return Function()->Scope()->IsSuperscopeOf(var->GetScope()) ||
169 Function()->Scope()->ParamScope()->IsSuperscopeOf(var->GetScope());
170 }
171
172 } // namespace ark::es2panda::ir
173