swc_ecma_compat_es2017/
async_to_generator.rs

1use std::{mem, vec};
2
3use serde::Deserialize;
4use swc_common::{util::take::Take, Mark, Spanned, SyntaxContext, DUMMY_SP};
5use swc_ecma_ast::*;
6use swc_ecma_transforms_base::{
7    helper, helper_expr,
8    perf::{should_work, Check},
9};
10use swc_ecma_utils::{
11    function::{init_this, FnEnvHoister},
12    prepend_stmt, private_ident, quote_ident, ExprFactory,
13};
14use swc_ecma_visit::{
15    noop_visit_mut_type, noop_visit_type, visit_mut_pass, Visit, VisitMut, VisitMutWith, VisitWith,
16};
17use swc_trace_macro::swc_trace;
18
19/// `@babel/plugin-transform-async-to-generator`
20///
21/// ## In
22///
23/// ```js
24/// async function foo() {
25///   await bar();
26/// }
27/// ```
28///
29/// ## Out
30///
31/// ```js
32/// var _async_to_generator = function (fn) {
33///   ...
34/// };
35/// var foo = _async_to_generator(function* () {
36///   yield bar();
37/// });
38/// ```
39pub fn async_to_generator(c: Config, unresolved_mark: Mark) -> impl Pass {
40    visit_mut_pass(AsyncToGenerator {
41        c,
42        fn_state: None,
43        in_subclass: false,
44        unresolved_ctxt: SyntaxContext::empty().apply_mark(unresolved_mark),
45    })
46}
47
48#[derive(Debug, Clone, Copy, Default, Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub struct Config {
51    #[serde(default)]
52    pub ignore_function_length: bool,
53}
54
55#[derive(Default, Clone, Debug)]
56struct FnState {
57    is_async: bool,
58    is_generator: bool,
59    use_this: bool,
60    use_arguments: bool,
61    use_super: bool,
62}
63
64#[derive(Default, Clone)]
65struct AsyncToGenerator {
66    c: Config,
67
68    fn_state: Option<FnState>,
69
70    in_subclass: bool,
71
72    unresolved_ctxt: SyntaxContext,
73}
74
75#[swc_trace]
76impl VisitMut for AsyncToGenerator {
77    noop_visit_mut_type!(fail);
78
79    fn visit_mut_function(&mut self, function: &mut Function) {
80        let Some(body) = &mut function.body else {
81            return;
82        };
83
84        function.params.visit_mut_with(self);
85
86        let fn_state = self.fn_state.replace(FnState {
87            is_async: function.is_async,
88            is_generator: function.is_generator,
89            ..Default::default()
90        });
91        body.visit_mut_with(self);
92
93        let mut fn_state = mem::replace(&mut self.fn_state, fn_state).unwrap();
94        if !fn_state.is_async {
95            return;
96        }
97
98        let mut stmts = vec![];
99        if fn_state.use_super {
100            // slow path
101            let mut fn_env_hoister = FnEnvHoister::new(self.unresolved_ctxt);
102            fn_env_hoister.disable_this();
103            fn_env_hoister.disable_arguments();
104
105            body.visit_mut_with(&mut fn_env_hoister);
106
107            stmts.extend(fn_env_hoister.to_stmt());
108        }
109
110        function.is_async = false;
111        function.is_generator = false;
112        if !fn_state.use_arguments {
113            // Errors thrown during argument evaluation must reject the resulting promise,
114            // which needs more complex code to handle
115            // https://github.com/evanw/esbuild/blob/75286c1b4fabcf93140b97c3c0488f0253158b47/internal/js_parser/js_parser_lower.go#L364
116            fn_state.use_arguments =
117                could_potentially_throw(&function.params, self.unresolved_ctxt);
118        }
119
120        let params = if fn_state.use_arguments {
121            let mut params = vec![];
122
123            if !self.c.ignore_function_length {
124                let fn_len = function
125                    .params
126                    .iter()
127                    .filter(|p| !matches!(p.pat, Pat::Assign(..) | Pat::Rest(..)))
128                    .count();
129                for i in 0..fn_len {
130                    params.push(Param {
131                        pat: private_ident!(format!("_{}", i)).into(),
132                        span: DUMMY_SP,
133                        decorators: vec![],
134                    });
135                }
136            }
137
138            mem::replace(&mut function.params, params)
139        } else {
140            vec![]
141        };
142
143        let expr = make_fn_ref(&fn_state, params, body.take());
144
145        stmts.push(
146            ReturnStmt {
147                arg: Some(expr.into()),
148                ..Default::default()
149            }
150            .into(),
151        );
152
153        function.body = Some(BlockStmt {
154            stmts,
155            ..Default::default()
156        });
157    }
158
159    fn visit_mut_arrow_expr(&mut self, arrow_expr: &mut ArrowExpr) {
160        if !arrow_expr.is_async {
161            arrow_expr.visit_mut_children_with(self);
162            return;
163        }
164
165        // arrow expressions cannot be generator
166        debug_assert!(!arrow_expr.is_generator);
167
168        arrow_expr.params.visit_mut_with(self);
169
170        let fn_state = self.fn_state.replace(FnState {
171            is_async: true,
172            is_generator: false,
173            ..Default::default()
174        });
175
176        arrow_expr.body.visit_mut_with(self);
177        let fn_state = mem::replace(&mut self.fn_state, fn_state).unwrap();
178
179        // `this`/`arguments`/`super` are inherited from the parent function
180        if let Some(out_fn_state) = &mut self.fn_state {
181            out_fn_state.use_this |= fn_state.use_this;
182            out_fn_state.use_arguments |= fn_state.use_arguments;
183            out_fn_state.use_super |= fn_state.use_super;
184        }
185
186        let mut stmts = vec![];
187        if fn_state.use_super {
188            // slow path
189            let mut fn_env_hoister = FnEnvHoister::new(self.unresolved_ctxt);
190            fn_env_hoister.disable_this();
191            fn_env_hoister.disable_arguments();
192
193            arrow_expr.body.visit_mut_with(&mut fn_env_hoister);
194
195            stmts.extend(fn_env_hoister.to_stmt());
196        }
197
198        arrow_expr.is_async = false;
199
200        let body = match *arrow_expr.body.take() {
201            BlockStmtOrExpr::BlockStmt(block_stmt) => block_stmt,
202            BlockStmtOrExpr::Expr(expr) => BlockStmt {
203                stmts: vec![ReturnStmt {
204                    arg: Some(expr),
205                    ..Default::default()
206                }
207                .into()],
208                ..Default::default()
209            },
210            #[cfg(swc_ast_unknown)]
211            _ => panic!("unable to access unknown nodes"),
212        };
213
214        let expr = make_fn_ref(&fn_state, vec![], body);
215
216        arrow_expr.body = if fn_state.use_super {
217            stmts.push(expr.into_stmt());
218            BlockStmtOrExpr::BlockStmt(BlockStmt {
219                stmts,
220                ..Default::default()
221            })
222        } else {
223            BlockStmtOrExpr::Expr(Box::new(expr))
224        }
225        .into()
226    }
227
228    fn visit_mut_class(&mut self, class: &mut Class) {
229        class.super_class.visit_mut_with(self);
230        let in_subclass = mem::replace(&mut self.in_subclass, class.super_class.is_some());
231        class.body.visit_mut_with(self);
232        self.in_subclass = in_subclass;
233    }
234
235    fn visit_mut_constructor(&mut self, constructor: &mut Constructor) {
236        constructor.params.visit_mut_with(self);
237
238        if let Some(BlockStmt { stmts, .. }) = &mut constructor.body {
239            if !should_work::<ShouldWork, _>(&*stmts) {
240                return;
241            }
242
243            let (decl, this_id) = if self.in_subclass {
244                let mut fn_env_hoister = FnEnvHoister::new(self.unresolved_ctxt);
245                stmts.visit_mut_with(&mut fn_env_hoister);
246                fn_env_hoister.to_stmt_in_subclass()
247            } else {
248                (None, None)
249            };
250
251            stmts.visit_mut_children_with(self);
252
253            if let Some(this_id) = this_id {
254                init_this(stmts, &this_id)
255            }
256
257            if let Some(decl) = decl {
258                prepend_stmt(stmts, decl)
259            }
260        }
261    }
262
263    fn visit_mut_getter_prop(&mut self, f: &mut GetterProp) {
264        let fn_state = self.fn_state.take();
265        f.visit_mut_children_with(self);
266        self.fn_state = fn_state;
267    }
268
269    fn visit_mut_setter_prop(&mut self, f: &mut SetterProp) {
270        f.param.visit_mut_with(self);
271        let fn_state = self.fn_state.take();
272        f.body.visit_mut_with(self);
273        self.fn_state = fn_state;
274    }
275
276    fn visit_mut_exprs(&mut self, exprs: &mut Vec<Box<Expr>>) {
277        if self.fn_state.as_ref().is_some_and(|f| !f.is_async)
278            && !should_work::<ShouldWork, _>(&*exprs)
279        {
280            return;
281        }
282
283        exprs.visit_mut_children_with(self);
284    }
285
286    fn visit_mut_expr(&mut self, expr: &mut Expr) {
287        if self.fn_state.as_ref().is_some_and(|f| !f.is_async)
288            && !should_work::<ShouldWork, _>(&*expr)
289        {
290            return;
291        }
292
293        expr.visit_mut_children_with(self);
294
295        let Some(fn_state @ FnState { is_async: true, .. }) = &mut self.fn_state else {
296            return;
297        };
298
299        match expr {
300            Expr::This(..) => {
301                fn_state.use_this = true;
302            }
303            Expr::Ident(Ident { sym, .. }) if sym == "arguments" => {
304                fn_state.use_arguments = true;
305            }
306            Expr::Await(AwaitExpr { arg, span }) => {
307                *expr = if fn_state.is_generator {
308                    let callee = helper!(await_async_generator);
309                    let arg = CallExpr {
310                        span: *span,
311                        callee,
312                        args: vec![arg.take().as_arg()],
313                        ..Default::default()
314                    }
315                    .into();
316                    YieldExpr {
317                        span: *span,
318                        delegate: false,
319                        arg: Some(arg),
320                    }
321                } else {
322                    YieldExpr {
323                        span: *span,
324                        delegate: false,
325                        arg: Some(arg.take()),
326                    }
327                }
328                .into();
329            }
330            Expr::Yield(YieldExpr {
331                span,
332                arg: Some(arg),
333                delegate: true,
334            }) => {
335                let async_iter =
336                    helper_expr!(async_iterator).as_call(DUMMY_SP, vec![arg.take().as_arg()]);
337
338                let arg = helper_expr!(async_generator_delegate)
339                    .as_call(*span, vec![async_iter.as_arg()])
340                    .into();
341
342                *expr = YieldExpr {
343                    span: *span,
344                    delegate: true,
345                    arg: Some(arg),
346                }
347                .into()
348            }
349
350            _ => {}
351        }
352    }
353
354    fn visit_mut_stmts(&mut self, stmts: &mut Vec<Stmt>) {
355        if self.fn_state.as_ref().is_some_and(|f| !f.is_async)
356            && !should_work::<ShouldWork, _>(&*stmts)
357        {
358            return;
359        }
360
361        stmts.visit_mut_children_with(self);
362    }
363
364    fn visit_mut_stmt(&mut self, stmt: &mut Stmt) {
365        if self.fn_state.as_ref().is_some_and(|f| !f.is_async)
366            && !should_work::<ShouldWork, _>(&*stmt)
367        {
368            return;
369        }
370
371        stmt.visit_mut_children_with(self);
372
373        if let Some(FnState {
374            is_async: true,
375            is_generator,
376            ..
377        }) = self.fn_state
378        {
379            handle_await_for(stmt, is_generator);
380        }
381    }
382
383    fn visit_mut_super(&mut self, _: &mut Super) {
384        if let Some(FnState { use_super, .. }) = &mut self.fn_state {
385            *use_super = true;
386        }
387    }
388}
389
390/// Creates
391///
392/// `_async_to_generator(function*() {})()` from `async function() {}`;
393#[tracing::instrument(level = "debug", skip_all)]
394fn make_fn_ref(fn_state: &FnState, params: Vec<Param>, body: BlockStmt) -> Expr {
395    let helper = if fn_state.is_generator {
396        helper_expr!(DUMMY_SP, wrap_async_generator)
397    } else {
398        helper_expr!(DUMMY_SP, async_to_generator)
399    }
400    .as_callee();
401    let this = ThisExpr { span: DUMMY_SP };
402    let arguments = quote_ident!("arguments");
403
404    let inner_fn = Function {
405        is_generator: true,
406        params,
407        body: Some(body),
408        ..Default::default()
409    };
410
411    let call_async = CallExpr {
412        callee: helper,
413        args: vec![inner_fn.as_arg()],
414        ..Default::default()
415    };
416
417    if fn_state.use_arguments {
418        // fn.apply(this, arguments)
419        call_async
420            .make_member(quote_ident!("apply"))
421            .as_call(DUMMY_SP, vec![this.as_arg(), arguments.as_arg()])
422    } else if fn_state.use_this {
423        // fn.call(this)
424        call_async
425            .make_member(quote_ident!("call"))
426            .as_call(DUMMY_SP, vec![this.as_arg()])
427    } else {
428        // fn()
429        call_async.as_call(DUMMY_SP, vec![])
430    }
431}
432
433#[tracing::instrument(level = "debug", skip_all)]
434fn could_potentially_throw(param: &[Param], unresolved_ctxt: SyntaxContext) -> bool {
435    for param in param {
436        debug_assert!(param.decorators.is_empty());
437
438        match &param.pat {
439            Pat::Ident(..) => continue,
440            Pat::Rest(RestPat { arg, .. }) if arg.is_ident() => continue,
441            Pat::Assign(assign_pat) => match &*assign_pat.right {
442                Expr::Ident(Ident { ctxt, sym, .. })
443                    if sym == "undefined" && *ctxt == unresolved_ctxt =>
444                {
445                    continue
446                }
447                Expr::Lit(
448                    Lit::Null(..) | Lit::Bool(..) | Lit::Num(..) | Lit::BigInt(..) | Lit::Str(..),
449                )
450                | Expr::Fn(..)
451                | Expr::Arrow(..) => continue,
452
453                _ => return true,
454            },
455            _ => return true,
456        }
457    }
458
459    false
460}
461
462#[derive(Default)]
463struct ShouldWork {
464    found: bool,
465}
466
467#[swc_trace]
468impl Visit for ShouldWork {
469    noop_visit_type!(fail);
470
471    fn visit_function(&mut self, f: &Function) {
472        if f.is_async {
473            self.found = true;
474            return;
475        }
476        f.visit_children_with(self);
477    }
478
479    fn visit_arrow_expr(&mut self, f: &ArrowExpr) {
480        if f.is_async {
481            self.found = true;
482            return;
483        }
484        f.visit_children_with(self);
485    }
486}
487
488impl Check for ShouldWork {
489    fn should_handle(&self) -> bool {
490        self.found
491    }
492}
493
494#[tracing::instrument(level = "debug", skip_all)]
495fn handle_await_for(stmt: &mut Stmt, is_async_generator: bool) {
496    let s = match stmt {
497        Stmt::ForOf(s @ ForOfStmt { is_await: true, .. }) => s.take(),
498        _ => return,
499    };
500
501    let value = private_ident!("_value");
502    let iterator = private_ident!("_iterator");
503    let iterator_error = private_ident!("_iteratorError");
504    let step = private_ident!("_step");
505    let did_iteration_error = private_ident!("_didIteratorError");
506    let iterator_abrupt_completion = private_ident!("_iteratorAbruptCompletion");
507    let err_param = private_ident!("err");
508
509    let try_body = {
510        let body_span = s.body.span();
511        let orig_body = match *s.body {
512            Stmt::Block(s) => s.stmts,
513            _ => vec![*s.body],
514        };
515
516        let mut for_loop_body = Vec::new();
517        {
518            // let value = _step.value;
519            let value_var = VarDeclarator {
520                span: DUMMY_SP,
521                name: value.clone().into(),
522                init: Some(step.clone().make_member(quote_ident!("value")).into()),
523                definite: false,
524            };
525            for_loop_body.push(
526                VarDecl {
527                    span: DUMMY_SP,
528                    kind: VarDeclKind::Let,
529                    declare: false,
530                    decls: vec![value_var],
531                    ..Default::default()
532                }
533                .into(),
534            );
535        }
536
537        match s.left {
538            ForHead::VarDecl(v) => {
539                let var = v.decls.into_iter().next().unwrap();
540                let var_decl = VarDeclarator {
541                    span: DUMMY_SP,
542                    name: var.name,
543                    init: Some(value.into()),
544                    definite: false,
545                };
546                for_loop_body.push(
547                    VarDecl {
548                        span: DUMMY_SP,
549                        kind: VarDeclKind::Const,
550                        declare: false,
551                        decls: vec![var_decl],
552                        ..Default::default()
553                    }
554                    .into(),
555                );
556            }
557            ForHead::Pat(p) => {
558                for_loop_body.push(
559                    ExprStmt {
560                        span: DUMMY_SP,
561                        expr: AssignExpr {
562                            span: DUMMY_SP,
563                            op: op!("="),
564                            left: p.try_into().unwrap(),
565                            right: Box::new(value.into()),
566                        }
567                        .into(),
568                    }
569                    .into(),
570                );
571            }
572
573            ForHead::UsingDecl(..) => {
574                unreachable!("using declaration must be removed by previous pass")
575            }
576
577            #[cfg(swc_ast_unknown)]
578            _ => panic!("unable to access unknown nodes"),
579        }
580
581        for_loop_body.extend(orig_body);
582
583        let for_loop_body = BlockStmt {
584            span: body_span,
585            stmts: for_loop_body,
586            ..Default::default()
587        };
588
589        let mut init_var_decls = Vec::new();
590        // _iterator = _async_iterator(lol())
591        init_var_decls.push(VarDeclarator {
592            span: DUMMY_SP,
593            name: iterator.clone().into(),
594            init: {
595                let callee = helper!(async_iterator);
596
597                Some(
598                    CallExpr {
599                        span: DUMMY_SP,
600                        callee,
601                        args: vec![s.right.as_arg()],
602                        ..Default::default()
603                    }
604                    .into(),
605                )
606            },
607            definite: false,
608        });
609        init_var_decls.push(VarDeclarator {
610            span: DUMMY_SP,
611            name: step.clone().into(),
612            init: None,
613            definite: false,
614        });
615
616        let for_stmt = ForStmt {
617            span: s.span,
618            // var _iterator = _async_iterator(lol()), _step;
619            init: Some(
620                VarDecl {
621                    span: DUMMY_SP,
622                    kind: VarDeclKind::Var,
623                    declare: false,
624                    decls: init_var_decls,
625                    ..Default::default()
626                }
627                .into(),
628            ),
629            // _iteratorAbruptCompletion = !(_step = yield _iterator.next()).done
630            test: {
631                let iter_next = iterator.clone().make_member(quote_ident!("next"));
632                let iter_next = CallExpr {
633                    span: DUMMY_SP,
634                    callee: iter_next.as_callee(),
635                    args: Default::default(),
636                    ..Default::default()
637                };
638
639                let yield_arg = if is_async_generator {
640                    CallExpr {
641                        span: DUMMY_SP,
642                        callee: helper!(await_async_generator),
643                        args: vec![iter_next.as_arg()],
644                        ..Default::default()
645                    }
646                    .into()
647                } else {
648                    iter_next.into()
649                };
650
651                let assign_to_step: Expr = AssignExpr {
652                    span: DUMMY_SP,
653                    op: op!("="),
654                    left: step.into(),
655                    right: YieldExpr {
656                        span: DUMMY_SP,
657                        arg: Some(yield_arg),
658                        delegate: false,
659                    }
660                    .into(),
661                }
662                .into();
663
664                let right = UnaryExpr {
665                    span: DUMMY_SP,
666                    op: op!("!"),
667                    arg: assign_to_step.make_member(quote_ident!("done")).into(),
668                }
669                .into();
670
671                let left = iterator_abrupt_completion.clone().into();
672
673                Some(
674                    AssignExpr {
675                        span: DUMMY_SP,
676                        op: op!("="),
677                        left,
678                        right,
679                    }
680                    .into(),
681                )
682            },
683            // _iteratorNormalCompletion = true
684            update: Some(
685                AssignExpr {
686                    span: DUMMY_SP,
687                    op: op!("="),
688                    left: iterator_abrupt_completion.clone().into(),
689                    right: false.into(),
690                }
691                .into(),
692            ),
693            body: Box::new(Stmt::Block(for_loop_body)),
694        }
695        .into();
696
697        BlockStmt {
698            span: body_span,
699            stmts: vec![for_stmt],
700            ..Default::default()
701        }
702    };
703
704    let catch_clause = {
705        // _didIteratorError = true;
706        let mark_as_errorred = ExprStmt {
707            span: DUMMY_SP,
708            expr: AssignExpr {
709                span: DUMMY_SP,
710                op: op!("="),
711                left: did_iteration_error.clone().into(),
712                right: true.into(),
713            }
714            .into(),
715        }
716        .into();
717        // _iteratorError = err;
718        let store_error = ExprStmt {
719            span: DUMMY_SP,
720            expr: AssignExpr {
721                span: DUMMY_SP,
722                op: op!("="),
723                left: iterator_error.clone().into(),
724                right: Box::new(err_param.clone().into()),
725            }
726            .into(),
727        }
728        .into();
729
730        CatchClause {
731            span: DUMMY_SP,
732            param: Some(err_param.into()),
733            body: BlockStmt {
734                stmts: vec![mark_as_errorred, store_error],
735                ..Default::default()
736            },
737        }
738    };
739
740    let finally_block = {
741        let throw_iterator_error = ThrowStmt {
742            span: DUMMY_SP,
743            arg: iterator_error.clone().into(),
744        }
745        .into();
746        let throw_iterator_error = IfStmt {
747            span: DUMMY_SP,
748            test: did_iteration_error.clone().into(),
749            cons: Box::new(Stmt::Block(BlockStmt {
750                span: DUMMY_SP,
751                stmts: vec![throw_iterator_error],
752                ..Default::default()
753            })),
754            alt: None,
755        }
756        .into();
757
758        let iterator_return: Expr = CallExpr {
759            span: DUMMY_SP,
760            callee: iterator
761                .clone()
762                .make_member(quote_ident!("return"))
763                .as_callee(),
764            args: Vec::new(),
765            ..Default::default()
766        }
767        .into();
768
769        // yield _iterator.return();
770        // or
771        // yield _awaitAsyncGenerator(_iterator.return());
772        let yield_stmt = ExprStmt {
773            span: DUMMY_SP,
774            expr: YieldExpr {
775                span: DUMMY_SP,
776                delegate: false,
777                arg: Some(if is_async_generator {
778                    CallExpr {
779                        span: DUMMY_SP,
780                        callee: helper!(await_async_generator),
781                        args: vec![iterator_return.as_arg()],
782                        ..Default::default()
783                    }
784                    .into()
785                } else {
786                    iterator_return.into()
787                }),
788            }
789            .into(),
790        }
791        .into();
792
793        let conditional_yield = IfStmt {
794            span: DUMMY_SP,
795            // _iteratorAbruptCompletion && _iterator.return != null
796            test: BinExpr {
797                span: DUMMY_SP,
798                op: op!("&&"),
799                // _iteratorAbruptCompletion
800                left: Box::new(iterator_abrupt_completion.clone().into()),
801                // _iterator.return != null
802                right: Box::new(
803                    BinExpr {
804                        span: DUMMY_SP,
805                        op: op!("!="),
806                        left: iterator.make_member(quote_ident!("return")).into(),
807                        right: Null { span: DUMMY_SP }.into(),
808                    }
809                    .into(),
810                ),
811            }
812            .into(),
813            cons: Box::new(Stmt::Block(BlockStmt {
814                stmts: vec![yield_stmt],
815                ..Default::default()
816            })),
817            alt: None,
818        }
819        .into();
820        let body = BlockStmt {
821            stmts: vec![conditional_yield],
822            ..Default::default()
823        };
824
825        let inner_try = TryStmt {
826            span: DUMMY_SP,
827            block: body,
828            handler: None,
829            finalizer: Some(BlockStmt {
830                stmts: vec![throw_iterator_error],
831                ..Default::default()
832            }),
833        }
834        .into();
835        BlockStmt {
836            stmts: vec![inner_try],
837            ..Default::default()
838        }
839    };
840
841    let try_stmt = TryStmt {
842        span: s.span,
843        block: try_body,
844        handler: Some(catch_clause),
845        finalizer: Some(finally_block),
846    };
847
848    let stmts = vec![
849        VarDecl {
850            kind: VarDeclKind::Var,
851            decls: vec![
852                // var _iteratorAbruptCompletion = false;
853                VarDeclarator {
854                    span: DUMMY_SP,
855                    name: iterator_abrupt_completion.into(),
856                    init: Some(false.into()),
857                    definite: false,
858                },
859                // var _didIteratorError = false;
860                VarDeclarator {
861                    span: DUMMY_SP,
862                    name: did_iteration_error.into(),
863                    init: Some(false.into()),
864                    definite: false,
865                },
866                // var _iteratorError;
867                VarDeclarator {
868                    span: DUMMY_SP,
869                    name: iterator_error.into(),
870                    init: None,
871                    definite: false,
872                },
873            ],
874            ..Default::default()
875        }
876        .into(),
877        try_stmt.into(),
878    ];
879
880    *stmt = BlockStmt {
881        span: s.span,
882        stmts,
883        ..Default::default()
884    }
885    .into()
886}