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
284impl VisitMut for FnEnvHoister {
285    noop_visit_mut_type!(fail);
286
287    fn visit_mut_assign_target_pat(&mut self, n: &mut AssignTargetPat) {
288        let in_pat = self.in_pat;
289        self.in_pat = true;
290        n.visit_mut_children_with(self);
291        self.in_pat = in_pat;
292    }
293
294    fn visit_mut_block_stmt(&mut self, b: &mut BlockStmt) {
295        b.visit_mut_children_with(self);
296
297        // we will not vist into fn/class so it's fine
298        if !self.extra_ident.is_empty() {
299            b.stmts.insert(
300                0,
301                VarDecl {
302                    kind: VarDeclKind::Var,
303                    decls: self
304                        .extra_ident
305                        .take()
306                        .into_iter()
307                        .map(|ident| VarDeclarator {
308                            span: DUMMY_SP,
309                            name: ident.into(),
310                            init: None,
311                            definite: false,
312                        })
313                        .collect(),
314                    ..Default::default()
315                }
316                .into(),
317            )
318        }
319    }
320
321    fn visit_mut_block_stmt_or_expr(&mut self, b: &mut BlockStmtOrExpr) {
322        b.visit_mut_children_with(self);
323
324        // we will not vist into fn/class so it's fine
325        if !self.extra_ident.is_empty() {
326            if let BlockStmtOrExpr::Expr(e) = b {
327                *b = BlockStmtOrExpr::BlockStmt(BlockStmt {
328                    stmts: vec![
329                        Stmt::Decl(Decl::Var(Box::new(VarDecl {
330                            kind: VarDeclKind::Var,
331                            decls: self
332                                .extra_ident
333                                .take()
334                                .into_iter()
335                                .map(|ident| VarDeclarator {
336                                    span: DUMMY_SP,
337                                    name: ident.into(),
338                                    init: None,
339                                    definite: false,
340                                })
341                                .collect(),
342                            ..Default::default()
343                        }))),
344                        Stmt::Return(ReturnStmt {
345                            span: e.span(),
346                            arg: Some(e.take()),
347                        }),
348                    ],
349                    ..Default::default()
350                })
351            }
352        }
353    }
354
355    /// Don't recurse into constructor
356    fn visit_mut_class(&mut self, _: &mut Class) {}
357
358    fn visit_mut_expr(&mut self, e: &mut Expr) {
359        match e {
360            Expr::Ident(Ident { ctxt, sym, .. })
361                if !self.arguments_disabled
362                    && *sym == "arguments"
363                    && (*ctxt == self.unresolved_ctxt || *ctxt == SyntaxContext::empty()) =>
364            {
365                let arguments = self
366                    .args
367                    .get_or_insert_with(|| private_ident!("_arguments"));
368                *e = arguments.clone().into();
369            }
370            Expr::This(..) if !self.this_disabled => {
371                let this = self.get_this();
372                *e = this.into();
373            }
374            Expr::MetaProp(MetaPropExpr {
375                kind: MetaPropKind::NewTarget,
376                ..
377            }) => {
378                let target = self
379                    .new_target
380                    .get_or_insert_with(|| private_ident!("_newtarget"));
381                *e = target.clone().into();
382            }
383            // super.foo = 123 => super_get_foo = (value) => super.foo = value
384            Expr::Assign(AssignExpr {
385                left,
386                right,
387                span,
388                op,
389            }) => {
390                let expr = match left {
391                    AssignTarget::Simple(e) => e,
392                    AssignTarget::Pat(..) => {
393                        e.visit_mut_children_with(self);
394                        return;
395                    }
396                    #[cfg(swc_ast_unknown)]
397                    _ => return,
398                };
399                if !self.super_disabled {
400                    if let SimpleAssignTarget::SuperProp(super_prop) = &mut *expr {
401                        let left_span = super_prop.span;
402                        match &mut super_prop.prop {
403                            SuperProp::Computed(c) => {
404                                let callee = self.super_set_computed(left_span);
405
406                                let op = op.to_update();
407
408                                let args = if let Some(op) = op {
409                                    let tmp = private_ident!("tmp");
410                                    self.extra_ident.push(tmp.clone());
411                                    vec![
412                                        Expr::Assign(AssignExpr {
413                                            span: DUMMY_SP,
414                                            left: tmp.clone().into(),
415                                            op: op!("="),
416                                            right: c.expr.take(),
417                                        })
418                                        .as_arg(),
419                                        Expr::Bin(BinExpr {
420                                            span: DUMMY_SP,
421                                            left: Box::new(Expr::Call(CallExpr {
422                                                span: DUMMY_SP,
423                                                callee: self
424                                                    .super_get_computed(DUMMY_SP)
425                                                    .as_callee(),
426                                                args: vec![tmp.as_arg()],
427                                                ..Default::default()
428                                            })),
429                                            op,
430                                            right: right.take(),
431                                        })
432                                        .as_arg(),
433                                    ]
434                                } else {
435                                    vec![c.expr.take().as_arg(), right.take().as_arg()]
436                                };
437                                *e = CallExpr {
438                                    span: *span,
439                                    args,
440                                    callee: callee.as_callee(),
441                                    ..Default::default()
442                                }
443                                .into();
444                            }
445                            SuperProp::Ident(id) => {
446                                let callee = self.super_set(&id.sym, left_span);
447                                *e = CallExpr {
448                                    span: *span,
449                                    args: vec![(if let Some(op) = op.to_update() {
450                                        Box::new(Expr::Bin(BinExpr {
451                                            span: DUMMY_SP,
452                                            left: Box::new(
453                                                self.super_get(&id.sym, id.span)
454                                                    .as_call(id.span, Vec::new()),
455                                            ),
456                                            op,
457                                            right: right.take(),
458                                        }))
459                                    } else {
460                                        right.take()
461                                    })
462                                    .as_arg()],
463                                    callee: callee.as_callee(),
464                                    ..Default::default()
465                                }
466                                .into();
467                            }
468                            #[cfg(swc_ast_unknown)]
469                            _ => (),
470                        }
471                    }
472                }
473                e.visit_mut_children_with(self)
474            }
475            // super.foo() => super_get_foo = () => super.foo
476            Expr::Call(CallExpr {
477                span,
478                callee: Callee::Expr(expr),
479                args,
480                ..
481            }) => {
482                if !self.super_disabled {
483                    if let Expr::SuperProp(super_prop) = &mut **expr {
484                        match &mut super_prop.prop {
485                            SuperProp::Computed(c) => {
486                                let callee = self.super_get_computed(super_prop.span);
487                                let call: Expr = CallExpr {
488                                    span: *span,
489                                    args: vec![c.expr.take().as_arg()],
490                                    callee: callee.as_callee(),
491                                    ..Default::default()
492                                }
493                                .into();
494                                let mut new_args = args.take();
495
496                                new_args.insert(0, self.get_this().as_arg());
497
498                                *e = call.call_fn(*span, new_args);
499                            }
500                            SuperProp::Ident(id) => {
501                                let callee = self.super_get(&id.sym, super_prop.span);
502                                let call: Expr = CallExpr {
503                                    span: *span,
504                                    args: Vec::new(),
505                                    callee: callee.as_callee(),
506                                    ..Default::default()
507                                }
508                                .into();
509                                let mut new_args = args.take();
510
511                                new_args.insert(0, self.get_this().as_arg());
512
513                                *e = call.call_fn(*span, new_args);
514                            }
515                            #[cfg(swc_ast_unknown)]
516                            _ => (),
517                        }
518                    };
519                }
520                e.visit_mut_children_with(self)
521            }
522            // super.foo ++
523            Expr::Update(UpdateExpr { arg, .. }) if arg.is_super_prop() => {
524                let in_pat = self.in_pat;
525                // NOTE: It's not in pat, but we need the `update` trick
526                self.in_pat = true;
527                arg.visit_mut_with(self);
528                self.in_pat = in_pat;
529            }
530            Expr::SuperProp(SuperPropExpr { prop, span, .. }) if !self.super_disabled => match prop
531            {
532                SuperProp::Computed(c) => {
533                    c.expr.visit_mut_children_with(self);
534                    *e = if self.in_pat {
535                        Expr::from(CallExpr {
536                            span: *span,
537                            args: vec![c.expr.take().as_arg()],
538                            callee: self.super_update_computed(*span).as_callee(),
539                            ..Default::default()
540                        })
541                        .make_member(atom!("_").into())
542                        .into()
543                    } else {
544                        CallExpr {
545                            span: *span,
546                            args: vec![c.expr.take().as_arg()],
547                            callee: self.super_get_computed(*span).as_callee(),
548                            ..Default::default()
549                        }
550                        .into()
551                    };
552                }
553                SuperProp::Ident(id) => {
554                    *e = if self.in_pat {
555                        self.super_update(&id.sym, *span)
556                            .make_member(quote_ident!("_"))
557                            .into()
558                    } else {
559                        CallExpr {
560                            span: *span,
561                            args: Vec::new(),
562                            callee: self.super_get(&id.sym, *span).as_callee(),
563                            ..Default::default()
564                        }
565                        .into()
566                    };
567                }
568                #[cfg(swc_ast_unknown)]
569                _ => (),
570            },
571            _ => e.visit_mut_children_with(self),
572        }
573    }
574
575    /// Don't recurse into fn
576    fn visit_mut_function(&mut self, _: &mut Function) {}
577
578    /// Don't recurse into getter/setter/method except computed key
579    fn visit_mut_getter_prop(&mut self, p: &mut GetterProp) {
580        if p.key.is_computed() {
581            p.key.visit_mut_with(self);
582        }
583    }
584
585    fn visit_mut_method_prop(&mut self, p: &mut MethodProp) {
586        if p.key.is_computed() {
587            p.key.visit_mut_with(self);
588        }
589    }
590
591    fn visit_mut_pat(&mut self, n: &mut Pat) {
592        let in_pat = self.in_pat;
593        self.in_pat = true;
594        n.visit_mut_children_with(self);
595        self.in_pat = in_pat;
596    }
597
598    fn visit_mut_setter_prop(&mut self, p: &mut SetterProp) {
599        if p.key.is_computed() {
600            p.key.visit_mut_with(self);
601        }
602    }
603}
604
605pub fn init_this(stmts: &mut Vec<Stmt>, this_id: &Ident) {
606    stmts.visit_mut_children_with(&mut InitThis { this_id })
607}
608
609struct InitThis<'a> {
610    this_id: &'a Ident,
611}
612
613// babel is skip function and class property
614impl VisitMut for InitThis<'_> {
615    noop_visit_mut_type!(fail);
616
617    fn visit_mut_class(&mut self, _: &mut Class) {}
618
619    // babel will transform super() to super(); _this = this
620    // hopefully it will be meaningless
621    // fn visit_mut_stmts(&mut self, stmt: &mut Vec<Stmt>) {}
622
623    fn visit_mut_expr(&mut self, expr: &mut Expr) {
624        expr.visit_mut_children_with(self);
625
626        if let Expr::Call(
627            call_expr @ CallExpr {
628                callee: Callee::Super(..),
629                ..
630            },
631        ) = expr
632        {
633            let span = call_expr.span;
634            *expr = ParenExpr {
635                span,
636                expr: SeqExpr {
637                    span,
638                    exprs: vec![
639                        Box::new(Expr::Call(call_expr.take())),
640                        Box::new(Expr::Assign(AssignExpr {
641                            span: DUMMY_SP,
642                            left: self.this_id.clone().into(),
643                            op: AssignOp::Assign,
644                            right: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })),
645                        })),
646                    ],
647                }
648                .into(),
649            }
650            .into()
651        }
652    }
653}
654
655fn extend_super(
656    decls: &mut Vec<VarDeclarator>,
657    get: SuperField,
658    set: SuperField,
659    update: SuperField,
660) {
661    decls.extend(update.ident.into_iter().map(|(key, ident)| {
662        let value = private_ident!("v");
663        VarDeclarator {
664            span: DUMMY_SP,
665            name: ident.into(),
666            init: Some(
667                ObjectLit {
668                    span: DUMMY_SP,
669                    props: vec![
670                        Prop::Getter(GetterProp {
671                            span: DUMMY_SP,
672                            key: PropName::Ident(atom!("_").into()),
673                            type_ann: None,
674                            body: Some(BlockStmt {
675                                stmts: vec![Expr::Ident(
676                                    get.ident
677                                        .get(&key)
678                                        .cloned()
679                                        .expect("getter not found")
680                                        .without_loc(),
681                                )
682                                .as_call(DUMMY_SP, Default::default())
683                                .into_return_stmt()
684                                .into()],
685                                ..Default::default()
686                            }),
687                        }),
688                        Prop::Setter(SetterProp {
689                            span: DUMMY_SP,
690                            key: PropName::Ident(atom!("_").into()),
691                            this_param: None,
692                            param: value.clone().into(),
693                            body: Some(BlockStmt {
694                                stmts: vec![Expr::Ident(
695                                    set.ident
696                                        .get(&key)
697                                        .cloned()
698                                        .expect("setter not found")
699                                        .without_loc(),
700                                )
701                                .as_call(DUMMY_SP, vec![value.as_arg()])
702                                .into_stmt()],
703                                ..Default::default()
704                            }),
705                        }),
706                    ]
707                    .into_iter()
708                    .map(Box::new)
709                    .map(From::from)
710                    .collect(),
711                }
712                .into(),
713            ),
714            definite: false,
715        }
716    }));
717    if let Some(id) = update.computed {
718        let prop = private_ident!("_prop");
719        let value = private_ident!("v");
720
721        decls.push(VarDeclarator {
722            span: DUMMY_SP,
723            name: id.into(),
724            init: Some(
725                ArrowExpr {
726                    span: DUMMY_SP,
727                    params: vec![prop.clone().into()],
728                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
729                        ObjectLit {
730                            span: DUMMY_SP,
731                            props: vec![
732                                Prop::Getter(GetterProp {
733                                    span: DUMMY_SP,
734                                    key: PropName::Ident(atom!("_").into()),
735                                    type_ann: None,
736                                    body: Some(BlockStmt {
737                                        stmts: vec![Expr::Ident(
738                                            get.computed
739                                                .clone()
740                                                .expect("getter computed not found")
741                                                .without_loc(),
742                                        )
743                                        .as_call(DUMMY_SP, vec![prop.clone().as_arg()])
744                                        .into_return_stmt()
745                                        .into()],
746                                        ..Default::default()
747                                    }),
748                                }),
749                                Prop::Setter(SetterProp {
750                                    span: DUMMY_SP,
751                                    key: PropName::Ident(atom!("_").into()),
752                                    this_param: None,
753                                    param: value.clone().into(),
754                                    body: Some(BlockStmt {
755                                        stmts: vec![Expr::Ident(
756                                            set.computed
757                                                .clone()
758                                                .expect("setter computed not found")
759                                                .without_loc(),
760                                        )
761                                        .as_call(DUMMY_SP, vec![prop.as_arg(), value.as_arg()])
762                                        .into_return_stmt()
763                                        .into()],
764                                        ..Default::default()
765                                    }),
766                                }),
767                            ]
768                            .into_iter()
769                            .map(Box::new)
770                            .map(From::from)
771                            .collect(),
772                        }
773                        .into(),
774                    ))),
775                    ..Default::default()
776                }
777                .into(),
778            ),
779            definite: false,
780        });
781    }
782    decls.extend(get.ident.into_iter().map(|(key, ident)| {
783        VarDeclarator {
784            span: DUMMY_SP,
785            name: ident.without_loc().into(),
786            init: Some(
787                ArrowExpr {
788                    span: DUMMY_SP,
789                    params: Vec::new(),
790                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
791                        SuperPropExpr {
792                            obj: Super { span: DUMMY_SP },
793                            prop: SuperProp::Ident(key.into()),
794                            span: DUMMY_SP,
795                        }
796                        .into(),
797                    ))),
798                    ..Default::default()
799                }
800                .into(),
801            ),
802            definite: false,
803        }
804    }));
805    if let Some(id) = get.computed {
806        let param = private_ident!("_prop");
807        decls.push(VarDeclarator {
808            span: DUMMY_SP,
809            name: id.without_loc().into(),
810            init: Some(
811                ArrowExpr {
812                    span: DUMMY_SP,
813                    params: vec![param.clone().into()],
814                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
815                        SuperPropExpr {
816                            obj: Super { span: DUMMY_SP },
817                            prop: SuperProp::Computed(ComputedPropName {
818                                span: DUMMY_SP,
819                                expr: Box::new(Expr::Ident(param)),
820                            }),
821                            span: DUMMY_SP,
822                        }
823                        .into(),
824                    ))),
825                    ..Default::default()
826                }
827                .into(),
828            ),
829            definite: false,
830        });
831    }
832    decls.extend(set.ident.into_iter().map(|(key, ident)| {
833        let value = private_ident!("_value");
834        VarDeclarator {
835            span: DUMMY_SP,
836            name: ident.without_loc().into(),
837            init: Some(
838                ArrowExpr {
839                    span: DUMMY_SP,
840                    params: vec![value.clone().into()],
841                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
842                        AssignExpr {
843                            span: DUMMY_SP,
844                            left: SuperPropExpr {
845                                obj: Super { span: DUMMY_SP },
846                                prop: SuperProp::Ident(key.into()),
847                                span: DUMMY_SP,
848                            }
849                            .into(),
850                            op: op!("="),
851                            right: Box::new(Expr::Ident(value)),
852                        }
853                        .into(),
854                    ))),
855                    ..Default::default()
856                }
857                .into(),
858            ),
859            definite: false,
860        }
861    }));
862    if let Some(id) = set.computed {
863        let prop = private_ident!("_prop");
864        let value = private_ident!("_value");
865        decls.push(VarDeclarator {
866            span: DUMMY_SP,
867            name: id.without_loc().into(),
868            init: Some(
869                ArrowExpr {
870                    span: DUMMY_SP,
871                    params: vec![prop.clone().into(), value.clone().into()],
872                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
873                        AssignExpr {
874                            span: DUMMY_SP,
875                            left: SuperPropExpr {
876                                obj: Super { span: DUMMY_SP },
877                                prop: SuperProp::Computed(ComputedPropName {
878                                    span: DUMMY_SP,
879                                    expr: Box::new(Expr::Ident(prop)),
880                                }),
881                                span: DUMMY_SP,
882                            }
883                            .into(),
884                            op: op!("="),
885                            right: Box::new(Expr::Ident(value)),
886                        }
887                        .into(),
888                    ))),
889                    ..Default::default()
890                }
891                .into(),
892            ),
893            definite: false,
894        });
895    }
896}