Skip to content

Commit

Permalink
fix(es/compat): Fix syntax context of async-to-generator (#6741)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdy1 committed Jan 3, 2023
1 parent 1602f66 commit 206c0db
Show file tree
Hide file tree
Showing 16 changed files with 194 additions and 27 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions crates/swc/tests/fixture/issues-6xxx/6730/input/.swcrc
@@ -0,0 +1,26 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false
},
"target": "es2015",
"loose": false,
"minify": {
"compress": false,
"mangle": {
"toplevel": false,
"keep_classnames": false,
"keep_fnames": false,
"keep_private_props": false,
"ie8": false,
"safari10": false
}
}
},
"module": {
"type": "es6"
},
"minify": false,
"isModule": true
}
11 changes: 11 additions & 0 deletions crates/swc/tests/fixture/issues-6xxx/6730/input/index.ts
@@ -0,0 +1,11 @@
import { Plugin, PluginBuild } from 'esbuild';

export const styleLoader = (): Plugin => {
return {
setup(build: PluginBuild) {
build.onLoad(async (args) => {

});
},
};
};
13 changes: 13 additions & 0 deletions crates/swc/tests/fixture/issues-6xxx/6730/output/index.ts
@@ -0,0 +1,13 @@
import r from "@swc/helpers/src/_async_to_generator.mjs";
export const styleLoader = ()=>{
return {
setup (t) {
t.onLoad(function() {
var t = r(function*(r) {});
return function(r) {
return t.apply(this, arguments);
};
}());
}
};
};
4 changes: 4 additions & 0 deletions crates/swc/tests/projects.rs
Expand Up @@ -812,6 +812,10 @@ fn should_visit() {

#[testing::fixture("tests/fixture/**/input/")]
#[testing::fixture("tests/vercel/**/input/")]
fn fixture(input_dir: PathBuf) {
tests(input_dir)
}

fn tests(input_dir: PathBuf) {
let output = input_dir.parent().unwrap().join("output");

Expand Down
2 changes: 1 addition & 1 deletion crates/swc/tests/vercel/full/next-31419/1/output/index.js
Expand Up @@ -64,7 +64,7 @@ export var listOfUser = function(t) {
2
];
});
}), function(r, e) {
}), function(r, n) {
return e.apply(this, arguments);
}));
};
2 changes: 1 addition & 1 deletion crates/swc/tests/vercel/full/next-31419/2/output/index.js
Expand Up @@ -19,7 +19,7 @@ export const listOfUser = function(n) {
postgreSQL.query(t, null, function(n, t) {
n ? e(n) : r(t.rows);
});
}), function(r, e) {
}), function(r, n) {
return e.apply(this, arguments);
}));
};
8 changes: 4 additions & 4 deletions crates/swc_ecma_minifier/src/compress/optimize/iife.rs
Expand Up @@ -5,15 +5,15 @@ use swc_atoms::js_word;
use swc_common::{pass::Either, util::take::Take, Mark, Spanned, SyntaxContext, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::{
contains_arguments, contains_this_expr, find_pat_ids, undefined, ExprFactory,
contains_arguments, contains_this_expr, find_pat_ids, undefined, ExprFactory, Remapper,
};
use swc_ecma_visit::VisitMutWith;

use super::{util::NormalMultiReplacer, Optimizer};
#[cfg(feature = "debug")]
use crate::debug::dump;
use crate::{
compress::optimize::{util::Remapper, Ctx},
compress::optimize::Ctx,
mode::Mode,
util::{idents_captured_by, idents_used_by, make_number},
};
Expand Down Expand Up @@ -578,7 +578,7 @@ where
if self.vars.inline_with_multi_replacer(body) {
self.changed = true;
}
body.visit_mut_with(&mut Remapper { vars: remap });
body.visit_mut_with(&mut Remapper::new(&remap));
exprs.push(body.take());

report_change!("inline: Inlining a call to an arrow function");
Expand Down Expand Up @@ -889,7 +889,7 @@ where
if self.vars.inline_with_multi_replacer(body) {
self.changed = true;
}
body.visit_mut_with(&mut Remapper { vars: remap });
body.visit_mut_with(&mut Remapper::new(&remap));

let mut vars = Vec::new();
let mut exprs = Vec::new();
Expand Down
20 changes: 1 addition & 19 deletions crates/swc_ecma_minifier/src/compress/optimize/util.rs
Expand Up @@ -5,7 +5,7 @@ use std::{

use rustc_hash::{FxHashMap, FxHashSet};
use swc_atoms::js_word;
use swc_common::{util::take::Take, Span, SyntaxContext, DUMMY_SP};
use swc_common::{util::take::Take, Span, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::{Parallel, ParallelExt};
use swc_ecma_utils::{ExprCtx, ExprExt};
Expand Down Expand Up @@ -185,24 +185,6 @@ pub(crate) fn is_valid_for_lhs(e: &Expr) -> bool {
!matches!(e, Expr::Lit(..) | Expr::Unary(..))
}

/// Variable remapper
///
/// - Used for evaluating IIFEs

pub(crate) struct Remapper {
pub vars: FxHashMap<Id, SyntaxContext>,
}

impl VisitMut for Remapper {
noop_visit_mut_type!();

fn visit_mut_ident(&mut self, i: &mut Ident) {
if let Some(new_ctxt) = self.vars.get(&i.to_id()).copied() {
i.span.ctxt = new_ctxt;
}
}
}

/// A visitor responsible for inlining special kind of variables and removing
/// (some) unused variables. Due to the order of visit, the main visitor cannot
/// handle all edge cases and this type is the complement for it.
Expand Down
@@ -0,0 +1,3 @@
{
"defaults": false
}
45 changes: 45 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/issues/6730/input.js
@@ -0,0 +1,45 @@
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function () {
var self = this, args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
export const styleLoader = () => {
return {
name: 'style-loader',
setup(build) {
build.onLoad({
filter: /.*/,
namespace: 'less'
}, function () {
var _ref = _asyncToGenerator(function* (args) { });
return function (args) {
return _ref.apply(this, arguments);
};
}());
}
};
};
@@ -0,0 +1,3 @@
{
"toplevel": true
}
42 changes: 42 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/issues/6730/output.js
@@ -0,0 +1,42 @@
function n(n, e, t, r, o, u, i) {
try {
var a = n[u](i);
var c = a.value;
} catch (s) {
t(s);
return;
}
if (a.done) e(c);
else Promise.resolve(c).then(r, o);
}
function e(e) {
return function() {
var t = this, r = arguments;
return new Promise(function(o, u) {
var i = e.apply(t, r);
function a(e) {
n(i, o, u, a, c, "next", e);
}
function c(e) {
n(i, o, u, a, c, "throw", e);
}
a(void 0);
});
};
}
export const styleLoader = ()=>{
return {
name: 'style-loader',
setup (n) {
n.onLoad({
filter: /.*/,
namespace: 'less'
}, function() {
var n = e(function*(n) {});
return function(e) {
return n.apply(this, arguments);
};
}());
}
};
};
14 changes: 12 additions & 2 deletions crates/swc_ecma_transforms_compat/src/es2017/async_to_generator.rs
Expand Up @@ -6,9 +6,9 @@ use swc_ecma_ast::*;
use swc_ecma_transforms_base::{helper, helper_expr, perf::Check};
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_utils::{
contains_this_expr,
contains_this_expr, find_pat_ids,
function::{FnEnvHoister, FnWrapperResult, FunctionWrapper},
private_ident, quote_ident, ExprFactory, StmtLike,
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,
Expand Down Expand Up @@ -393,6 +393,16 @@ impl<C: Comments> Actual<C> {
/// `_asyncToGenerator(function*() {})` from `async function() {}`;
#[tracing::instrument(level = "info", skip_all)]
fn make_fn_ref(mut expr: FnExpr) -> Expr {
{
let param_ids: Vec<Id> = find_pat_ids(&expr.function.params);
let mapping = param_ids
.into_iter()
.map(|id| (id, SyntaxContext::empty().apply_mark(Mark::new())))
.collect();

expr.function.visit_mut_with(&mut Remapper::new(&mapping));
}

expr.function.body.visit_mut_with(&mut AsyncFnBodyHandler {
is_async_generator: expr.function.is_generator,
});
Expand Down
1 change: 1 addition & 0 deletions crates/swc_ecma_utils/Cargo.toml
Expand Up @@ -24,6 +24,7 @@ indexmap = "1.6.1"
num_cpus = "1.13.1"
once_cell = "1.10.0"
rayon = {version = "1.5.1", optional = true}
rustc-hash = "1.1.0"
swc_atoms = {version = "0.4.32", path = "../swc_atoms"}
swc_common = {version = "0.29.25", path = "../swc_common"}
swc_ecma_ast = {version = "0.95.9", path = "../swc_ecma_ast"}
Expand Down
26 changes: 26 additions & 0 deletions crates/swc_ecma_utils/src/lib.rs
Expand Up @@ -18,6 +18,7 @@ use std::{
ops::Add,
};

use rustc_hash::FxHashMap;
use swc_atoms::{js_word, JsWord};
use swc_common::{collections::AHashSet, Mark, Span, Spanned, SyntaxContext, DUMMY_SP};
use swc_ecma_ast::*;
Expand Down Expand Up @@ -2825,6 +2826,31 @@ pub fn contains_top_level_await<V: VisitWith<TopLevelAwait>>(t: &V) -> bool {
finder.found
}

/// Variable remapper
///
/// This visitor modifies [SyntaxContext] while preserving the symbol of
/// [Ident]s.

pub struct Remapper<'a> {
vars: &'a FxHashMap<Id, SyntaxContext>,
}

impl<'a> Remapper<'a> {
pub fn new(vars: &'a FxHashMap<Id, SyntaxContext>) -> Self {
Self { vars }
}
}

impl VisitMut for Remapper<'_> {
noop_visit_mut_type!();

fn visit_mut_ident(&mut self, i: &mut Ident) {
if let Some(new_ctxt) = self.vars.get(&i.to_id()).copied() {
i.span.ctxt = new_ctxt;
}
}
}

#[cfg(test)]
mod test {
use swc_common::{input::StringInput, BytePos};
Expand Down

0 comments on commit 206c0db

Please sign in to comment.