swc_ecma_compat_es2015/
arrow.rs1use std::mem;
2
3use swc_common::{util::take::Take, Mark, SyntaxContext, DUMMY_SP};
4use swc_ecma_ast::*;
5use swc_ecma_utils::{
6 function::{init_this, FnEnvHoister},
7 prepend_stmt,
8};
9use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, InjectVars, VisitMut, VisitMutWith};
10use swc_trace_macro::swc_trace;
11
12pub fn arrow(unresolved_mark: Mark) -> impl Pass + VisitMut + InjectVars {
61 visit_mut_pass(Arrow {
62 in_subclass: false,
63 hoister: FnEnvHoister::new(SyntaxContext::empty().apply_mark(unresolved_mark)),
64 })
65}
66
67#[derive(Default)]
68struct Arrow {
69 in_subclass: bool,
70 hoister: FnEnvHoister,
71}
72
73#[swc_trace]
74impl VisitMut for Arrow {
75 noop_visit_mut_type!(fail);
76
77 fn visit_mut_class(&mut self, c: &mut Class) {
78 let old = self.in_subclass;
79
80 if c.super_class.is_some() {
81 self.in_subclass = true;
82 }
83 c.visit_mut_children_with(self);
84 self.in_subclass = old;
85 }
86
87 fn visit_mut_constructor(&mut self, c: &mut Constructor) {
88 c.params.visit_mut_children_with(self);
89
90 if let Some(BlockStmt { span: _, stmts, .. }) = &mut c.body {
91 let old_rep = self.hoister.take();
92
93 stmts.visit_mut_children_with(self);
94
95 if self.in_subclass {
96 let (decl, this_id) =
97 mem::replace(&mut self.hoister, old_rep).to_stmt_in_subclass();
98
99 if let Some(stmt) = decl {
100 if let Some(this_id) = this_id {
101 init_this(stmts, &this_id)
102 }
103 prepend_stmt(stmts, stmt);
104 }
105 } else {
106 let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
107
108 if let Some(stmt) = decl {
109 prepend_stmt(stmts, stmt);
110 }
111 }
112 }
113 }
114
115 fn visit_mut_expr(&mut self, expr: &mut Expr) {
116 match expr {
117 Expr::Arrow(ArrowExpr {
118 span,
119 params,
120 body,
121 is_async,
122 is_generator,
123 ..
124 }) => {
125 params.visit_mut_with(self);
126 params.visit_mut_with(&mut self.hoister);
127
128 let params: Vec<Param> = params
129 .take()
130 .into_iter()
131 .map(|pat| Param {
132 span: DUMMY_SP,
133 decorators: Default::default(),
134 pat,
135 })
136 .collect();
137
138 body.visit_mut_with(self);
139
140 body.visit_mut_with(&mut self.hoister);
141
142 let fn_expr = Function {
143 decorators: Vec::new(),
144 span: *span,
145 params,
146 is_async: *is_async,
147 is_generator: *is_generator,
148 body: Some(match &mut **body {
149 BlockStmtOrExpr::BlockStmt(block) => block.take(),
150 BlockStmtOrExpr::Expr(expr) => BlockStmt {
151 span: DUMMY_SP,
152 stmts: vec![Stmt::Return(ReturnStmt {
153 span: DUMMY_SP,
157 arg: Some(expr.take()),
158 })],
159 ..Default::default()
160 },
161 }),
162 ..Default::default()
163 }
164 .into();
165
166 *expr = fn_expr;
167 }
168 _ => {
169 expr.visit_mut_children_with(self);
170 }
171 }
172 }
173
174 fn visit_mut_function(&mut self, f: &mut Function) {
175 let old_rep = self.hoister.take();
176
177 f.visit_mut_children_with(self);
178
179 let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
180
181 if let (Some(body), Some(stmt)) = (&mut f.body, decl) {
182 prepend_stmt(&mut body.stmts, stmt);
183 }
184 }
185
186 fn visit_mut_getter_prop(&mut self, f: &mut GetterProp) {
187 f.key.visit_mut_with(self);
188
189 if let Some(body) = &mut f.body {
190 let old_rep = self.hoister.take();
191
192 body.visit_mut_with(self);
193
194 let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
195
196 if let Some(stmt) = decl {
197 prepend_stmt(&mut body.stmts, stmt);
198 }
199 }
200 }
201
202 fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
203 stmts.visit_mut_children_with(self);
204
205 let decl = self.hoister.take().to_stmt();
206
207 if let Some(stmt) = decl {
208 prepend_stmt(stmts, stmt.into());
209 }
210 }
211
212 fn visit_mut_script(&mut self, script: &mut Script) {
213 script.visit_mut_children_with(self);
214
215 let decl = self.hoister.take().to_stmt();
216
217 if let Some(stmt) = decl {
218 prepend_stmt(&mut script.body, stmt);
219 }
220 }
221
222 fn visit_mut_setter_prop(&mut self, f: &mut SetterProp) {
223 f.key.visit_mut_with(self);
224 f.param.visit_mut_with(self);
225
226 if let Some(body) = &mut f.body {
227 let old_rep = self.hoister.take();
228
229 body.visit_mut_with(self);
230
231 let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
232
233 if let Some(stmt) = decl {
234 prepend_stmt(&mut body.stmts, stmt);
235 }
236 }
237 }
238}
239
240impl InjectVars for Arrow {
241 fn take_vars(&mut self) -> Vec<VarDeclarator> {
242 self.hoister.take().to_decl()
243 }
244}