swc_ecma_utils/function/
fn_env_hoister.rs

1use std::mem;
2
3use indexmap::IndexMap;
4use rustc_hash::FxBuildHasher;
5use swc_atoms::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("arguments".into(), 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("arguments".into(), 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                };
397                if !self.super_disabled {
398                    if let SimpleAssignTarget::SuperProp(super_prop) = &mut *expr {
399                        let left_span = super_prop.span;
400                        match &mut super_prop.prop {
401                            SuperProp::Computed(c) => {
402                                let callee = self.super_set_computed(left_span);
403
404                                let op = op.to_update();
405
406                                let args = if let Some(op) = op {
407                                    let tmp = private_ident!("tmp");
408                                    self.extra_ident.push(tmp.clone());
409                                    vec![
410                                        Expr::Assign(AssignExpr {
411                                            span: DUMMY_SP,
412                                            left: tmp.clone().into(),
413                                            op: op!("="),
414                                            right: c.expr.take(),
415                                        })
416                                        .as_arg(),
417                                        Expr::Bin(BinExpr {
418                                            span: DUMMY_SP,
419                                            left: Box::new(Expr::Call(CallExpr {
420                                                span: DUMMY_SP,
421                                                callee: self
422                                                    .super_get_computed(DUMMY_SP)
423                                                    .as_callee(),
424                                                args: vec![tmp.as_arg()],
425                                                ..Default::default()
426                                            })),
427                                            op,
428                                            right: right.take(),
429                                        })
430                                        .as_arg(),
431                                    ]
432                                } else {
433                                    vec![c.expr.take().as_arg(), right.take().as_arg()]
434                                };
435                                *e = CallExpr {
436                                    span: *span,
437                                    args,
438                                    callee: callee.as_callee(),
439                                    ..Default::default()
440                                }
441                                .into();
442                            }
443                            SuperProp::Ident(id) => {
444                                let callee = self.super_set(&id.sym, left_span);
445                                *e = CallExpr {
446                                    span: *span,
447                                    args: vec![(if let Some(op) = op.to_update() {
448                                        Box::new(Expr::Bin(BinExpr {
449                                            span: DUMMY_SP,
450                                            left: Box::new(
451                                                self.super_get(&id.sym, id.span)
452                                                    .as_call(id.span, Vec::new()),
453                                            ),
454                                            op,
455                                            right: right.take(),
456                                        }))
457                                    } else {
458                                        right.take()
459                                    })
460                                    .as_arg()],
461                                    callee: callee.as_callee(),
462                                    ..Default::default()
463                                }
464                                .into();
465                            }
466                        }
467                    }
468                }
469                e.visit_mut_children_with(self)
470            }
471            // super.foo() => super_get_foo = () => super.foo
472            Expr::Call(CallExpr {
473                span,
474                callee: Callee::Expr(expr),
475                args,
476                ..
477            }) => {
478                if !self.super_disabled {
479                    if let Expr::SuperProp(super_prop) = &mut **expr {
480                        match &mut super_prop.prop {
481                            SuperProp::Computed(c) => {
482                                let callee = self.super_get_computed(super_prop.span);
483                                let call: Expr = CallExpr {
484                                    span: *span,
485                                    args: vec![c.expr.take().as_arg()],
486                                    callee: callee.as_callee(),
487                                    ..Default::default()
488                                }
489                                .into();
490                                let mut new_args = args.take();
491
492                                new_args.insert(0, self.get_this().as_arg());
493
494                                *e = call.call_fn(*span, new_args);
495                            }
496                            SuperProp::Ident(id) => {
497                                let callee = self.super_get(&id.sym, super_prop.span);
498                                let call: Expr = CallExpr {
499                                    span: *span,
500                                    args: Vec::new(),
501                                    callee: callee.as_callee(),
502                                    ..Default::default()
503                                }
504                                .into();
505                                let mut new_args = args.take();
506
507                                new_args.insert(0, self.get_this().as_arg());
508
509                                *e = call.call_fn(*span, new_args);
510                            }
511                        }
512                    };
513                }
514                e.visit_mut_children_with(self)
515            }
516            // super.foo ++
517            Expr::Update(UpdateExpr { arg, .. }) if arg.is_super_prop() => {
518                let in_pat = self.in_pat;
519                // NOTE: It's not in pat, but we need the `update` trick
520                self.in_pat = true;
521                arg.visit_mut_with(self);
522                self.in_pat = in_pat;
523            }
524            Expr::SuperProp(SuperPropExpr { prop, span, .. }) if !self.super_disabled => match prop
525            {
526                SuperProp::Computed(c) => {
527                    c.expr.visit_mut_children_with(self);
528                    *e = if self.in_pat {
529                        Expr::from(CallExpr {
530                            span: *span,
531                            args: vec![c.expr.take().as_arg()],
532                            callee: self.super_update_computed(*span).as_callee(),
533                            ..Default::default()
534                        })
535                        .make_member("_".into())
536                        .into()
537                    } else {
538                        CallExpr {
539                            span: *span,
540                            args: vec![c.expr.take().as_arg()],
541                            callee: self.super_get_computed(*span).as_callee(),
542                            ..Default::default()
543                        }
544                        .into()
545                    };
546                }
547                SuperProp::Ident(id) => {
548                    *e = if self.in_pat {
549                        self.super_update(&id.sym, *span)
550                            .make_member(quote_ident!("_"))
551                            .into()
552                    } else {
553                        CallExpr {
554                            span: *span,
555                            args: Vec::new(),
556                            callee: self.super_get(&id.sym, *span).as_callee(),
557                            ..Default::default()
558                        }
559                        .into()
560                    };
561                }
562            },
563            _ => e.visit_mut_children_with(self),
564        }
565    }
566
567    /// Don't recurse into fn
568    fn visit_mut_function(&mut self, _: &mut Function) {}
569
570    /// Don't recurse into getter/setter/method except computed key
571    fn visit_mut_getter_prop(&mut self, p: &mut GetterProp) {
572        if p.key.is_computed() {
573            p.key.visit_mut_with(self);
574        }
575    }
576
577    fn visit_mut_method_prop(&mut self, p: &mut MethodProp) {
578        if p.key.is_computed() {
579            p.key.visit_mut_with(self);
580        }
581    }
582
583    fn visit_mut_pat(&mut self, n: &mut Pat) {
584        let in_pat = self.in_pat;
585        self.in_pat = true;
586        n.visit_mut_children_with(self);
587        self.in_pat = in_pat;
588    }
589
590    fn visit_mut_setter_prop(&mut self, p: &mut SetterProp) {
591        if p.key.is_computed() {
592            p.key.visit_mut_with(self);
593        }
594    }
595}
596
597pub fn init_this(stmts: &mut Vec<Stmt>, this_id: &Ident) {
598    stmts.visit_mut_children_with(&mut InitThis { this_id })
599}
600
601struct InitThis<'a> {
602    this_id: &'a Ident,
603}
604
605// babel is skip function and class property
606impl VisitMut for InitThis<'_> {
607    noop_visit_mut_type!(fail);
608
609    fn visit_mut_class(&mut self, _: &mut Class) {}
610
611    // babel will transform super() to super(); _this = this
612    // hopefully it will be meaningless
613    // fn visit_mut_stmts(&mut self, stmt: &mut Vec<Stmt>) {}
614
615    fn visit_mut_expr(&mut self, expr: &mut Expr) {
616        expr.visit_mut_children_with(self);
617
618        if let Expr::Call(
619            call_expr @ CallExpr {
620                callee: Callee::Super(..),
621                ..
622            },
623        ) = expr
624        {
625            let span = call_expr.span;
626            *expr = ParenExpr {
627                span,
628                expr: SeqExpr {
629                    span,
630                    exprs: vec![
631                        Box::new(Expr::Call(call_expr.take())),
632                        Box::new(Expr::Assign(AssignExpr {
633                            span: DUMMY_SP,
634                            left: self.this_id.clone().into(),
635                            op: AssignOp::Assign,
636                            right: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })),
637                        })),
638                    ],
639                }
640                .into(),
641            }
642            .into()
643        }
644    }
645}
646
647fn extend_super(
648    decls: &mut Vec<VarDeclarator>,
649    get: SuperField,
650    set: SuperField,
651    update: SuperField,
652) {
653    decls.extend(update.ident.into_iter().map(|(key, ident)| {
654        let value = private_ident!("v");
655        VarDeclarator {
656            span: DUMMY_SP,
657            name: ident.into(),
658            init: Some(
659                ObjectLit {
660                    span: DUMMY_SP,
661                    props: vec![
662                        Prop::Getter(GetterProp {
663                            span: DUMMY_SP,
664                            key: PropName::Ident("_".into()),
665                            type_ann: None,
666                            body: Some(BlockStmt {
667                                stmts: vec![Expr::Ident(
668                                    get.ident
669                                        .get(&key)
670                                        .cloned()
671                                        .expect("getter not found")
672                                        .without_loc(),
673                                )
674                                .as_call(DUMMY_SP, Default::default())
675                                .into_return_stmt()
676                                .into()],
677                                ..Default::default()
678                            }),
679                        }),
680                        Prop::Setter(SetterProp {
681                            span: DUMMY_SP,
682                            key: PropName::Ident("_".into()),
683                            this_param: None,
684                            param: value.clone().into(),
685                            body: Some(BlockStmt {
686                                stmts: vec![Expr::Ident(
687                                    set.ident
688                                        .get(&key)
689                                        .cloned()
690                                        .expect("setter not found")
691                                        .without_loc(),
692                                )
693                                .as_call(DUMMY_SP, vec![value.as_arg()])
694                                .into_stmt()],
695                                ..Default::default()
696                            }),
697                        }),
698                    ]
699                    .into_iter()
700                    .map(Box::new)
701                    .map(From::from)
702                    .collect(),
703                }
704                .into(),
705            ),
706            definite: false,
707        }
708    }));
709    if let Some(id) = update.computed {
710        let prop = private_ident!("_prop");
711        let value = private_ident!("v");
712
713        decls.push(VarDeclarator {
714            span: DUMMY_SP,
715            name: id.into(),
716            init: Some(
717                ArrowExpr {
718                    span: DUMMY_SP,
719                    params: vec![prop.clone().into()],
720                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
721                        ObjectLit {
722                            span: DUMMY_SP,
723                            props: vec![
724                                Prop::Getter(GetterProp {
725                                    span: DUMMY_SP,
726                                    key: PropName::Ident("_".into()),
727                                    type_ann: None,
728                                    body: Some(BlockStmt {
729                                        stmts: vec![Expr::Ident(
730                                            get.computed
731                                                .clone()
732                                                .expect("getter computed not found")
733                                                .without_loc(),
734                                        )
735                                        .as_call(DUMMY_SP, vec![prop.clone().as_arg()])
736                                        .into_return_stmt()
737                                        .into()],
738                                        ..Default::default()
739                                    }),
740                                }),
741                                Prop::Setter(SetterProp {
742                                    span: DUMMY_SP,
743                                    key: PropName::Ident("_".into()),
744                                    this_param: None,
745                                    param: value.clone().into(),
746                                    body: Some(BlockStmt {
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                                        ..Default::default()
757                                    }),
758                                }),
759                            ]
760                            .into_iter()
761                            .map(Box::new)
762                            .map(From::from)
763                            .collect(),
764                        }
765                        .into(),
766                    ))),
767                    ..Default::default()
768                }
769                .into(),
770            ),
771            definite: false,
772        });
773    }
774    decls.extend(get.ident.into_iter().map(|(key, ident)| {
775        VarDeclarator {
776            span: DUMMY_SP,
777            name: ident.without_loc().into(),
778            init: Some(
779                ArrowExpr {
780                    span: DUMMY_SP,
781                    params: Vec::new(),
782                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
783                        SuperPropExpr {
784                            obj: Super { span: DUMMY_SP },
785                            prop: SuperProp::Ident(key.into()),
786                            span: DUMMY_SP,
787                        }
788                        .into(),
789                    ))),
790                    ..Default::default()
791                }
792                .into(),
793            ),
794            definite: false,
795        }
796    }));
797    if let Some(id) = get.computed {
798        let param = private_ident!("_prop");
799        decls.push(VarDeclarator {
800            span: DUMMY_SP,
801            name: id.without_loc().into(),
802            init: Some(
803                ArrowExpr {
804                    span: DUMMY_SP,
805                    params: vec![param.clone().into()],
806                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
807                        SuperPropExpr {
808                            obj: Super { span: DUMMY_SP },
809                            prop: SuperProp::Computed(ComputedPropName {
810                                span: DUMMY_SP,
811                                expr: Box::new(Expr::Ident(param)),
812                            }),
813                            span: DUMMY_SP,
814                        }
815                        .into(),
816                    ))),
817                    ..Default::default()
818                }
819                .into(),
820            ),
821            definite: false,
822        });
823    }
824    decls.extend(set.ident.into_iter().map(|(key, ident)| {
825        let value = private_ident!("_value");
826        VarDeclarator {
827            span: DUMMY_SP,
828            name: ident.without_loc().into(),
829            init: Some(
830                ArrowExpr {
831                    span: DUMMY_SP,
832                    params: vec![value.clone().into()],
833                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
834                        AssignExpr {
835                            span: DUMMY_SP,
836                            left: SuperPropExpr {
837                                obj: Super { span: DUMMY_SP },
838                                prop: SuperProp::Ident(key.into()),
839                                span: DUMMY_SP,
840                            }
841                            .into(),
842                            op: op!("="),
843                            right: Box::new(Expr::Ident(value)),
844                        }
845                        .into(),
846                    ))),
847                    ..Default::default()
848                }
849                .into(),
850            ),
851            definite: false,
852        }
853    }));
854    if let Some(id) = set.computed {
855        let prop = private_ident!("_prop");
856        let value = private_ident!("_value");
857        decls.push(VarDeclarator {
858            span: DUMMY_SP,
859            name: id.without_loc().into(),
860            init: Some(
861                ArrowExpr {
862                    span: DUMMY_SP,
863                    params: vec![prop.clone().into(), value.clone().into()],
864                    body: Box::new(BlockStmtOrExpr::Expr(Box::new(
865                        AssignExpr {
866                            span: DUMMY_SP,
867                            left: SuperPropExpr {
868                                obj: Super { span: DUMMY_SP },
869                                prop: SuperProp::Computed(ComputedPropName {
870                                    span: DUMMY_SP,
871                                    expr: Box::new(Expr::Ident(prop)),
872                                }),
873                                span: DUMMY_SP,
874                            }
875                            .into(),
876                            op: op!("="),
877                            right: Box::new(Expr::Ident(value)),
878                        }
879                        .into(),
880                    ))),
881                    ..Default::default()
882                }
883                .into(),
884            ),
885            definite: false,
886        });
887    }
888}