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 should_handle_super =
187            fn_state.use_super && self.fn_state.as_ref().is_some_and(|s| !s.is_async);
188
189        let mut stmts = vec![];
190        if should_handle_super {
191            // slow path
192            let mut fn_env_hoister = FnEnvHoister::new(self.unresolved_ctxt);
193            fn_env_hoister.disable_this();
194            fn_env_hoister.disable_arguments();
195
196            arrow_expr.body.visit_mut_with(&mut fn_env_hoister);
197
198            stmts.extend(fn_env_hoister.to_stmt());
199        }
200
201        arrow_expr.is_async = false;
202
203        let body = match *arrow_expr.body.take() {
204            BlockStmtOrExpr::BlockStmt(block_stmt) => block_stmt,
205            BlockStmtOrExpr::Expr(expr) => BlockStmt {
206                stmts: vec![ReturnStmt {
207                    arg: Some(expr),
208                    ..Default::default()
209                }
210                .into()],
211                ..Default::default()
212            },
213        };
214
215        let expr = make_fn_ref(&fn_state, vec![], body);
216
217        arrow_expr.body = if should_handle_super {
218            stmts.push(expr.into_stmt());
219            BlockStmtOrExpr::BlockStmt(BlockStmt {
220                stmts,
221                ..Default::default()
222            })
223        } else {
224            BlockStmtOrExpr::Expr(Box::new(expr))
225        }
226        .into()
227    }
228
229    fn visit_mut_class(&mut self, class: &mut Class) {
230        class.super_class.visit_mut_with(self);
231        let in_subclass = mem::replace(&mut self.in_subclass, class.super_class.is_some());
232        class.body.visit_mut_with(self);
233        self.in_subclass = in_subclass;
234    }
235
236    fn visit_mut_constructor(&mut self, constructor: &mut Constructor) {
237        constructor.params.visit_mut_with(self);
238
239        if let Some(BlockStmt { stmts, .. }) = &mut constructor.body {
240            if !should_work::<ShouldWork, _>(&*stmts) {
241                return;
242            }
243
244            let (decl, this_id) = if self.in_subclass {
245                let mut fn_env_hoister = FnEnvHoister::new(self.unresolved_ctxt);
246                stmts.visit_mut_with(&mut fn_env_hoister);
247                fn_env_hoister.to_stmt_in_subclass()
248            } else {
249                (None, None)
250            };
251
252            stmts.visit_mut_children_with(self);
253
254            if let Some(this_id) = this_id {
255                init_this(stmts, &this_id)
256            }
257
258            if let Some(decl) = decl {
259                prepend_stmt(stmts, decl)
260            }
261        }
262    }
263
264    fn visit_mut_getter_prop(&mut self, f: &mut GetterProp) {
265        let fn_state = self.fn_state.take();
266        f.visit_mut_children_with(self);
267        self.fn_state = fn_state;
268    }
269
270    fn visit_mut_setter_prop(&mut self, f: &mut SetterProp) {
271        f.param.visit_mut_with(self);
272        let fn_state = self.fn_state.take();
273        f.body.visit_mut_with(self);
274        self.fn_state = fn_state;
275    }
276
277    fn visit_mut_exprs(&mut self, exprs: &mut Vec<Box<Expr>>) {
278        if self.fn_state.as_ref().is_some_and(|f| !f.is_async)
279            && !should_work::<ShouldWork, _>(&*exprs)
280        {
281            return;
282        }
283
284        exprs.visit_mut_children_with(self);
285    }
286
287    fn visit_mut_expr(&mut self, expr: &mut Expr) {
288        if self.fn_state.as_ref().is_some_and(|f| !f.is_async)
289            && !should_work::<ShouldWork, _>(&*expr)
290        {
291            return;
292        }
293
294        expr.visit_mut_children_with(self);
295
296        let Some(fn_state @ FnState { is_async: true, .. }) = &mut self.fn_state else {
297            return;
298        };
299
300        match expr {
301            Expr::This(..) => {
302                fn_state.use_this = true;
303            }
304            Expr::Ident(Ident { sym, .. }) if sym == "arguments" => {
305                fn_state.use_arguments = true;
306            }
307            Expr::Await(AwaitExpr { arg, span }) => {
308                *expr = if fn_state.is_generator {
309                    let callee = helper!(await_async_generator);
310                    let arg = CallExpr {
311                        span: *span,
312                        callee,
313                        args: vec![arg.take().as_arg()],
314                        ..Default::default()
315                    }
316                    .into();
317                    YieldExpr {
318                        span: *span,
319                        delegate: false,
320                        arg: Some(arg),
321                    }
322                } else {
323                    YieldExpr {
324                        span: *span,
325                        delegate: false,
326                        arg: Some(arg.take()),
327                    }
328                }
329                .into();
330            }
331            Expr::Yield(YieldExpr {
332                span,
333                arg: Some(arg),
334                delegate: true,
335            }) => {
336                let async_iter =
337                    helper_expr!(async_iterator).as_call(DUMMY_SP, vec![arg.take().as_arg()]);
338
339                let arg = helper_expr!(async_generator_delegate)
340                    .as_call(*span, vec![async_iter.as_arg()])
341                    .into();
342
343                *expr = YieldExpr {
344                    span: *span,
345                    delegate: true,
346                    arg: Some(arg),
347                }
348                .into()
349            }
350
351            _ => {}
352        }
353    }
354
355    fn visit_mut_stmts(&mut self, stmts: &mut Vec<Stmt>) {
356        if self.fn_state.as_ref().is_some_and(|f| !f.is_async)
357            && !should_work::<ShouldWork, _>(&*stmts)
358        {
359            return;
360        }
361
362        stmts.visit_mut_children_with(self);
363    }
364
365    fn visit_mut_stmt(&mut self, stmt: &mut Stmt) {
366        if self.fn_state.as_ref().is_some_and(|f| !f.is_async)
367            && !should_work::<ShouldWork, _>(&*stmt)
368        {
369            return;
370        }
371
372        stmt.visit_mut_children_with(self);
373
374        if let Some(FnState {
375            is_async: true,
376            is_generator,
377            ..
378        }) = self.fn_state
379        {
380            handle_await_for(stmt, is_generator);
381        }
382    }
383
384    fn visit_mut_super(&mut self, _: &mut Super) {
385        if let Some(FnState { use_super, .. }) = &mut self.fn_state {
386            *use_super = true;
387        }
388    }
389}
390
391/// Creates
392///
393/// `_async_to_generator(function*() {})()` from `async function() {}`;
394#[tracing::instrument(level = "debug", skip_all)]
395fn make_fn_ref(fn_state: &FnState, params: Vec<Param>, body: BlockStmt) -> Expr {
396    let helper = if fn_state.is_generator {
397        helper_expr!(DUMMY_SP, wrap_async_generator)
398    } else {
399        helper_expr!(DUMMY_SP, async_to_generator)
400    }
401    .as_callee();
402    let this = ThisExpr { span: DUMMY_SP };
403    let arguments = quote_ident!("arguments");
404
405    let inner_fn = Function {
406        is_generator: true,
407        params,
408        body: Some(body),
409        ..Default::default()
410    };
411
412    let call_async = CallExpr {
413        callee: helper,
414        args: vec![inner_fn.as_arg()],
415        ..Default::default()
416    };
417
418    if fn_state.use_arguments {
419        // fn.apply(this, arguments)
420        call_async
421            .make_member(quote_ident!("apply"))
422            .as_call(DUMMY_SP, vec![this.as_arg(), arguments.as_arg()])
423    } else if fn_state.use_this {
424        // fn.call(this)
425        call_async
426            .make_member(quote_ident!("call"))
427            .as_call(DUMMY_SP, vec![this.as_arg()])
428    } else {
429        // fn()
430        call_async.as_call(DUMMY_SP, vec![])
431    }
432}
433
434#[tracing::instrument(level = "debug", skip_all)]
435fn could_potentially_throw(param: &[Param], unresolved_ctxt: SyntaxContext) -> bool {
436    for param in param {
437        debug_assert!(param.decorators.is_empty());
438
439        match &param.pat {
440            Pat::Ident(..) => continue,
441            Pat::Rest(RestPat { arg, .. }) if arg.is_ident() => continue,
442            Pat::Assign(assign_pat) => match &*assign_pat.right {
443                Expr::Ident(Ident { ctxt, sym, .. })
444                    if sym == "undefined" && *ctxt == unresolved_ctxt =>
445                {
446                    continue
447                }
448                Expr::Lit(
449                    Lit::Null(..) | Lit::Bool(..) | Lit::Num(..) | Lit::BigInt(..) | Lit::Str(..),
450                )
451                | Expr::Fn(..)
452                | Expr::Arrow(..) => continue,
453
454                _ => return true,
455            },
456            _ => return true,
457        }
458    }
459
460    false
461}
462
463#[derive(Default)]
464struct ShouldWork {
465    found: bool,
466}
467
468#[swc_trace]
469impl Visit for ShouldWork {
470    noop_visit_type!(fail);
471
472    fn visit_function(&mut self, f: &Function) {
473        if f.is_async {
474            self.found = true;
475            return;
476        }
477        f.visit_children_with(self);
478    }
479
480    fn visit_arrow_expr(&mut self, f: &ArrowExpr) {
481        if f.is_async {
482            self.found = true;
483            return;
484        }
485        f.visit_children_with(self);
486    }
487}
488
489impl Check for ShouldWork {
490    fn should_handle(&self) -> bool {
491        self.found
492    }
493}
494
495#[tracing::instrument(level = "debug", skip_all)]
496fn handle_await_for(stmt: &mut Stmt, is_async_generator: bool) {
497    let s = match stmt {
498        Stmt::ForOf(s @ ForOfStmt { is_await: true, .. }) => s.take(),
499        _ => return,
500    };
501
502    let value = private_ident!("_value");
503    let iterator = private_ident!("_iterator");
504    let iterator_error = private_ident!("_iteratorError");
505    let step = private_ident!("_step");
506    let did_iteration_error = private_ident!("_didIteratorError");
507    let iterator_abrupt_completion = private_ident!("_iteratorAbruptCompletion");
508    let err_param = private_ident!("err");
509
510    let try_body = {
511        let body_span = s.body.span();
512        let orig_body = match *s.body {
513            Stmt::Block(s) => s.stmts,
514            _ => vec![*s.body],
515        };
516
517        let mut for_loop_body = Vec::new();
518        {
519            // let value = _step.value;
520            let value_var = VarDeclarator {
521                span: DUMMY_SP,
522                name: value.clone().into(),
523                init: Some(step.clone().make_member(quote_ident!("value")).into()),
524                definite: false,
525            };
526            for_loop_body.push(
527                VarDecl {
528                    span: DUMMY_SP,
529                    kind: VarDeclKind::Let,
530                    declare: false,
531                    decls: vec![value_var],
532                    ..Default::default()
533                }
534                .into(),
535            );
536        }
537
538        match s.left {
539            ForHead::VarDecl(v) => {
540                let var = v.decls.into_iter().next().unwrap();
541                let var_decl = VarDeclarator {
542                    span: DUMMY_SP,
543                    name: var.name,
544                    init: Some(value.into()),
545                    definite: false,
546                };
547                for_loop_body.push(
548                    VarDecl {
549                        span: DUMMY_SP,
550                        kind: VarDeclKind::Const,
551                        declare: false,
552                        decls: vec![var_decl],
553                        ..Default::default()
554                    }
555                    .into(),
556                );
557            }
558            ForHead::Pat(p) => {
559                for_loop_body.push(
560                    ExprStmt {
561                        span: DUMMY_SP,
562                        expr: AssignExpr {
563                            span: DUMMY_SP,
564                            op: op!("="),
565                            left: p.try_into().unwrap(),
566                            right: Box::new(value.into()),
567                        }
568                        .into(),
569                    }
570                    .into(),
571                );
572            }
573
574            ForHead::UsingDecl(..) => {
575                unreachable!("using declaration must be removed by previous pass")
576            }
577        }
578
579        for_loop_body.extend(orig_body);
580
581        let for_loop_body = BlockStmt {
582            span: body_span,
583            stmts: for_loop_body,
584            ..Default::default()
585        };
586
587        let mut init_var_decls = Vec::new();
588        // _iterator = _async_iterator(lol())
589        init_var_decls.push(VarDeclarator {
590            span: DUMMY_SP,
591            name: iterator.clone().into(),
592            init: {
593                let callee = helper!(async_iterator);
594
595                Some(
596                    CallExpr {
597                        span: DUMMY_SP,
598                        callee,
599                        args: vec![s.right.as_arg()],
600                        ..Default::default()
601                    }
602                    .into(),
603                )
604            },
605            definite: false,
606        });
607        init_var_decls.push(VarDeclarator {
608            span: DUMMY_SP,
609            name: step.clone().into(),
610            init: None,
611            definite: false,
612        });
613
614        let for_stmt = ForStmt {
615            span: s.span,
616            // var _iterator = _async_iterator(lol()), _step;
617            init: Some(
618                VarDecl {
619                    span: DUMMY_SP,
620                    kind: VarDeclKind::Var,
621                    declare: false,
622                    decls: init_var_decls,
623                    ..Default::default()
624                }
625                .into(),
626            ),
627            // _iteratorAbruptCompletion = !(_step = yield _iterator.next()).done
628            test: {
629                let iter_next = iterator.clone().make_member(quote_ident!("next"));
630                let iter_next = CallExpr {
631                    span: DUMMY_SP,
632                    callee: iter_next.as_callee(),
633                    args: Default::default(),
634                    ..Default::default()
635                };
636
637                let yield_arg = if is_async_generator {
638                    CallExpr {
639                        span: DUMMY_SP,
640                        callee: helper!(await_async_generator),
641                        args: vec![iter_next.as_arg()],
642                        ..Default::default()
643                    }
644                    .into()
645                } else {
646                    iter_next.into()
647                };
648
649                let assign_to_step: Expr = AssignExpr {
650                    span: DUMMY_SP,
651                    op: op!("="),
652                    left: step.into(),
653                    right: YieldExpr {
654                        span: DUMMY_SP,
655                        arg: Some(yield_arg),
656                        delegate: false,
657                    }
658                    .into(),
659                }
660                .into();
661
662                let right = UnaryExpr {
663                    span: DUMMY_SP,
664                    op: op!("!"),
665                    arg: assign_to_step.make_member(quote_ident!("done")).into(),
666                }
667                .into();
668
669                let left = iterator_abrupt_completion.clone().into();
670
671                Some(
672                    AssignExpr {
673                        span: DUMMY_SP,
674                        op: op!("="),
675                        left,
676                        right,
677                    }
678                    .into(),
679                )
680            },
681            // _iteratorNormalCompletion = true
682            update: Some(
683                AssignExpr {
684                    span: DUMMY_SP,
685                    op: op!("="),
686                    left: iterator_abrupt_completion.clone().into(),
687                    right: false.into(),
688                }
689                .into(),
690            ),
691            body: Box::new(Stmt::Block(for_loop_body)),
692        }
693        .into();
694
695        BlockStmt {
696            span: body_span,
697            stmts: vec![for_stmt],
698            ..Default::default()
699        }
700    };
701
702    let catch_clause = {
703        // _didIteratorError = true;
704        let mark_as_errorred = ExprStmt {
705            span: DUMMY_SP,
706            expr: AssignExpr {
707                span: DUMMY_SP,
708                op: op!("="),
709                left: did_iteration_error.clone().into(),
710                right: true.into(),
711            }
712            .into(),
713        }
714        .into();
715        // _iteratorError = err;
716        let store_error = ExprStmt {
717            span: DUMMY_SP,
718            expr: AssignExpr {
719                span: DUMMY_SP,
720                op: op!("="),
721                left: iterator_error.clone().into(),
722                right: Box::new(err_param.clone().into()),
723            }
724            .into(),
725        }
726        .into();
727
728        CatchClause {
729            span: DUMMY_SP,
730            param: Some(err_param.into()),
731            body: BlockStmt {
732                stmts: vec![mark_as_errorred, store_error],
733                ..Default::default()
734            },
735        }
736    };
737
738    let finally_block = {
739        let throw_iterator_error = ThrowStmt {
740            span: DUMMY_SP,
741            arg: iterator_error.clone().into(),
742        }
743        .into();
744        let throw_iterator_error = IfStmt {
745            span: DUMMY_SP,
746            test: did_iteration_error.clone().into(),
747            cons: Box::new(Stmt::Block(BlockStmt {
748                span: DUMMY_SP,
749                stmts: vec![throw_iterator_error],
750                ..Default::default()
751            })),
752            alt: None,
753        }
754        .into();
755
756        let iterator_return: Expr = CallExpr {
757            span: DUMMY_SP,
758            callee: iterator
759                .clone()
760                .make_member(quote_ident!("return"))
761                .as_callee(),
762            args: Vec::new(),
763            ..Default::default()
764        }
765        .into();
766
767        // yield _iterator.return();
768        // or
769        // yield _awaitAsyncGenerator(_iterator.return());
770        let yield_stmt = ExprStmt {
771            span: DUMMY_SP,
772            expr: YieldExpr {
773                span: DUMMY_SP,
774                delegate: false,
775                arg: Some(if is_async_generator {
776                    CallExpr {
777                        span: DUMMY_SP,
778                        callee: helper!(await_async_generator),
779                        args: vec![iterator_return.as_arg()],
780                        ..Default::default()
781                    }
782                    .into()
783                } else {
784                    iterator_return.into()
785                }),
786            }
787            .into(),
788        }
789        .into();
790
791        let conditional_yield = IfStmt {
792            span: DUMMY_SP,
793            // _iteratorAbruptCompletion && _iterator.return != null
794            test: BinExpr {
795                span: DUMMY_SP,
796                op: op!("&&"),
797                // _iteratorAbruptCompletion
798                left: Box::new(iterator_abrupt_completion.clone().into()),
799                // _iterator.return != null
800                right: Box::new(
801                    BinExpr {
802                        span: DUMMY_SP,
803                        op: op!("!="),
804                        left: iterator.make_member(quote_ident!("return")).into(),
805                        right: Null { span: DUMMY_SP }.into(),
806                    }
807                    .into(),
808                ),
809            }
810            .into(),
811            cons: Box::new(Stmt::Block(BlockStmt {
812                stmts: vec![yield_stmt],
813                ..Default::default()
814            })),
815            alt: None,
816        }
817        .into();
818        let body = BlockStmt {
819            stmts: vec![conditional_yield],
820            ..Default::default()
821        };
822
823        let inner_try = TryStmt {
824            span: DUMMY_SP,
825            block: body,
826            handler: None,
827            finalizer: Some(BlockStmt {
828                stmts: vec![throw_iterator_error],
829                ..Default::default()
830            }),
831        }
832        .into();
833        BlockStmt {
834            stmts: vec![inner_try],
835            ..Default::default()
836        }
837    };
838
839    let try_stmt = TryStmt {
840        span: s.span,
841        block: try_body,
842        handler: Some(catch_clause),
843        finalizer: Some(finally_block),
844    };
845
846    let stmts = vec![
847        VarDecl {
848            kind: VarDeclKind::Var,
849            decls: vec![
850                // var _iteratorAbruptCompletion = false;
851                VarDeclarator {
852                    span: DUMMY_SP,
853                    name: iterator_abrupt_completion.into(),
854                    init: Some(false.into()),
855                    definite: false,
856                },
857                // var _didIteratorError = false;
858                VarDeclarator {
859                    span: DUMMY_SP,
860                    name: did_iteration_error.into(),
861                    init: Some(false.into()),
862                    definite: false,
863                },
864                // var _iteratorError;
865                VarDeclarator {
866                    span: DUMMY_SP,
867                    name: iterator_error.into(),
868                    init: None,
869                    definite: false,
870                },
871            ],
872            ..Default::default()
873        }
874        .into(),
875        try_stmt.into(),
876    ];
877
878    *stmt = BlockStmt {
879        span: s.span,
880        stmts,
881        ..Default::default()
882    }
883    .into()
884}