Skip to main content

swc_ecma_utils/function/
fn_env_hoister.rs

1use std::mem;
2
3use indexmap::IndexMap;
4use rustc_hash::FxBuildHasher;
5use swc_atoms::{atom, Atom};
6use swc_common::{util::take::Take, Span, Spanned, SyntaxContext, DUMMY_SP};
7use swc_ecma_ast::*;
8use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
9
10use crate::ExprFactory;
11
12#[derive(Default)]
13struct SuperField {
14    computed: Option<Ident>,
15    ident: IndexMap<Atom, Ident, FxBuildHasher>,
16}
17
18/// Don't use it against function, it will stop if come across any function
19/// use it against function body
20
21#[derive(Default)]
22pub struct FnEnvHoister {
23    unresolved_ctxt: SyntaxContext,
24    this: Option<Ident>,
25    args: Option<Ident>,
26    new_target: Option<Ident>,
27    super_get: SuperField,
28    super_set: SuperField,
29    super_update: SuperField,
30
31    arguments_disabled: bool,
32    this_disabled: bool,
33    super_disabled: bool,
34
35    in_pat: bool,
36
37    // extra ident for super["xx"] += 123
38    extra_ident: Vec<Ident>,
39}
40
41impl FnEnvHoister {
42    pub fn new(unresolved_ctxt: SyntaxContext) -> Self {
43        Self {
44            unresolved_ctxt,
45            ..Default::default()
46        }
47    }
48
49    /// Disable hoisting of `arguments`
50    pub fn disable_arguments(&mut self) {
51        self.arguments_disabled = true;
52    }
53
54    /// Disable hoisting of `this`
55    pub fn disable_this(&mut self) {
56        self.this_disabled = true;
57    }
58
59    /// Disable hoisting of nodes realted to `super`
60    pub fn disable_super(&mut self) {
61        self.super_disabled = true;
62    }
63
64    pub fn take(&mut self) -> Self {
65        let mut new = Self {
66            unresolved_ctxt: self.unresolved_ctxt,
67            ..Default::default()
68        };
69
70        mem::swap(self, &mut new);
71
72        new
73    }
74
75    pub fn to_decl(self) -> Vec<VarDeclarator> {
76        let Self {
77            this,
78            args,
79            new_target,
80            super_get,
81            super_set,
82            super_update,
83            ..
84        } = self;
85
86        let mut decls = Vec::with_capacity(3);
87        if let Some(this_id) = this {
88            decls.push(VarDeclarator {
89                span: DUMMY_SP,
90                name: this_id.into(),
91                init: Some(ThisExpr { span: DUMMY_SP }.into()),
92                definite: false,
93            });
94        }
95        if let Some(id) = args {
96            decls.push(VarDeclarator {
97                span: DUMMY_SP,
98                name: id.into(),
99                init: Some(Ident::new_no_ctxt(atom!("arguments"), DUMMY_SP).into()),
100                definite: false,
101            });
102        }
103        if let Some(id) = new_target {
104            decls.push(VarDeclarator {
105                span: DUMMY_SP,
106                name: id.into(),
107                init: Some(
108                    MetaPropExpr {
109                        span: DUMMY_SP,
110                        kind: MetaPropKind::NewTarget,
111                    }
112                    .into(),
113                ),
114                definite: false,
115            });
116        }
117        extend_super(&mut decls, super_get, super_set, super_update);
118        decls
119    }
120
121    pub fn to_stmt(self) -> Option<Stmt> {
122        let decls = self.to_decl();
123
124        if decls.is_empty() {
125            None
126        } else {
127            Some(
128                VarDecl {
129                    kind: VarDeclKind::Var,
130                    decls,
131                    ..Default::default()
132                }
133                .into(),
134            )
135        }
136    }
137
138    pub fn to_stmt_in_subclass(self) -> (Option<Stmt>, Option<Ident>) {
139        let Self {
140            this,
141            args,
142            new_target,
143            super_get,
144            super_set,
145            super_update,
146            ..
147        } = self;
148
149        let mut decls = Vec::with_capacity(3);
150        if let Some(this_id) = &this {
151            decls.push(VarDeclarator {
152                span: DUMMY_SP,
153                name: this_id.clone().into(),
154                init: None,
155                definite: false,
156            });
157        }
158        if let Some(id) = args {
159            decls.push(VarDeclarator {
160                span: DUMMY_SP,
161                name: id.into(),
162                init: Some(Ident::new_no_ctxt(atom!("arguments"), DUMMY_SP).into()),
163                definite: false,
164            });
165        }
166        if let Some(id) = new_target {
167            decls.push(VarDeclarator {
168                span: DUMMY_SP,
169                name: id.into(),
170                init: Some(
171                    MetaPropExpr {
172                        span: DUMMY_SP,
173                        kind: MetaPropKind::NewTarget,
174                    }
175                    .into(),
176                ),
177                definite: false,
178            });
179        }
180
181        extend_super(&mut decls, super_get, super_set, super_update);
182
183        if decls.is_empty() {
184            (None, None)
185        } else {
186            (
187                Some(
188                    VarDecl {
189                        kind: VarDeclKind::Var,
190                        decls,
191                        ..Default::default()
192                    }
193                    .into(),
194                ),
195                this,
196            )
197        }
198    }
199
200    fn get_this(&mut self) -> Ident {
201        self.this
202            .get_or_insert_with(|| private_ident!("_this"))
203            .clone()
204    }
205
206    fn super_get(&mut self, prop_name: &Atom, prop_span: Span) -> Ident {
207        if let Some(callee) = self.super_get.ident.get(prop_name) {
208            callee.clone()
209        } else {
210            let ident = private_ident!(prop_span, format!("_superprop_get_{}", prop_name));
211            self.super_get
212                .ident
213                .insert(prop_name.clone(), ident.clone());
214            ident
215        }
216    }
217
218    fn super_get_computed(&mut self, span: Span) -> Ident {
219        self.super_get
220            .computed
221            .get_or_insert_with(|| private_ident!(span, "_superprop_get"))
222            .clone()
223    }
224
225    fn super_set(&mut self, prop_name: &Atom, prop_span: Span) -> Ident {
226        if let Some(callee) = self.super_set.ident.get(prop_name) {
227            callee.clone()
228        } else {
229            let ident = private_ident!(prop_span, format!("_superprop_set_{}", prop_name));
230            self.super_set
231                .ident
232                .insert(prop_name.clone(), ident.clone());
233            ident
234        }
235    }
236
237    fn super_set_computed(&mut self, span: Span) -> Ident {
238        self.super_set
239            .computed
240            .get_or_insert_with(|| private_ident!(span, "_superprop_set"))
241            .clone()
242    }
243
244    fn super_update(&mut self, prop_name: &Atom, prop_span: Span) -> Ident {
245        if let Some(callee) = self.super_update.ident.get(prop_name) {
246            callee.clone()
247        } else {
248            self.super_get
249                .ident
250                .entry(prop_name.clone())
251                .or_insert_with(|| {
252                    private_ident!(prop_span, format!("_superprop_get_{}", prop_name))
253                });
254
255            self.super_set
256                .ident
257                .entry(prop_name.clone())
258                .or_insert_with(|| {
259                    private_ident!(prop_span, format!("_superprop_set_{}", prop_name))
260                });
261
262            let ident = private_ident!(prop_span, format!("_superprop_update_{}", prop_name));
263            self.super_update
264                .ident
265                .insert(prop_name.clone(), ident.clone());
266            ident
267        }
268    }
269
270    fn super_update_computed(&mut self, span: Span) -> Ident {
271        self.super_get
272            .computed
273            .get_or_insert_with(|| private_ident!(span, "_superprop_get"));
274        self.super_set
275            .computed
276            .get_or_insert_with(|| private_ident!(span, "_superprop_set"));
277        self.super_update
278            .computed
279            .get_or_insert_with(|| private_ident!(span, "_superprop_update"))
280            .clone()
281    }
282
283    fn take_extra_var_decl(&mut self) -> Option<Stmt> {
284        if self.extra_ident.is_empty() {
285            return None;
286        }
287
288        Some(
289            VarDecl {
290                kind: VarDeclKind::Var,
291                decls: self
292                    .extra_ident
293                    .take()
294                    .into_iter()
295                    .map(|ident| VarDeclarator {
296                        span: DUMMY_SP,
297                        name: ident.into(),
298                        init: None,
299                        definite: false,
300                    })
301                    .collect(),
302                ..Default::default()
303            }
304            .into(),
305        )
306    }
307
308    fn prepend_extra_var_decl(&mut self, stmts: &mut Vec<Stmt>) {
309        if let Some(decl) = self.take_extra_var_decl() {
310            stmts.insert(0, decl);
311        }
312    }
313}
314
315impl VisitMut for FnEnvHoister {
316    noop_visit_mut_type!(fail);
317
318    fn visit_mut_assign_target_pat(&mut self, n: &mut AssignTargetPat) {
319        let in_pat = self.in_pat;
320        self.in_pat = true;
321        n.visit_mut_children_with(self);
322        self.in_pat = in_pat;
323    }
324
325    fn visit_mut_block_stmt(&mut self, b: &mut BlockStmt) {
326        b.visit_mut_children_with(self);
327
328        // We will not visit into nested functions or classes, so declarations
329        // collected while visiting this block belong to the current function.
330        self.prepend_extra_var_decl(&mut b.stmts);
331    }
332
333    fn visit_mut_function_body(&mut self, body: &mut FunctionBody) {
334        body.visit_mut_children_with(self);
335
336        self.prepend_extra_var_decl(&mut body.stmts);
337    }
338
339    fn visit_mut_arrow_function_body(&mut self, body: &mut ArrowFunctionBody) {
340        body.visit_mut_children_with(self);
341
342        let Some(decl) = self.take_extra_var_decl() else {
343            return;
344        };
345        if let ArrowFunctionBody::Expr(expr) = body {
346            *body = ArrowFunctionBody::FunctionBody(FunctionBody {
347                span: DUMMY_SP,
348                stmts: vec![
349                    decl,
350                    Stmt::Return(ReturnStmt {
351                        span: expr.span(),
352                        arg: Some(expr.take()),
353                    }),
354                ],
355            });
356        }
357    }
358
359    /// Don't recurse into constructor
360    fn visit_mut_class(&mut self, _: &mut Class) {}
361
362    fn visit_mut_expr(&mut self, e: &mut Expr) {
363        match e {
364            Expr::Ident(Ident { ctxt, sym, .. })
365                if !self.arguments_disabled
366                    && *sym == "arguments"
367                    && (*ctxt == self.unresolved_ctxt || *ctxt == SyntaxContext::empty()) =>
368            {
369                let arguments = self
370                    .args
371                    .get_or_insert_with(|| private_ident!("_arguments"));
372                *e = arguments.clone().into();
373            }
374            Expr::This(..) if !self.this_disabled => {
375                let this = self.get_this();
376                *e = this.into();
377            }
378            Expr::MetaProp(MetaPropExpr {
379                kind: MetaPropKind::NewTarget,
380                ..
381            }) => {
382                let target = self
383                    .new_target
384                    .get_or_insert_with(|| private_ident!("_newtarget"));
385                *e = target.clone().into();
386            }
387            // super.foo = 123 => super_get_foo = (value) => super.foo = value
388            Expr::Assign(AssignExpr {
389                left,
390                right,
391                span,
392                op,
393            }) => {
394                let expr = match left {
395                    AssignTarget::Simple(e) => e,
396                    AssignTarget::Pat(..) => {
397                        e.visit_mut_children_with(self);
398                        return;
399                    }
400                    #[cfg(swc_ast_unknown)]
401                    _ => return,
402                };
403                if !self.super_disabled {
404                    if let SimpleAssignTarget::SuperProp(super_prop) = &mut *expr {
405                        let left_span = super_prop.span;
406                        match &mut super_prop.prop {
407                            SuperProp::Computed(c) => {
408                                let callee = self.super_set_computed(left_span);
409
410                                let op = op.to_update();
411
412                                let args = if let Some(op) = op {
413                                    let tmp = private_ident!("tmp");
414                                    self.extra_ident.push(tmp.clone());
415                                    vec![
416                                        Expr::Assign(AssignExpr {
417                                            span: DUMMY_SP,
418                                            left: tmp.clone().into(),
419                                            op: op!("="),
420                                            right: c.expr.take(),
421                                        })
422                                        .as_arg(),
423                                        Expr::Bin(BinExpr {
424                                            span: DUMMY_SP,
425                                            left: Box::new(Expr::Call(CallExpr {
426                                                span: DUMMY_SP,
427                                                callee: self
428                                                    .super_get_computed(DUMMY_SP)
429                                                    .as_callee(),
430                                                args: vec![tmp.as_arg()],
431                                                ..Default::default()
432                                            })),
433                                            op,
434                                            right: right.take(),
435                                        })
436                                        .as_arg(),
437                                    ]
438                                } else {
439                                    vec![c.expr.take().as_arg(), right.take().as_arg()]
440                                };
441                                *e = CallExpr {
442                                    span: *span,
443                                    args,
444                                    callee: callee.as_callee(),
445                                    ..Default::default()
446                                }
447                                .into();
448                            }
449                            SuperProp::Ident(id) => {
450                                let callee = self.super_set(&id.sym, left_span);
451                                *e = CallExpr {
452                                    span: *span,
453                                    args: vec![(if let Some(op) = op.to_update() {
454                                        Box::new(Expr::Bin(BinExpr {
455                                            span: DUMMY_SP,
456                                            left: Box::new(
457                                                self.super_get(&id.sym, id.span)
458                                                    .as_call(id.span, Vec::new()),
459                                            ),
460                                            op,
461                                            right: right.take(),
462                                        }))
463                                    } else {
464                                        right.take()
465                                    })
466                                    .as_arg()],
467                                    callee: callee.as_callee(),
468                                    ..Default::default()
469                                }
470                                .into();
471                            }
472                            #[cfg(swc_ast_unknown)]
473                            _ => (),
474                        }
475                    }
476                }
477                e.visit_mut_children_with(self)
478            }
479            // super.foo() => super_get_foo = () => super.foo
480            Expr::Call(CallExpr {
481                span,
482                callee: Callee::Expr(expr),
483                args,
484                ..
485            }) => {
486                if !self.super_disabled {
487                    if let Expr::SuperProp(super_prop) = &mut **expr {
488                        match &mut super_prop.prop {
489                            SuperProp::Computed(c) => {
490                                let callee = self.super_get_computed(super_prop.span);
491                                let call: Expr = CallExpr {
492                                    span: *span,
493                                    args: vec![c.expr.take().as_arg()],
494                                    callee: callee.as_callee(),
495                                    ..Default::default()
496                                }
497                                .into();
498                                let mut new_args = args.take();
499
500                                new_args.insert(0, self.get_this().as_arg());
501
502                                *e = call.call_fn(*span, new_args);
503                            }
504                            SuperProp::Ident(id) => {
505                                let callee = self.super_get(&id.sym, super_prop.span);
506                                let call: Expr = CallExpr {
507                                    span: *span,
508                                    args: Vec::new(),
509                                    callee: callee.as_callee(),
510                                    ..Default::default()
511                                }
512                                .into();
513                                let mut new_args = args.take();
514
515                                new_args.insert(0, self.get_this().as_arg());
516
517                                *e = call.call_fn(*span, new_args);
518                            }
519                            #[cfg(swc_ast_unknown)]
520                            _ => (),
521                        }
522                    };
523                }
524                e.visit_mut_children_with(self)
525            }
526            // super.foo ++
527            Expr::Update(UpdateExpr { arg, .. }) if arg.is_super_prop() => {
528                let in_pat = self.in_pat;
529                // NOTE: It's not in pat, but we need the `update` trick
530                self.in_pat = true;
531                arg.visit_mut_with(self);
532                self.in_pat = in_pat;
533            }
534            Expr::SuperProp(SuperPropExpr { prop, span, .. }) if !self.super_disabled => match prop
535            {
536                SuperProp::Computed(c) => {
537                    c.expr.visit_mut_children_with(self);
538                    *e = if self.in_pat {
539                        Expr::from(CallExpr {
540                            span: *span,
541                            args: vec![c.expr.take().as_arg()],
542                            callee: self.super_update_computed(*span).as_callee(),
543                            ..Default::default()
544                        })
545                        .make_member(atom!("_").into())
546                        .into()
547                    } else {
548                        CallExpr {
549                            span: *span,
550                            args: vec![c.expr.take().as_arg()],
551                            callee: self.super_get_computed(*span).as_callee(),
552                            ..Default::default()
553                        }
554                        .into()
555                    };
556                }
557                SuperProp::Ident(id) => {
558                    *e = if self.in_pat {
559                        self.super_update(&id.sym, *span)
560                            .make_member(quote_ident!("_"))
561                            .into()
562                    } else {
563                        CallExpr {
564                            span: *span,
565                            args: Vec::new(),
566                            callee: self.super_get(&id.sym, *span).as_callee(),
567                            ..Default::default()
568                        }
569                        .into()
570                    };
571                }
572                #[cfg(swc_ast_unknown)]
573                _ => (),
574            },
575            _ => e.visit_mut_children_with(self),
576        }
577    }
578
579    /// Don't recurse into fn
580    fn visit_mut_function(&mut self, _: &mut Function) {}
581
582    fn visit_mut_pat(&mut self, n: &mut Pat) {
583        let in_pat = self.in_pat;
584        self.in_pat = true;
585        n.visit_mut_children_with(self);
586        self.in_pat = in_pat;
587    }
588}
589
590pub fn init_this(stmts: &mut Vec<Stmt>, this_id: &Ident) {
591    stmts.visit_mut_children_with(&mut InitThis { this_id })
592}
593
594struct InitThis<'a> {
595    this_id: &'a Ident,
596}
597
598// babel is skip function and class property
599impl VisitMut for InitThis<'_> {
600    noop_visit_mut_type!(fail);
601
602    fn visit_mut_class(&mut self, _: &mut Class) {}
603
604    // babel will transform super() to super(); _this = this
605    // hopefully it will be meaningless
606    // fn visit_mut_stmts(&mut self, stmt: &mut Vec<Stmt>) {}
607
608    fn visit_mut_expr(&mut self, expr: &mut Expr) {
609        expr.visit_mut_children_with(self);
610
611        if let Expr::Call(
612            call_expr @ CallExpr {
613                callee: Callee::Super(..),
614                ..
615            },
616        ) = expr
617        {
618            let span = call_expr.span;
619            *expr = ParenExpr {
620                span,
621                expr: SeqExpr {
622                    span,
623                    exprs: vec![
624                        Box::new(Expr::Call(call_expr.take())),
625                        Box::new(Expr::Assign(AssignExpr {
626                            span: DUMMY_SP,
627                            left: self.this_id.clone().into(),
628                            op: AssignOp::Assign,
629                            right: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })),
630                        })),
631                    ],
632                }
633                .into(),
634            }
635            .into()
636        }
637    }
638}
639
640fn extend_super(
641    decls: &mut Vec<VarDeclarator>,
642    get: SuperField,
643    set: SuperField,
644    update: SuperField,
645) {
646    decls.extend(update.ident.into_iter().map(|(key, ident)| {
647        let value = private_ident!("v");
648        VarDeclarator {
649            span: DUMMY_SP,
650            name: ident.into(),
651            init: Some(
652                ObjectLit {
653                    span: DUMMY_SP,
654                    props: vec![
655                        Prop::Getter(GetterProp {
656                            span: DUMMY_SP,
657                            key: PropName::Ident(atom!("_").into()),
658                            function: Box::new(Function {
659                                body: Some(FunctionBody {
660                                    span: DUMMY_SP,
661                                    stmts: vec![Expr::Ident(
662                                        get.ident
663                                            .get(&key)
664                                            .cloned()
665                                            .expect("getter not found")
666                                            .without_loc(),
667                                    )
668                                    .as_call(DUMMY_SP, Default::default())
669                                    .into_return_stmt()
670                                    .into()],
671                                }),
672                                ..Default::default()
673                            }),
674                        }),
675                        Prop::Setter(SetterProp {
676                            span: DUMMY_SP,
677                            key: PropName::Ident(atom!("_").into()),
678                            function: Box::new(Function {
679                                params: vec![Param::from(Pat::from(value.clone()))],
680                                body: Some(FunctionBody {
681                                    span: DUMMY_SP,
682                                    stmts: vec![Expr::Ident(
683                                        set.ident
684                                            .get(&key)
685                                            .cloned()
686                                            .expect("setter not found")
687                                            .without_loc(),
688                                    )
689                                    .as_call(DUMMY_SP, vec![value.as_arg()])
690                                    .into_stmt()],
691                                }),
692                                ..Default::default()
693                            }),
694                        }),
695                    ]
696                    .into_iter()
697                    .map(Box::new)
698                    .map(From::from)
699                    .collect(),
700                }
701                .into(),
702            ),
703            definite: false,
704        }
705    }));
706    if let Some(id) = update.computed {
707        let prop = private_ident!("_prop");
708        let value = private_ident!("v");
709
710        decls.push(VarDeclarator {
711            span: DUMMY_SP,
712            name: id.into(),
713            init: Some(
714                ArrowExpr {
715                    span: DUMMY_SP,
716                    params: vec![prop.clone().into()],
717                    body: Box::new(ArrowFunctionBody::Expr(Box::new(
718                        ObjectLit {
719                            span: DUMMY_SP,
720                            props: vec![
721                                Prop::Getter(GetterProp {
722                                    span: DUMMY_SP,
723                                    key: PropName::Ident(atom!("_").into()),
724                                    function: Box::new(Function {
725                                        body: Some(FunctionBody {
726                                            span: DUMMY_SP,
727                                            stmts: vec![Expr::Ident(
728                                                get.computed
729                                                    .clone()
730                                                    .expect("getter computed not found")
731                                                    .without_loc(),
732                                            )
733                                            .as_call(DUMMY_SP, vec![prop.clone().as_arg()])
734                                            .into_return_stmt()
735                                            .into()],
736                                        }),
737                                        ..Default::default()
738                                    }),
739                                }),
740                                Prop::Setter(SetterProp {
741                                    span: DUMMY_SP,
742                                    key: PropName::Ident(atom!("_").into()),
743                                    function: Box::new(Function {
744                                        params: vec![Param::from(Pat::from(value.clone()))],
745                                        body: Some(FunctionBody {
746                                            span: DUMMY_SP,
747                                            stmts: vec![Expr::Ident(
748                                                set.computed
749                                                    .clone()
750                                                    .expect("setter computed not found")
751                                                    .without_loc(),
752                                            )
753                                            .as_call(DUMMY_SP, vec![prop.as_arg(), value.as_arg()])
754                                            .into_return_stmt()
755                                            .into()],
756                                        }),
757                                        ..Default::default()
758                                    }),
759                                }),
760                            ]
761                            .into_iter()
762                            .map(Box::new)
763                            .map(From::from)
764                            .collect(),
765                        }
766                        .into(),
767                    ))),
768                    ..Default::default()
769                }
770                .into(),
771            ),
772            definite: false,
773        });
774    }
775    decls.extend(get.ident.into_iter().map(|(key, ident)| {
776        VarDeclarator {
777            span: DUMMY_SP,
778            name: ident.without_loc().into(),
779            init: Some(
780                ArrowExpr {
781                    span: DUMMY_SP,
782                    params: Vec::new(),
783                    body: Box::new(ArrowFunctionBody::Expr(Box::new(
784                        SuperPropExpr {
785                            obj: Super { span: DUMMY_SP },
786                            prop: SuperProp::Ident(key.into()),
787                            span: DUMMY_SP,
788                        }
789                        .into(),
790                    ))),
791                    ..Default::default()
792                }
793                .into(),
794            ),
795            definite: false,
796        }
797    }));
798    if let Some(id) = get.computed {
799        let param = private_ident!("_prop");
800        decls.push(VarDeclarator {
801            span: DUMMY_SP,
802            name: id.without_loc().into(),
803            init: Some(
804                ArrowExpr {
805                    span: DUMMY_SP,
806                    params: vec![param.clone().into()],
807                    body: Box::new(ArrowFunctionBody::Expr(Box::new(
808                        SuperPropExpr {
809                            obj: Super { span: DUMMY_SP },
810                            prop: SuperProp::Computed(ComputedPropName {
811                                span: DUMMY_SP,
812                                expr: Box::new(Expr::Ident(param)),
813                            }),
814                            span: DUMMY_SP,
815                        }
816                        .into(),
817                    ))),
818                    ..Default::default()
819                }
820                .into(),
821            ),
822            definite: false,
823        });
824    }
825    decls.extend(set.ident.into_iter().map(|(key, ident)| {
826        let value = private_ident!("_value");
827        VarDeclarator {
828            span: DUMMY_SP,
829            name: ident.without_loc().into(),
830            init: Some(
831                ArrowExpr {
832                    span: DUMMY_SP,
833                    params: vec![value.clone().into()],
834                    body: Box::new(ArrowFunctionBody::Expr(Box::new(
835                        AssignExpr {
836                            span: DUMMY_SP,
837                            left: SuperPropExpr {
838                                obj: Super { span: DUMMY_SP },
839                                prop: SuperProp::Ident(key.into()),
840                                span: DUMMY_SP,
841                            }
842                            .into(),
843                            op: op!("="),
844                            right: Box::new(Expr::Ident(value)),
845                        }
846                        .into(),
847                    ))),
848                    ..Default::default()
849                }
850                .into(),
851            ),
852            definite: false,
853        }
854    }));
855    if let Some(id) = set.computed {
856        let prop = private_ident!("_prop");
857        let value = private_ident!("_value");
858        decls.push(VarDeclarator {
859            span: DUMMY_SP,
860            name: id.without_loc().into(),
861            init: Some(
862                ArrowExpr {
863                    span: DUMMY_SP,
864                    params: vec![prop.clone().into(), value.clone().into()],
865                    body: Box::new(ArrowFunctionBody::Expr(Box::new(
866                        AssignExpr {
867                            span: DUMMY_SP,
868                            left: SuperPropExpr {
869                                obj: Super { span: DUMMY_SP },
870                                prop: SuperProp::Computed(ComputedPropName {
871                                    span: DUMMY_SP,
872                                    expr: Box::new(Expr::Ident(prop)),
873                                }),
874                                span: DUMMY_SP,
875                            }
876                            .into(),
877                            op: op!("="),
878                            right: Box::new(Expr::Ident(value)),
879                        }
880                        .into(),
881                    ))),
882                    ..Default::default()
883                }
884                .into(),
885            ),
886            definite: false,
887        });
888    }
889}