mirror of
https://github.com/swc-project/swc.git
synced 2024-12-25 22:56:11 +03:00
fix(es/compat): Init this in sub class constructor for async (#9446)
**Related issue:** - Closes https://github.com/swc-project/swc/issues/8452 - Closes https://github.com/swc-project/swc/issues/9432
This commit is contained in:
parent
08dd948289
commit
bfaf31bc4b
7
.changeset/grumpy-cars-move.md
Normal file
7
.changeset/grumpy-cars-move.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
swc_core: patch
|
||||
swc_ecma_compat_es2017: patch
|
||||
swc_ecma_compat_es2015: patch
|
||||
---
|
||||
|
||||
fix(es/compat): Init this in sub class constructor for async
|
@ -5,8 +5,8 @@ import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
|
||||
export var CompanyBgStore = function CompanyBgStore() {
|
||||
"use strict";
|
||||
_class_call_check(this, CompanyBgStore);
|
||||
_define_property(this, "corpName", 123);
|
||||
var _this = this;
|
||||
_define_property(this, "corpName", 123);
|
||||
_define_property(this, "getBusinessInfo", _async_to_generator(function() {
|
||||
var corpName;
|
||||
var _arguments = arguments;
|
||||
|
@ -13,10 +13,9 @@ var A = function A() {
|
||||
];
|
||||
});
|
||||
});
|
||||
var _this1 = this;
|
||||
this.bar = /*#__PURE__*/ _async_to_generator._(function() {
|
||||
return _ts_generator._(this, function(_state) {
|
||||
_this1.x();
|
||||
_this.x();
|
||||
return [
|
||||
2
|
||||
];
|
||||
|
@ -5,9 +5,8 @@ class A {
|
||||
this.foo = /*#__PURE__*/ _async_to_generator._(function*() {
|
||||
_this.x();
|
||||
});
|
||||
var _this1 = this;
|
||||
this.bar = /*#__PURE__*/ _async_to_generator._(function*() {
|
||||
_this1.x();
|
||||
_this.x();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -75,11 +75,13 @@ impl VisitMut for Arrow {
|
||||
noop_visit_mut_type!(fail);
|
||||
|
||||
fn visit_mut_class(&mut self, c: &mut Class) {
|
||||
let old = self.in_subclass;
|
||||
|
||||
if c.super_class.is_some() {
|
||||
self.in_subclass = true;
|
||||
}
|
||||
c.visit_mut_children_with(self);
|
||||
self.in_subclass = false;
|
||||
self.in_subclass = old;
|
||||
}
|
||||
|
||||
fn visit_mut_constructor(&mut self, c: &mut Constructor) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::iter;
|
||||
use std::{iter, mem};
|
||||
|
||||
use serde::Deserialize;
|
||||
use swc_common::{
|
||||
@ -9,8 +9,8 @@ use swc_ecma_transforms_base::{helper, helper_expr, perf::Check};
|
||||
use swc_ecma_transforms_macros::fast_path;
|
||||
use swc_ecma_utils::{
|
||||
contains_this_expr, find_pat_ids,
|
||||
function::{FnEnvHoister, FnWrapperResult, FunctionWrapper},
|
||||
private_ident, quote_ident, ExprFactory, Remapper, StmtLike,
|
||||
function::{init_this, FnEnvHoister, FnWrapperResult, FunctionWrapper},
|
||||
prepend_stmt, private_ident, quote_ident, ExprFactory, Remapper, StmtLike,
|
||||
};
|
||||
use swc_ecma_visit::{
|
||||
as_folder, noop_visit_mut_type, noop_visit_type, Fold, Visit, VisitMut, VisitMutWith, VisitWith,
|
||||
@ -45,6 +45,7 @@ pub fn async_to_generator<C: Comments + Clone>(
|
||||
as_folder(AsyncToGenerator {
|
||||
c,
|
||||
comments,
|
||||
in_subclass: false,
|
||||
unresolved_ctxt: SyntaxContext::empty().apply_mark(unresolved_mark),
|
||||
})
|
||||
}
|
||||
@ -62,6 +63,7 @@ pub struct Config {
|
||||
struct AsyncToGenerator<C: Comments + Clone> {
|
||||
c: Config,
|
||||
comments: Option<C>,
|
||||
in_subclass: bool,
|
||||
unresolved_ctxt: SyntaxContext,
|
||||
}
|
||||
|
||||
@ -69,9 +71,11 @@ struct Actual<C: Comments> {
|
||||
c: Config,
|
||||
comments: Option<C>,
|
||||
|
||||
in_subclass: bool,
|
||||
hoister: FnEnvHoister,
|
||||
|
||||
unresolved_ctxt: SyntaxContext,
|
||||
extra_stmts: Vec<Stmt>,
|
||||
hoist_stmts: Vec<Stmt>,
|
||||
}
|
||||
|
||||
#[swc_trace]
|
||||
@ -79,6 +83,14 @@ struct Actual<C: Comments> {
|
||||
impl<C: Comments + Clone> VisitMut for AsyncToGenerator<C> {
|
||||
noop_visit_mut_type!(fail);
|
||||
|
||||
fn visit_mut_class(&mut self, c: &mut Class) {
|
||||
if c.super_class.is_some() {
|
||||
self.in_subclass = true;
|
||||
}
|
||||
c.visit_mut_children_with(self);
|
||||
self.in_subclass = false;
|
||||
}
|
||||
|
||||
fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
|
||||
self.visit_mut_stmt_like(n);
|
||||
}
|
||||
@ -98,16 +110,19 @@ impl<C: Comments + Clone> AsyncToGenerator<C> {
|
||||
let mut stmts_updated = Vec::with_capacity(stmts.len());
|
||||
|
||||
for mut stmt in stmts.drain(..) {
|
||||
let hoister = FnEnvHoister::new(self.unresolved_ctxt);
|
||||
|
||||
let mut actual = Actual {
|
||||
c: self.c,
|
||||
comments: self.comments.clone(),
|
||||
in_subclass: self.in_subclass,
|
||||
hoister,
|
||||
unresolved_ctxt: self.unresolved_ctxt,
|
||||
extra_stmts: Vec::new(),
|
||||
hoist_stmts: Vec::new(),
|
||||
};
|
||||
|
||||
stmt.visit_mut_with(&mut actual);
|
||||
stmts_updated.extend(actual.hoist_stmts.into_iter().map(T::from));
|
||||
stmts_updated.extend(actual.hoister.to_stmt().into_iter().map(T::from));
|
||||
stmts_updated.push(stmt);
|
||||
stmts_updated.extend(actual.extra_stmts.into_iter().map(T::from));
|
||||
}
|
||||
@ -122,6 +137,45 @@ impl<C: Comments + Clone> AsyncToGenerator<C> {
|
||||
impl<C: Comments> VisitMut for Actual<C> {
|
||||
noop_visit_mut_type!(fail);
|
||||
|
||||
fn visit_mut_class(&mut self, c: &mut Class) {
|
||||
let old = self.in_subclass;
|
||||
|
||||
if c.super_class.is_some() {
|
||||
self.in_subclass = true;
|
||||
}
|
||||
c.visit_mut_children_with(self);
|
||||
self.in_subclass = old;
|
||||
}
|
||||
|
||||
fn visit_mut_constructor(&mut self, c: &mut Constructor) {
|
||||
c.params.visit_mut_children_with(self);
|
||||
|
||||
if let Some(BlockStmt { span: _, stmts, .. }) = &mut c.body {
|
||||
let old_rep = self.hoister.take();
|
||||
|
||||
stmts.visit_mut_children_with(self);
|
||||
|
||||
if self.in_subclass {
|
||||
let (decl, this_id) =
|
||||
mem::replace(&mut self.hoister, old_rep).to_stmt_in_subclass();
|
||||
|
||||
if let Some(this_id) = this_id {
|
||||
init_this(stmts, &this_id)
|
||||
}
|
||||
|
||||
if let Some(decl) = decl {
|
||||
prepend_stmt(stmts, decl)
|
||||
}
|
||||
} else {
|
||||
let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
|
||||
|
||||
if let Some(decl) = decl {
|
||||
prepend_stmt(stmts, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_class_method(&mut self, m: &mut ClassMethod) {
|
||||
if m.function.body.is_none() {
|
||||
return;
|
||||
@ -192,6 +246,51 @@ impl<C: Comments> VisitMut for Actual<C> {
|
||||
self.visit_mut_expr_with_binding(expr, None, false);
|
||||
}
|
||||
|
||||
fn visit_mut_function(&mut self, f: &mut Function) {
|
||||
let old_rep = self.hoister.take();
|
||||
|
||||
f.visit_mut_children_with(self);
|
||||
|
||||
let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
|
||||
|
||||
if let (Some(body), Some(decl)) = (&mut f.body, decl) {
|
||||
prepend_stmt(&mut body.stmts, decl);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_getter_prop(&mut self, f: &mut GetterProp) {
|
||||
f.key.visit_mut_with(self);
|
||||
|
||||
if let Some(body) = &mut f.body {
|
||||
let old_rep = self.hoister.take();
|
||||
|
||||
body.visit_mut_with(self);
|
||||
|
||||
let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
|
||||
|
||||
if let Some(stmt) = decl {
|
||||
prepend_stmt(&mut body.stmts, stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_setter_prop(&mut self, f: &mut SetterProp) {
|
||||
f.key.visit_mut_with(self);
|
||||
f.param.visit_mut_with(self);
|
||||
|
||||
if let Some(body) = &mut f.body {
|
||||
let old_rep = self.hoister.take();
|
||||
|
||||
body.visit_mut_with(self);
|
||||
|
||||
let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
|
||||
|
||||
if let Some(stmt) = decl {
|
||||
prepend_stmt(&mut body.stmts, stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_fn_decl(&mut self, f: &mut FnDecl) {
|
||||
f.visit_mut_children_with(self);
|
||||
if !f.function.is_async {
|
||||
@ -342,11 +441,7 @@ impl<C: Comments> Actual<C> {
|
||||
|
||||
match expr {
|
||||
Expr::Arrow(arrow_expr @ ArrowExpr { is_async: true, .. }) => {
|
||||
let mut state = FnEnvHoister::new(self.unresolved_ctxt);
|
||||
|
||||
arrow_expr.visit_mut_with(&mut state);
|
||||
|
||||
self.hoist_stmts.extend(state.to_stmt());
|
||||
arrow_expr.visit_mut_with(&mut self.hoister);
|
||||
|
||||
let mut wrapper = FunctionWrapper::from(arrow_expr.take());
|
||||
wrapper.ignore_function_name = self.c.ignore_function_name;
|
||||
|
@ -0,0 +1,15 @@
|
||||
class Test0 {
|
||||
}
|
||||
class Test extends Test0 {
|
||||
constructor(){
|
||||
var _this;
|
||||
super(), _this = this, console.log(function() {
|
||||
var _ref = _async_to_generator(function*(e) {
|
||||
yield _this.test();
|
||||
});
|
||||
return function(e) {
|
||||
return _ref.apply(this, arguments);
|
||||
};
|
||||
}());
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
class Foo extends Bar {
|
||||
constructor(options){
|
||||
var _this;
|
||||
super({
|
||||
callA: _async_to_generator(function*() {
|
||||
_this.callA();
|
||||
})
|
||||
}), _this = this;
|
||||
}
|
||||
}
|
@ -2077,6 +2077,44 @@ test!(
|
||||
"
|
||||
);
|
||||
|
||||
test!(
|
||||
Syntax::default(),
|
||||
|_| async_to_generator::<SingleThreadedComments>(Default::default(), None, Mark::new()),
|
||||
issue_8452,
|
||||
r#"
|
||||
class Test0 {}
|
||||
|
||||
class Test extends Test0 {
|
||||
constructor() {
|
||||
super(),
|
||||
console.log(async (e) => {
|
||||
await this.test();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
"#
|
||||
);
|
||||
|
||||
test!(
|
||||
Syntax::default(),
|
||||
|_| with_resolver(),
|
||||
issue_9432,
|
||||
r#"
|
||||
class Foo extends Bar {
|
||||
constructor(options) {
|
||||
super(
|
||||
{
|
||||
callA: async () => {
|
||||
this.callA();
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
|
||||
#[testing::fixture("tests/async-to-generator/**/exec.js")]
|
||||
fn exec(input: PathBuf) {
|
||||
let input = read_to_string(input).unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user