Repository: swc-project/swc
File: crates/swc_ecma_transformer/src/es2017/async_to_generator.rs (Rust)

Code before:
            replace_this_in_opt_chain_base(&mut opt.base, this_var);
        }
        // Don't traverse into nested functions/classes/arrows as they have their own `this`
        // context
        Expr::Fn(_) | Expr::Arrow(_) | Expr::Class(_) => {}
        // These don't contain expressions that could have `this`
        Expr::Ident(_)
        | Expr::Lit(_)
        | Expr::PrivateName(_)
        | Expr::JSXMember(_)
        | Expr::JSXNamespacedName(_)
        | Expr::JSXEmpty(_)
        | Expr::JSXElement(_)
        | Expr::JSXFragment(_)
        | Expr::TsTypeAssertion(_)
        | Expr::TsConstAssertion(_)
        | Expr::TsNonNull(_)
        | Expr::TsAs(_)
        | Expr::TsInstantiation(_)
        | Expr::TsSatisfies(_)
        | Expr::MetaProp(_)
        | Expr::Invalid(_) => {}
        #[cfg(swc_ast_unknown)]
        _ => {}
    }
}

fn replace_this_in_member_expr(member: &mut MemberExpr, this_var: &Ident) {
    replace_this_in_expr(&mut member.obj, this_var);
    if let MemberProp::Computed(computed) = &mut member.prop {
        replace_this_in_expr(&mut computed.expr, this_var);
    }
}

fn replace_this_in_opt_chain_base(base: &mut OptChainBase, this_var: &Ident) {
    match base {
        OptChainBase::Member(member) => {
            replace_this_in_expr(&mut member.obj, this_var);
            if let MemberProp::Computed(computed) = &mut member.prop {
                replace_this_in_expr(&mut computed.expr, this_var);
            }
        }
        OptChainBase::Call(call) => {
            replace_this_in_expr(&mut call.callee, this_var);
            for arg in &mut call.args {
                replace_this_in_expr(&mut arg.expr, this_var);
            }
        }
        #[cfg(swc_ast_unknown)]
        _ => {}
    }

Review comment (bug):
Several TypeScript expression types are listed as not containing expressions that could have `this`, but this is incorrect. `Expr::TsTypeAssertion(_)`, `Expr::TsNonNull(_)`, `Expr::TsAs(_)`, `Expr::TsInstantiation(_)`, and `Expr::TsSatisfies(_)` all wrap underlying expressions that may contain `this` references. For example, `(this.value as number)` contains a `this` reference that should be replaced. These TypeScript wrapper expressions should traverse into their wrapped expressions.
```suggestion
        | Expr::TsConstAssertion(_)
        | Expr::MetaProp(_)
        | Expr::Invalid(_) => {}
        // Traverse into TypeScript wrapper expressions
        Expr::TsTypeAssertion(ts_type_assertion) => {
            replace_this_in_expr(&mut ts_type_assertion.expr, this_var);
        }
        Expr::TsNonNull(ts_non_null) => {
            replace_this_in_expr(&mut ts_non_null.expr, this_var);
        }
        Expr::TsAs(ts_as) => {
            replace_this_in_expr(&mut ts_as.expr, this_var);
        }
        Expr::TsInstantiation(ts_instantiation) => {
            replace_this_in_expr(&mut ts_instantiation.expr, this_var);
        }
        Expr::TsSatisfies(ts_satisfies) => {
            replace_this_in_expr(&mut ts_satisfies.expr, this_var);
        }
```

Code after:
        }
        Expr::OptChain(opt) => {
            replace_this_in_opt_chain_base(&mut opt.base, this_var);
        }
        // Don't traverse into nested functions/classes/arrows as they have their own `this`
        // context
        Expr::Fn(_) | Expr::Arrow(_) | Expr::Class(_) => {}
        // These don't contain expressions that could have `this`
        Expr::Ident(_)
        | Expr::Lit(_)
        | Expr::PrivateName(_)
        | Expr::JSXMember(_)
        | Expr::JSXNamespacedName(_)
        | Expr::JSXEmpty(_)
        | Expr::JSXElement(_)
        | Expr::JSXFragment(_)
        | Expr::TsTypeAssertion(_)
        | Expr::TsConstAssertion(_)
        | Expr::TsNonNull(_)
        | Expr::TsAs(_)
        | Expr::TsInstantiation(_)
        | Expr::TsSatisfies(_)
        | Expr::MetaProp(_)
        | Expr::Invalid(_) => {}
        #[cfg(swc_ast_unknown)]
        _ => {}
    }
}

fn replace_this_in_member_expr(member: &mut MemberExpr, this_var: &Ident) {
    replace_this_in_expr(&mut member.obj, this_var);
    if let MemberProp::Computed(computed) = &mut member.prop {
        replace_this_in_expr(&mut computed.expr, this_var);
    }
}

fn replace_this_in_opt_chain_base(base: &mut OptChainBase, this_var: &Ident) {
    match base {
        OptChainBase::Member(member) => {
            replace_this_in_expr(&mut member.obj, this_var);
            if let MemberProp::Computed(computed) = &mut member.prop {
                replace_this_in_expr(&mut computed.expr, this_var);
            }
        }
        OptChainBase::Call(call) => {
            replace_this_in_expr(&mut call.callee, this_var);
            for arg in &mut call.args {
                replace_this_in_expr(&mut arg.expr, this_var);
            }
        }
        #[cfg(swc_ast_unknown)]