perf(es/transforms): Reduce usage of #[fast_path] (#2439)

swc_ecma_transforms_compat:
 - Remove `#[fast_path]` from passes.
 - Migrate some passes to `VisitMut`.
This commit is contained in:
Donny/강동윤 2021-10-15 19:18:27 +09:00 committed by GitHub
parent d045244089
commit e722bd4887
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 282 additions and 507 deletions

4
Cargo.lock generated
View File

@ -2815,7 +2815,7 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_compat"
version = "0.43.0"
version = "0.43.1"
dependencies = [
"ahash",
"arrayvec",
@ -3156,7 +3156,7 @@ dependencies = [
[[package]]
name = "swc_visit"
version = "0.2.6"
version = "0.2.7"
dependencies = [
"either",
"swc_visit_macros",

View File

@ -56,6 +56,8 @@ macro_rules! mark_nested {
}
};
}
/// TODO: VisitMut
impl<'a> Fold for SuperFieldAccessFolder<'a> {
noop_fold_type!();

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_compat"
repository = "https://github.com/swc-project/swc.git"
version = "0.43.0"
version = "0.43.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -18,6 +18,7 @@ struct AsyncArrowsInClass {
vars: Vec<VarDeclarator>,
}
/// TODO: VisitMut
impl Fold for AsyncArrowsInClass {
noop_fold_type!();

View File

@ -13,6 +13,7 @@ struct EdgeDefaultParam {
in_arrow: bool,
}
/// TODO: VisitMut
impl Fold for EdgeDefaultParam {
noop_fold_type!();

View File

@ -55,6 +55,7 @@ impl TemplateLiteralCaching {
}
}
/// TODO: VisitMut
impl Fold for TemplateLiteralCaching {
noop_fold_type!();

View File

@ -67,6 +67,7 @@ struct Arrow {
vars: Vec<VarDeclarator>,
}
/// TODO: VisitMut
#[fast_path(ArrowVisitor)]
impl Fold for Arrow {
noop_fold_type!();
@ -238,6 +239,7 @@ struct ArgumentsReplacer {
found: bool,
}
/// TODO: VisitMut
impl Fold for ArgumentsReplacer {
noop_fold_type!();

View File

@ -12,6 +12,7 @@ pub fn block_scoped_functions() -> impl Fold {
#[derive(Clone, Copy)]
struct BlockScopedFns;
/// TODO: VisitMut
#[fast_path(BlockScopedFnFinder)]
impl Fold for BlockScopedFns {
noop_fold_type!();

View File

@ -418,6 +418,7 @@ impl BlockScoping {
}
}
/// TODO: VisitMut
impl Fold for BlockScoping {
noop_fold_type!();
@ -761,6 +762,7 @@ impl<'a> FlowHelper<'a> {
}
}
/// TODO: VisitMut
impl Fold for FlowHelper<'_> {
noop_fold_type!();

View File

@ -180,6 +180,7 @@ pub(super) enum SuperFoldingMode {
Var,
}
/// TODO: VisitMut
impl Fold for ConstructorFolder<'_> {
noop_fold_type!();
fold_only_key!();
@ -425,6 +426,7 @@ pub(super) fn replace_this_in_constructor(mark: Mark, c: Constructor) -> (Constr
in_injected_define_property_call: bool,
}
/// TODO: VisitMut
impl Fold for Replacer {
noop_fold_type!();
@ -543,6 +545,7 @@ pub(super) struct VarRenamer<'a> {
pub class_name: &'a JsWord,
}
/// TODO: VisitMut
impl<'a> Fold for VarRenamer<'a> {
noop_fold_type!();

View File

@ -179,6 +179,7 @@ where
}
}
/// TODO: VisitMut
#[fast_path(ClassFinder)]
impl<C> Fold for Classes<C>
where

View File

@ -47,6 +47,7 @@ struct ObjectLitFolder {
used_define_enum_props: bool,
}
/// TODO: VisitMut
impl Fold for ObjectLitFolder {
noop_fold_type!();
@ -288,6 +289,7 @@ impl Visit for ComplexVisitor {
}
}
/// TODO: VisitMut
impl Fold for ComputedProps {
noop_fold_type!();

View File

@ -448,6 +448,7 @@ impl AssignFolder {
}
}
/// TODO: VisitMut
#[fast_path(DestructuringVisitor)]
impl Fold for Destructuring {
noop_fold_type!();
@ -522,6 +523,7 @@ struct AssignFolder {
ignore_return_value: Option<()>,
}
/// TODO: VisitMut
#[fast_path(DestructuringVisitor)]
impl Fold for AssignFolder {
noop_fold_type!();

View File

@ -398,6 +398,7 @@ impl Actual {
}
}
/// TODO: VisitMut
impl Fold for Actual {
noop_fold_type!();
@ -503,6 +504,7 @@ fn make_finally_block(
})
}
/// TODO: VisitMut
impl Fold for ForOf {
noop_fold_type!();

View File

@ -1,8 +1,8 @@
use swc_common::util::take::Take;
use swc_ecma_ast::*;
use swc_ecma_transforms_base::{helper, perf::Check};
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_transforms_base::helper;
use swc_ecma_utils::ExprFactory;
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit, VisitWith};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
/// `@babel/plugin-transform-instanceof`
///
@ -29,17 +29,16 @@ use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visi
///
/// _instanceof(foo, Bar);
/// ```
pub fn instance_of() -> impl Fold {
InstanceOf
pub fn instance_of() -> impl Fold + VisitMut {
as_folder(InstanceOf)
}
struct InstanceOf;
#[fast_path(InstnaceOfFinder)]
impl Fold for InstanceOf {
noop_fold_type!();
impl VisitMut for InstanceOf {
noop_visit_mut_type!();
fn fold_expr(&mut self, expr: Expr) -> Expr {
let expr = expr.fold_children_with(self);
fn visit_mut_expr(&mut self, expr: &mut Expr) {
expr.visit_mut_children_with(self);
match expr {
Expr::Bin(BinExpr {
@ -47,36 +46,15 @@ impl Fold for InstanceOf {
left,
op: op!("instanceof"),
right,
}) => Expr::Call(CallExpr {
span,
callee: helper!(span, instanceof, "instanceof"),
args: vec![left.as_arg(), right.as_arg()],
type_args: Default::default(),
}),
_ => expr,
}) => {
*expr = Expr::Call(CallExpr {
span: *span,
callee: helper!(*span, instanceof, "instanceof"),
args: vec![left.take().as_arg(), right.take().as_arg()],
type_args: Default::default(),
});
}
_ => {}
}
}
}
#[derive(Default)]
struct InstnaceOfFinder {
found: bool,
}
impl Visit for InstnaceOfFinder {
noop_visit_type!();
fn visit_bin_expr(&mut self, e: &BinExpr, _: &dyn Node) {
e.visit_children_with(self);
if e.op == op!("instanceof") {
self.found = true
}
}
}
impl Check for InstnaceOfFinder {
fn should_handle(&self) -> bool {
self.found
}
}

View File

@ -2,8 +2,7 @@ use std::borrow::Cow;
use swc_atoms::js_word;
use swc_common::{pass::CompilerPass, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::Check;
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_transforms_base::perf::{should_work, Check};
use swc_ecma_utils::{prepend, private_ident, quote_ident, undefined, ExprFactory};
use swc_ecma_visit::{
as_folder, noop_visit_mut_type, noop_visit_type, Fold, Node, Visit, VisitMut, VisitMutWith,
@ -25,12 +24,14 @@ struct NewTarget {
var: Option<VarDeclarator>,
}
#[fast_path(ShouldWork)]
impl VisitMut for NewTarget {
noop_visit_mut_type!();
fn visit_mut_arrow_expr(&mut self, e: &mut ArrowExpr) {
// #[fast_path] ensures that `e` contains new.target
// Ensure that `e` contains new.target
if !should_work::<ShouldWork, _>(&*e) {
return;
}
let old = self.in_arrow_expr;
if self.var.is_none() {
@ -143,7 +144,10 @@ impl VisitMut for NewTarget {
}
fn visit_mut_fn_decl(&mut self, f: &mut FnDecl) {
// #[fast_path] ensures that `f` contains `new.target`.
// Ensure that `f` contains `new.target`.
if !should_work::<ShouldWork, _>(&*f) {
return;
}
let old = self.cur.take();
self.cur = Some(f.ident.clone());
@ -154,7 +158,10 @@ impl VisitMut for NewTarget {
}
fn visit_mut_fn_expr(&mut self, f: &mut FnExpr) {
// #[fast_path] ensures that `f` contains `new.target`.
// Ensure that `f` contains `new.target`.
if !should_work::<ShouldWork, _>(&*f) {
return;
}
let i = f
.ident

View File

@ -253,6 +253,7 @@ impl Params {
}
}
/// TODO: VisitMut
impl Fold for Params {
noop_fold_type!();

View File

@ -1532,6 +1532,7 @@ struct UnmarkedInvalidHandler {
case_id: usize,
}
/// TODO: VisitMut
impl Fold for UnmarkedInvalidHandler {
noop_fold_type!();
@ -1553,6 +1554,8 @@ struct InvalidToLit<'a> {
// Map from loc-id to stmt index
map: &'a [Loc],
}
/// TODO: VisitMut
impl Fold for InvalidToLit<'_> {
noop_fold_type!();
@ -1585,6 +1588,7 @@ struct CatchParamHandler<'a> {
param: Option<&'a Pat>,
}
/// TODO: VisitMut
impl Fold for CatchParamHandler<'_> {
noop_fold_type!();

View File

@ -56,6 +56,7 @@ impl Hoister {
}
}
/// TODO: VisitMut
impl Fold for Hoister {
noop_fold_type!();

View File

@ -82,6 +82,7 @@ impl Regenerator {
}
}
/// TODO: VisitMut
impl Fold for Regenerator {
noop_fold_type!();
@ -500,6 +501,7 @@ struct FnSentVisitor {
ctx: Ident,
}
/// TODO: VisitMut
impl Fold for FnSentVisitor {
noop_fold_type!();

View File

@ -1,8 +1,7 @@
use swc_common::util::take::Take;
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::Check;
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_utils::quote_ident;
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit, VisitWith};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
/// Compile ES2015 shorthand properties to ES5
///
@ -38,58 +37,40 @@ use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visi
/// }
/// };
/// ```
pub fn shorthand() -> impl 'static + Fold {
Shorthand
pub fn shorthand() -> impl 'static + Fold + VisitMut {
as_folder(Shorthand)
}
#[derive(Clone, Copy)]
struct Shorthand;
#[fast_path(ShorthandFinder)]
impl Fold for Shorthand {
noop_fold_type!();
impl VisitMut for Shorthand {
noop_visit_mut_type!();
fn fold_prop(&mut self, prop: Prop) -> Prop {
let prop = prop.fold_children_with(self);
fn visit_mut_prop(&mut self, prop: &mut Prop) {
prop.visit_mut_children_with(self);
match prop {
Prop::Shorthand(Ident { sym, span, .. }) => Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!(span, sym.clone())),
value: Box::new(quote_ident!(span, sym).into()),
}),
Prop::Method(MethodProp { key, function }) => Prop::KeyValue(KeyValueProp {
key,
value: Box::new(Expr::Fn(FnExpr {
ident: None,
function,
})),
}),
_ => prop,
Prop::Shorthand(Ident { sym, span, .. }) => {
*prop = Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!(*span, sym.clone())),
value: Box::new(quote_ident!(*span, sym.clone()).into()),
});
}
Prop::Method(MethodProp { key, function }) => {
*prop = Prop::KeyValue(KeyValueProp {
key: key.take(),
value: Box::new(Expr::Fn(FnExpr {
ident: None,
function: function.take(),
})),
})
}
_ => {}
}
}
}
#[derive(Default)]
struct ShorthandFinder {
found: bool,
}
impl Visit for ShorthandFinder {
noop_visit_type!();
fn visit_prop(&mut self, n: &Prop, _: &dyn Node) {
n.visit_children_with(self);
self.found |= n.is_shorthand() || n.is_method();
}
}
impl Check for ShorthandFinder {
fn should_handle(&self) -> bool {
self.found
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -97,7 +78,7 @@ mod tests {
test!(
::swc_ecma_parser::Syntax::default(),
|_| Shorthand,
|_| shorthand(),
babel_method_plain,
"var obj = {
method() {
@ -113,7 +94,7 @@ mod tests {
test!(
::swc_ecma_parser::Syntax::default(),
|_| Shorthand,
|_| shorthand(),
babel_comments,
"var A = 'a';
var o = {
@ -128,7 +109,7 @@ var o = {
test!(
::swc_ecma_parser::Syntax::default(),
|_| Shorthand,
|_| shorthand(),
babel_mixed,
"var coords = { x, y, foo: 'bar' };",
"var coords = {
@ -140,7 +121,7 @@ var o = {
test!(
::swc_ecma_parser::Syntax::default(),
|_| Shorthand,
|_| shorthand(),
babel_multiple,
"var coords = { x, y };",
"var coords = {
@ -151,7 +132,7 @@ var o = {
test!(
::swc_ecma_parser::Syntax::default(),
|_| Shorthand,
|_| shorthand(),
babel_single,
"var coords = { x };",
"var coords = {

View File

@ -1,18 +1,20 @@
use serde::Deserialize;
use std::mem;
use swc_atoms::js_word;
use swc_common::{util::move_map::MoveMap, Span, Spanned, DUMMY_SP};
use swc_common::{util::take::Take, Span, Spanned, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::{ext::ExprRefExt, helper, perf::Check};
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_transforms_base::{ext::ExprRefExt, helper};
use swc_ecma_utils::{
alias_ident_for, is_literal, member_expr, prepend, quote_ident, undefined, ExprFactory,
StmtLike,
};
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit, VisitWith};
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
pub fn spread(c: Config) -> impl Fold {
Spread { c }
Spread {
c,
vars: Default::default(),
}
}
#[derive(Debug, Clone, Copy, Default, Deserialize)]
@ -25,15 +27,10 @@ pub struct Config {
#[derive(Default)]
struct Spread {
c: Config,
}
#[derive(Default)]
struct ActualFolder {
c: Config,
vars: Vec<VarDeclarator>,
}
#[fast_path(SpreadFinder)]
/// TODO: VisitMut
impl Fold for Spread {
noop_fold_type!();
@ -44,37 +41,6 @@ impl Fold for Spread {
fn fold_stmts(&mut self, n: Vec<Stmt>) -> Vec<Stmt> {
self.fold_stmt_like(n)
}
}
impl Spread {
fn fold_stmt_like<T>(&mut self, items: Vec<T>) -> Vec<T>
where
T: StmtLike + FoldWith<ActualFolder> + FoldWith<Self>,
{
let mut folder = ActualFolder {
c: self.c,
vars: vec![],
};
let mut items = items.move_map(|item| item.fold_with(&mut folder));
if !folder.vars.is_empty() {
prepend(
&mut items,
T::from_stmt(Stmt::Decl(Decl::Var(VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
declare: false,
decls: mem::replace(&mut folder.vars, vec![]),
}))),
);
}
items
}
}
#[fast_path(SpreadFinder)]
impl Fold for ActualFolder {
noop_fold_type!();
fn fold_expr(&mut self, e: Expr) -> Expr {
let e = e.fold_children_with(self);
@ -230,7 +196,34 @@ impl Fold for ActualFolder {
}
}
impl ActualFolder {
impl Spread {
fn fold_stmt_like<T>(&mut self, items: Vec<T>) -> Vec<T>
where
T: StmtLike,
Vec<T>: FoldWith<Self>,
{
let orig = self.vars.take();
let mut items = items.fold_children_with(self);
if !self.vars.is_empty() {
prepend(
&mut items,
T::from_stmt(Stmt::Decl(Decl::Var(VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
declare: false,
decls: self.vars.take(),
}))),
);
}
self.vars = orig;
items
}
}
impl Spread {
fn concat_args(
&self,
span: Span,
@ -453,24 +446,3 @@ fn expand_literal_args(
expand(&mut buf, args);
buf
}
#[derive(Default)]
struct SpreadFinder {
found: bool,
}
impl Visit for SpreadFinder {
noop_visit_type!();
fn visit_expr_or_spread(&mut self, n: &ExprOrSpread, _: &dyn Node) {
n.visit_children_with(self);
self.found |= n.spread.is_some();
}
}
impl Check for SpreadFinder {
fn should_handle(&self) -> bool {
self.found
}
}

View File

@ -1,10 +1,8 @@
use swc_atoms::JsWord;
use swc_common::DUMMY_SP;
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::Check;
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_utils::{quote_ident, ExprFactory};
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
/// Compile ES2015 sticky regex to an ES5 RegExp constructor
///
@ -20,19 +18,18 @@ use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visi
/// ```js
/// new RegExp("o+", "y")
/// ```
pub fn sticky_regex() -> impl 'static + Fold {
StickyRegex
pub fn sticky_regex() -> impl 'static + Fold + VisitMut {
as_folder(StickyRegex)
}
#[derive(Clone, Copy)]
struct StickyRegex;
#[fast_path(StickyRegexVisitor)]
impl Fold for StickyRegex {
noop_fold_type!();
impl VisitMut for StickyRegex {
noop_visit_mut_type!();
fn fold_expr(&mut self, e: Expr) -> Expr {
let e = e.fold_children_with(self);
fn visit_mut_expr(&mut self, e: &mut Expr) {
e.visit_mut_children_with(self);
match e {
Expr::Lit(Lit::Regex(Regex { exp, flags, span })) => {
@ -48,40 +45,22 @@ impl Fold for StickyRegex {
})))
};
Expr::New(NewExpr {
span,
callee: Box::new(quote_ident!(span, "RegExp").into()),
args: Some(vec![str_lit(exp).as_arg(), str_lit(flags).as_arg()]),
*e = Expr::New(NewExpr {
span: *span,
callee: Box::new(quote_ident!(*span, "RegExp").into()),
args: Some(vec![
str_lit(exp.clone()).as_arg(),
str_lit(flags.clone()).as_arg(),
]),
type_args: Default::default(),
})
} else {
Expr::Lit(Lit::Regex(Regex { exp, flags, span }))
}
}
_ => e,
_ => {}
}
}
}
#[derive(Default)]
struct StickyRegexVisitor {
found: bool,
}
impl Visit for StickyRegexVisitor {
noop_visit_type!();
fn visit_regex(&mut self, n: &Regex, _: &dyn Node) {
self.found |= n.flags.contains('y');
}
}
impl Check for StickyRegexVisitor {
fn should_handle(&self) -> bool {
self.found
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -89,7 +68,7 @@ mod tests {
test!(
::swc_ecma_parser::Syntax::default(),
|_| StickyRegex,
|_| sticky_regex(),
babel_basic,
"var re = /o+/y;",
"var re = new RegExp('o+', 'y');"
@ -97,7 +76,7 @@ mod tests {
test!(
::swc_ecma_parser::Syntax::default(),
|_| StickyRegex,
|_| sticky_regex(),
babel_ignore_non_sticky,
"var re = /o+/;",
"var re = /o+/;"

View File

@ -1,13 +1,9 @@
use swc_atoms::js_word;
use swc_common::{util::take::Take, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::{helper, perf::Check};
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_transforms_base::helper;
use swc_ecma_utils::{quote_str, ExprFactory};
use swc_ecma_visit::{
as_folder, noop_visit_mut_type, noop_visit_type, Fold, Node, Visit, VisitMut, VisitMutWith,
VisitWith,
};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
pub fn typeof_symbol() -> impl VisitMut + Fold {
as_folder(TypeOfSymbol)
@ -16,7 +12,6 @@ pub fn typeof_symbol() -> impl VisitMut + Fold {
#[derive(Clone)]
struct TypeOfSymbol;
#[fast_path(TypeOfFinder)]
impl VisitMut for TypeOfSymbol {
noop_visit_mut_type!();
@ -109,29 +104,6 @@ impl VisitMut for TypeOfSymbol {
}
}
#[derive(Default)]
struct TypeOfFinder {
found: bool,
}
impl Visit for TypeOfFinder {
noop_visit_type!();
fn visit_unary_expr(&mut self, e: &UnaryExpr, _: &dyn Node) {
e.visit_children_with(self);
if e.op == op!("typeof") {
self.found = true
}
}
}
impl Check for TypeOfFinder {
fn should_handle(&self) -> bool {
self.found
}
}
fn is_non_symbol_literal(e: &Expr) -> bool {
match *e {
Expr::Lit(Lit::Str(Str {

View File

@ -1,9 +1,8 @@
use swc_common::{Span, Spanned, DUMMY_SP};
use swc_common::{util::take::Take, Span, Spanned, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::{ext::PatOrExprExt, perf::Check};
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_transforms_base::ext::PatOrExprExt;
use swc_ecma_utils::{member_expr, private_ident, ExprFactory, StmtLike};
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit, VisitWith};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
/// `@babel/plugin-transform-exponentiation-operator`
///
@ -24,30 +23,34 @@ use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visi
///
/// x = Math.pow(x, 3);
/// ```
pub fn exponentation() -> impl Fold {
Exponentation
pub fn exponentation() -> impl Fold + VisitMut {
as_folder(Exponentation::default())
}
#[derive(Clone, Copy)]
struct Exponentation;
#[derive(Default)]
struct AssignFolder {
struct Exponentation {
vars: Vec<VarDeclarator>,
}
#[fast_path(ShouldFold)]
impl Fold for AssignFolder {
noop_fold_type!();
impl VisitMut for Exponentation {
noop_visit_mut_type!();
fn fold_expr(&mut self, e: Expr) -> Expr {
let e = e.fold_children_with(self);
fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
self.visit_mut_stmt_like(n)
}
fn visit_mut_stmts(&mut self, n: &mut Vec<Stmt>) {
self.visit_mut_stmt_like(n)
}
fn visit_mut_expr(&mut self, e: &mut Expr) {
e.visit_mut_children_with(self);
match e {
Expr::Assign(AssignExpr {
span,
left,
op: op!("**="),
op: op @ op!("**="),
right,
}) => {
let lhs: Ident = match left {
@ -67,79 +70,62 @@ impl Fold for AssignFolder {
}
left => {
return Expr::Assign(AssignExpr {
span,
left,
*e = Expr::Assign(AssignExpr {
span: *span,
left: left.take(),
op: op!("="),
right,
right: right.take(),
});
return;
}
};
Expr::Assign(AssignExpr {
span,
left,
op: op!("="),
right: Box::new(mk_call(span, Box::new(lhs.into()), right)),
})
*op = op!("=");
*right = Box::new(mk_call(*span, Box::new(lhs.into()), right.take()));
}
Expr::Bin(BinExpr {
span,
left,
op: op!("**"),
right,
}) => mk_call(span, left, right),
_ => e,
}) => {
*e = mk_call(*span, left.take(), right.take());
}
_ => {}
}
}
}
#[fast_path(ShouldFold)]
impl Fold for Exponentation {
noop_fold_type!();
fn fold_module_items(&mut self, n: Vec<ModuleItem>) -> Vec<ModuleItem> {
self.fold_stmt_like(n)
}
fn fold_stmts(&mut self, n: Vec<Stmt>) -> Vec<Stmt> {
self.fold_stmt_like(n)
}
}
impl Exponentation {
fn fold_stmt_like<T>(&mut self, stmts: Vec<T>) -> Vec<T>
fn visit_mut_stmt_like<T>(&mut self, stmts: &mut Vec<T>)
where
T: StmtLike + VisitWith<ShouldFold>,
Vec<T>: FoldWith<Self> + VisitWith<ShouldFold>,
T: StmtLike + VisitMutWith<Self>,
Vec<T>: VisitMutWith<Self>,
{
let stmts = stmts.fold_children_with(self);
let orig = self.vars.take();
let mut buf = vec![];
let mut buf = Vec::with_capacity(stmts.len());
for stmt in stmts {
match stmt.try_into_stmt() {
Err(module_item) => buf.push(module_item),
Ok(stmt) => {
let mut folder = AssignFolder::default();
let stmt = stmt.fold_with(&mut folder);
for mut stmt in stmts.take() {
stmt.visit_mut_with(self);
// Add variable declaration
// e.g. var ref
if !folder.vars.is_empty() {
buf.push(T::from_stmt(Stmt::Decl(Decl::Var(VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
decls: folder.vars,
declare: false,
}))));
}
buf.push(T::from_stmt(stmt));
}
// Add variable declaration
// e.g. var ref
if !self.vars.is_empty() {
buf.push(T::from_stmt(Stmt::Decl(Decl::Var(VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
decls: self.vars.take(),
declare: false,
}))));
}
buf.push(stmt);
}
buf
self.vars = orig;
*stmts = buf
}
}
@ -154,37 +140,6 @@ fn mk_call(span: Span, left: Box<Expr>, right: Box<Expr>) -> Expr {
})
}
#[derive(Default)]
struct ShouldFold {
found: bool,
}
impl Visit for ShouldFold {
noop_visit_type!();
fn visit_bin_expr(&mut self, e: &BinExpr, _: &dyn Node) {
if e.op == op!("**") {
self.found = true;
}
}
fn visit_assign_expr(&mut self, e: &AssignExpr, _: &dyn Node) {
if e.op == op!("**=") {
self.found = true;
}
if !self.found {
e.left.visit_with(e as _, self);
e.right.visit_with(e as _, self);
}
}
}
impl Check for ShouldFold {
fn should_handle(&self) -> bool {
self.found
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -192,7 +147,7 @@ mod tests {
test!(
::swc_ecma_parser::Syntax::default(),
|_| Exponentation,
|_| exponentation(),
babel_binary,
"2 ** 2",
"Math.pow(2, 2)"
@ -201,7 +156,7 @@ mod tests {
test_exec!(
ignore,
::swc_ecma_parser::Syntax::default(),
|_| Exponentation,
|_| exponentation(),
babel_comprehensive,
r#"expect(2 ** 3).toBe(8);
expect(3 * 2 ** 3).toBe(24);
@ -230,7 +185,7 @@ expect(2 ** 3 ** 2).toBe(512);"#
// FIXME
ignore,
::swc_ecma_parser::Syntax::default(),
|_| Exponentation,
|_| exponentation(),
babel_memoize_object,
r#"var counters = 0;
Object.defineProperty(global, "reader", {
@ -246,7 +201,7 @@ expect(counters).toBe(1);"#
test!(
::swc_ecma_parser::Syntax::default(),
|_| Exponentation,
|_| exponentation(),
assign,
r#"x **= 3"#,
r#"x = Math.pow(x, 3)"#,
@ -254,7 +209,7 @@ expect(counters).toBe(1);"#
);
// test!(::swc_ecma_parser::Syntax::default(),
// |_| Exponentation,
// |_| exponentation(),
// babel_4403,
// "var a, b;
// a[`${b++}`] **= 1;",
@ -266,7 +221,7 @@ expect(counters).toBe(1);"#
test!(
::swc_ecma_parser::Syntax::default(),
|_| Exponentation,
|_| exponentation(),
issue_740,
"self.a = 10 ** 2",
"self.a = Math.pow(10, 2)",
@ -277,7 +232,7 @@ expect(counters).toBe(1);"#
// bu JakeChampion
test!(
::swc_ecma_parser::Syntax::default(),
|_| Exponentation,
|_| exponentation(),
babel_binary_member_assignment_expression,
"var x = {}; x.a = 2 ** 2",
"var x = {}; x.a = Math.pow(2, 2)"
@ -285,7 +240,7 @@ expect(counters).toBe(1);"#
test!(
::swc_ecma_parser::Syntax::default(),
|_| Exponentation,
|_| exponentation(),
assign_to_object_property,
r#"var self = {}; self.x **= 3"#,
r#"var self = {}; var ref = self.x; self.x = Math.pow(ref, 3);"#,

View File

@ -40,6 +40,7 @@ struct Actual {
extra_stmts: Vec<Stmt>,
}
/// TODO: VisitMut
#[fast_path(ShouldWork)]
impl Fold for AsyncToGenerator {
noop_fold_type!();
@ -78,6 +79,7 @@ impl AsyncToGenerator {
}
}
/// TODO: VisitMut
#[fast_path(ShouldWork)]
impl Fold for Actual {
noop_fold_type!();
@ -497,6 +499,7 @@ impl MethodFolder {
}
}
/// TODO: VisitMut
impl Fold for MethodFolder {
noop_fold_type!();
@ -910,6 +913,7 @@ macro_rules! noop {
};
}
/// TODO: VisitMut
impl Fold for AsyncFnBodyHandler {
noop_fold_type!();

View File

@ -1,17 +1,23 @@
use std::{iter, mem};
use swc_common::{chain, util::move_map::MoveMap, Mark, Spanned, DUMMY_SP};
use swc_common::{
chain,
util::{move_map::MoveMap, take::Take},
Mark, Spanned, DUMMY_SP,
};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::{helper, helper_expr, perf::Check};
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_transforms_base::{helper, helper_expr};
use swc_ecma_utils::{
alias_ident_for, alias_if_required, is_literal, private_ident, quote_ident, var::VarCollector,
ExprFactory, StmtLike,
};
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit, VisitWith};
use swc_ecma_visit::{
as_folder, noop_fold_type, noop_visit_mut_type, noop_visit_type, Fold, FoldWith, Node, Visit,
VisitMut, VisitMutWith, VisitWith,
};
/// `@babel/plugin-proposal-object-rest-spread`
pub fn object_rest_spread() -> impl Fold {
chain!(ObjectRest, ObjectSpread)
chain!(ObjectRest, as_folder(ObjectSpread))
}
struct ObjectRest;
@ -141,6 +147,7 @@ macro_rules! impl_for_for_stmt {
};
}
/// TODO: VisitMut
impl Fold for RestFolder {
noop_fold_type!();
@ -403,6 +410,7 @@ where
v.found
}
/// TODO: VisitMut
impl Fold for ObjectRest {
noop_fold_type!();
fn fold_module_items(&mut self, n: Vec<ModuleItem>) -> Vec<ModuleItem> {
@ -1050,6 +1058,8 @@ fn excluded_props(props: &[ObjectPatProp]) -> Vec<Option<ExprOrSpread>> {
/// - `{ x4: {} }` -> `{}`
fn simplify_pat(pat: Pat) -> Pat {
struct PatSimplifier;
/// TODO: VisitMut
impl Fold for PatSimplifier {
noop_fold_type!();
@ -1092,12 +1102,11 @@ fn simplify_pat(pat: Pat) -> Pat {
struct ObjectSpread;
#[fast_path(SpreadVisitor)]
impl Fold for ObjectSpread {
noop_fold_type!();
impl VisitMut for ObjectSpread {
noop_visit_mut_type!();
fn fold_expr(&mut self, expr: Expr) -> Expr {
let expr = expr.fold_children_with(self);
fn visit_mut_expr(&mut self, expr: &mut Expr) {
expr.visit_mut_children_with(self);
match expr {
Expr::Object(ObjectLit { span, props }) => {
@ -1106,7 +1115,7 @@ impl Fold for ObjectSpread {
_ => false,
});
if !has_spread {
return Expr::Object(ObjectLit { span, props });
return;
}
let mut first = true;
@ -1118,7 +1127,7 @@ impl Fold for ObjectSpread {
span: DUMMY_SP,
props: vec![],
};
for prop in props {
for prop in props.take() {
match prop {
PropOrSpread::Prop(..) => obj.props.push(prop),
PropOrSpread::Spread(SpreadElement { expr, .. }) => {
@ -1147,32 +1156,14 @@ impl Fold for ObjectSpread {
buf
};
Expr::Call(CallExpr {
span,
*expr = Expr::Call(CallExpr {
span: *span,
callee: helper!(object_spread, "objectSpread"),
args,
type_args: Default::default(),
})
});
}
_ => expr,
_ => {}
}
}
}
#[derive(Default)]
struct SpreadVisitor {
found: bool,
}
impl Visit for SpreadVisitor {
noop_visit_type!();
fn visit_spread_element(&mut self, _: &SpreadElement, _: &dyn Node) {
self.found = true;
}
}
impl Check for SpreadVisitor {
fn should_handle(&self) -> bool {
self.found
}
}

View File

@ -1,52 +1,23 @@
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::Check;
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_utils::private_ident;
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit, VisitWith};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
struct OptionalCatchBinding;
pub fn optional_catch_binding() -> impl Fold {
OptionalCatchBinding
pub fn optional_catch_binding() -> impl Fold + VisitMut {
as_folder(OptionalCatchBinding)
}
#[fast_path(ShouldWork)]
impl Fold for OptionalCatchBinding {
noop_fold_type!();
impl VisitMut for OptionalCatchBinding {
noop_visit_mut_type!();
fn fold_catch_clause(&mut self, mut cc: CatchClause) -> CatchClause {
cc = cc.fold_children_with(self);
fn visit_mut_catch_clause(&mut self, cc: &mut CatchClause) {
cc.visit_mut_children_with(self);
if cc.param.is_some() {
return cc;
}
CatchClause {
param: Some(private_ident!("e").into()),
..cc
}
}
}
#[derive(Default)]
struct ShouldWork {
found: bool,
}
impl Visit for ShouldWork {
noop_visit_type!();
fn visit_catch_clause(&mut self, n: &CatchClause, _: &dyn Node) {
if n.param.is_none() {
self.found = true;
return;
}
n.visit_children_with(self)
}
}
impl Check for ShouldWork {
fn should_handle(&self) -> bool {
self.found
cc.param = Some(private_ident!("e").into());
}
}

View File

@ -8,6 +8,7 @@ pub(super) struct ClassNameTdzFolder<'a> {
pub class_name: &'a Ident,
}
/// TODO: VisitMut
impl<'a> Fold for ClassNameTdzFolder<'a> {
noop_fold_type!();

View File

@ -52,6 +52,7 @@ struct ClassProperties {
method_mark: Mark,
}
/// TODO: VisitMut
#[fast_path(ShouldWork)]
impl Fold for ClassProperties {
noop_fold_type!();

View File

@ -129,6 +129,7 @@ macro_rules! take_vars {
};
}
/// TODO: VisitMut
impl<'a> Fold for FieldAccessFolder<'a> {
noop_fold_type!();

View File

@ -5,6 +5,7 @@ pub(super) struct ThisInStaticFolder {
pub ident: Ident,
}
/// TODO: VisitMut
impl Fold for ThisInStaticFolder {
noop_fold_type!();

View File

@ -9,6 +9,7 @@ pub fn export_namespace_from() -> impl Fold {
struct ExportNamespaceFrom;
/// TODO: VisitMut
impl Fold for ExportNamespaceFrom {
noop_fold_type!();

View File

@ -44,6 +44,7 @@ impl NullishCoalescing {
}
}
/// TODO: VisitMut
#[fast_path(ShouldWork)]
impl Fold for NullishCoalescing {
noop_fold_type!();

View File

@ -16,6 +16,7 @@ struct OptChaining {
vars_with_init: Vec<VarDeclarator>,
}
/// TODO: VisitMut
#[fast_path(ShouldWork)]
impl Fold for OptChaining {
noop_fold_type!();
@ -76,8 +77,8 @@ impl OptChaining {
Vec<T>: FoldWith<Self>,
{
// This is to support nested block statements
let old_no_init = mem::replace(&mut self.vars_without_init, vec![]);
let old_init = mem::replace(&mut self.vars_with_init, vec![]);
let old_no_init = mem::take(&mut self.vars_without_init);
let old_init = mem::take(&mut self.vars_with_init);
let mut new: Vec<T> = vec![];

View File

@ -1,11 +1,7 @@
use swc_common::{util::take::Take, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::Check;
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_utils::{alias_ident_for, prepend, ExprFactory};
use swc_ecma_visit::{
as_folder, noop_visit_mut_type, noop_visit_type, Fold, Node, Visit, VisitMut, VisitMutWith,
};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
pub fn logical_assignments() -> impl Fold + VisitMut {
as_folder(Operators::default())
@ -16,7 +12,6 @@ struct Operators {
vars: Vec<VarDeclarator>,
}
#[fast_path(OperatorFinder)]
impl VisitMut for Operators {
noop_visit_mut_type!();
@ -159,22 +154,3 @@ impl VisitMut for Operators {
}
}
}
#[derive(Default)]
struct OperatorFinder {
found: bool,
}
impl Visit for OperatorFinder {
noop_visit_type!();
fn visit_assign_op(&mut self, n: &AssignOp, _: &dyn Node) {
self.found |= *n == op!("||=") || *n == op!("??=");
}
}
impl Check for OperatorFinder {
fn should_handle(&self) -> bool {
self.found
}
}

View File

@ -25,6 +25,7 @@ pub fn member_expression_literals() -> impl Fold {
#[derive(Default, Clone, Copy)]
struct MemberExprLit;
/// TODO: VisitMut
impl Fold for MemberExprLit {
noop_fold_type!();

View File

@ -35,6 +35,7 @@ pub fn property_literals() -> impl Fold {
struct PropertyLiteral;
/// TODO: VisitMut
impl Fold for PropertyLiteral {
noop_fold_type!();

View File

@ -25,6 +25,7 @@ struct ReservedWord {
pub preserve_import: bool,
}
/// TODO: VisitMut
impl Fold for ReservedWord {
noop_fold_type!();

View File

@ -1,10 +1,6 @@
use swc_atoms::{js_word, JsWord};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::Check;
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_visit::{
as_folder, noop_visit_mut_type, noop_visit_type, Fold, Node, Visit, VisitMut, VisitMutWith,
};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
pub fn reserved_words() -> impl 'static + Fold + VisitMut {
as_folder(EsReservedWord)
@ -12,17 +8,11 @@ pub fn reserved_words() -> impl 'static + Fold + VisitMut {
struct EsReservedWord;
#[fast_path(ShouldWork)]
impl VisitMut for EsReservedWord {
noop_visit_mut_type!();
fn visit_mut_export_specifier(&mut self, _n: &mut ExportSpecifier) {}
/// For #[fast_path]
fn visit_mut_expr(&mut self, e: &mut Expr) {
e.visit_mut_children_with(self);
}
fn visit_mut_ident(&mut self, i: &mut Ident) {
rename_ident(&mut i.sym, true);
}
@ -56,11 +46,6 @@ impl VisitMut for EsReservedWord {
fn visit_mut_meta_prop_expr(&mut self, _n: &mut MetaPropExpr) {}
fn visit_mut_prop_name(&mut self, _n: &mut PropName) {}
/// For #[fast_path]
fn visit_mut_stmt(&mut self, s: &mut Stmt) {
s.visit_mut_children_with(self);
}
}
fn is_reserved(sym: &JsWord) -> bool {
@ -117,24 +102,3 @@ fn rename_ident(sym: &mut JsWord, _strict: bool) {
*sym = s;
}
}
#[derive(Default)]
struct ShouldWork {
found: bool,
}
impl Visit for ShouldWork {
noop_visit_type!();
fn visit_ident(&mut self, i: &Ident, _: &dyn Node) {
if is_reserved(&i.sym) {
self.found = true;
return;
}
}
}
impl Check for ShouldWork {
fn should_handle(&self) -> bool {
self.found
}
}

View File

@ -235,7 +235,6 @@ switch (true){
"#,
r#"
var _obj;
function fn() {}
@ -248,6 +247,7 @@ var obj = {
switch (true) {
case true:
var _obj;
(_obj = obj.obj).fn.apply(_obj, _toConsumableArray(args));
break;

View File

@ -67,6 +67,7 @@ pub struct Config {
pub config: util::Config,
}
/// TODO: VisitMut
impl<R> Fold for Amd<R>
where
R: ImportResolver,

View File

@ -66,6 +66,7 @@ where
resolver: Option<(P, FileName)>,
}
/// TODO: VisitMut
impl<P> Fold for CommonJs<P>
where
P: ImportResolver,

View File

@ -13,7 +13,10 @@ pub fn import_analyzer(scope: Rc<RefCell<Scope>>) -> ImportAnalyzer {
pub struct ImportAnalyzer {
scope: Rc<RefCell<Scope>>,
}
/// Inject required helpers methods **for** module transform passes.
///
/// TODO: VisitMut
impl Fold for ImportAnalyzer {
noop_fold_type!();

View File

@ -70,6 +70,7 @@ where
resolver: Option<(R, FileName)>,
}
/// TODO: VisitMut
impl<R> Fold for Umd<R>
where
R: ImportResolver,

View File

@ -79,6 +79,7 @@ struct Scope {
imported: HashMap<JsWord, Arc<Expr>>,
}
/// TODO: VisitMut
impl Fold for ConstModules {
noop_fold_type!();

View File

@ -41,6 +41,7 @@ impl Default for JsonParse {
}
}
/// TODO: VisitMut
impl Fold for JsonParse {
noop_fold_type!();

View File

@ -82,6 +82,7 @@ struct Decorators {
vars: Vec<VarDeclarator>,
}
/// TODO: VisitMut
impl Fold for Decorators {
noop_fold_type!();

View File

@ -81,6 +81,7 @@ impl Visit for Legacy {
}
}
/// TODO: VisitMut
impl Fold for Legacy {
noop_fold_type!();

View File

@ -8,6 +8,7 @@ use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
/// https://github.com/leonardfactory/babel-plugin-transform-typescript-metadata/blob/master/src/parameter/parameterVisitor.ts
pub(super) struct ParamMetadata;
/// TODO: VisitMut
impl Fold for ParamMetadata {
noop_fold_type!();
@ -125,6 +126,7 @@ pub(super) struct Metadata<'a> {
pub(super) class_name: Option<&'a Ident>,
}
/// TODO: VisitMut
impl Fold for Metadata<'_> {
noop_fold_type!();

View File

@ -10,6 +10,7 @@ pub fn export_default_from() -> impl Fold {
struct ExportDefaultFrom;
/// TODO: VisitMut
impl Fold for ExportDefaultFrom {
noop_fold_type!();

View File

@ -7,8 +7,7 @@ use swc_common::{
collections::AHashSet, pass::CompilerPass, util::take::Take, Mark, Spanned, DUMMY_SP,
};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::{pass::JsPass, perf::Check};
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_transforms_base::pass::JsPass;
use swc_ecma_utils::{
default_constructor, ident::IdentLike, prepend, private_ident, quote_ident, ExprFactory, Id,
};
@ -126,7 +125,6 @@ impl PrivateInObject {
}
}
#[fast_path(ShouldWork)]
impl VisitMut for PrivateInObject {
noop_visit_mut_type!();
@ -513,35 +511,3 @@ impl Visit for ClassAnalyzer<'_> {
n.visit_children_with(self);
}
}
#[derive(Default)]
struct ShouldWork {
found: bool,
}
impl Check for ShouldWork {
fn should_handle(&self) -> bool {
self.found
}
}
impl Visit for ShouldWork {
noop_visit_type!();
fn visit_bin_expr(&mut self, e: &BinExpr, _: &dyn Node) {
if e.op == op!("in") && e.left.is_private_name() {
self.found = true;
return;
}
e.visit_children_with(self);
}
fn visit_private_method(&mut self, _: &PrivateMethod, _: &dyn Node) {
self.found = true;
}
fn visit_private_prop(&mut self, _: &PrivateProp, _: &dyn Node) {
self.found = true;
}
}

View File

@ -16,6 +16,7 @@ struct JsxSelf {
dev: bool,
}
/// TODO: VisitMut
impl Fold for JsxSelf {
noop_fold_type!();

View File

@ -16,6 +16,7 @@ struct JsxSrc {
dev: bool,
}
/// TODO: VisitMut
impl Fold for JsxSrc {
noop_fold_type!();

View File

@ -565,7 +565,9 @@ where
}
}
// We let user do /* @refresh reset */ to reset state in the whole file.
/// We let user do /* @refresh reset */ to reset state in the whole file.
///
/// TODO: VisitMut
impl<C: Comments> Fold for Refresh<C> {
fn fold_jsx_opening_element(&mut self, n: JSXOpeningElement) -> JSXOpeningElement {
if let JSXElementName::Ident(ident) = &n.name {

View File

@ -5,7 +5,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_visit"
repository = "https://github.com/swc-project/swc.git"
version = "0.2.6"
version = "0.2.7"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -17,6 +17,10 @@
//!
//! # `Fold`
//!
//! > WARNING: `Fold` is slow, and it's recommended to use VisiMut if you are
//! experienced.
//!
//!
//! `Fold` takes ownership of value, which means you have to return the new
//! value. Returning new value means returning ownership of the value. But you
//! don't have to care about ownership or about managing memories while using