mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 13:38:33 +03:00
fix(es/transforms/compat): Improve performance (#1673)
swc_ecma_transforms_compat: - `classes`: Fast-path. - `destructuring`: Fast-path. - `sticky_regex`: Fast-path. - `spread`: Fast-path. - `shorthand`: Fast-path. - `typeof_symbol`: Fast-path. - `block_scoped_functions`: Fast path. - `duplicate_keys`: Use fxhash. - `instance_of`: Fast path. - `reserved_words`: Make string comparison efficient.
This commit is contained in:
parent
9381d0dbc2
commit
2ad0af9e91
@ -1,3 +1,13 @@
|
||||
//! [JsWord] is an interened string.
|
||||
//!
|
||||
//! This type should be used instead of [String] for values, because lots of
|
||||
//! values are duplicated. For example, if an identifer is named `myVariable`,
|
||||
//! there will be lots of identifier usages with the value `myVariable`.
|
||||
//!
|
||||
//! This type
|
||||
//! - makes equality comparison faster.
|
||||
//! - reduces memory usage.
|
||||
|
||||
#![allow(clippy::unreadable_literal)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/js_word.rs"));
|
||||
|
@ -63,7 +63,20 @@ impl Globals {
|
||||
}
|
||||
}
|
||||
|
||||
// scoped_thread_local!(pub static GLOBALS: Globals);
|
||||
/// Storage for span hygiene data.
|
||||
///
|
||||
/// This variable is used to manage identifiers or to identify nodes.
|
||||
/// Note that it's stored as a thread-local storage, but actually it's shared
|
||||
/// between threads.
|
||||
///
|
||||
/// # Usages
|
||||
///
|
||||
/// ## Span hygiene
|
||||
///
|
||||
/// [Mark]s are stored in this variable.
|
||||
///
|
||||
/// You can see the document how swc uses the span hygiene info at
|
||||
/// https://rustdoc.swc.rs/swc_ecma_transforms_base/resolver/fn.resolver_with_mark.html
|
||||
pub static GLOBALS: ::scoped_tls::ScopedKey<Globals> = ::scoped_tls::ScopedKey {
|
||||
inner: {
|
||||
thread_local!(static FOO: ::std::cell::Cell<usize> = {
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use swc_common::comments::SingleThreadedComments;
|
||||
use swc_common::FileName;
|
||||
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax};
|
||||
use test::Bencher;
|
||||
@ -71,97 +72,21 @@ fn yui(b: &mut Bencher) {
|
||||
bench_module(b, Default::default(), include_str!("./files/yui-3.12.0.js"))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn colors_ts(b: &mut Bencher) {
|
||||
// Copied from ratel-rust
|
||||
bench_module(
|
||||
b,
|
||||
Syntax::Typescript(Default::default()),
|
||||
include_str!("../colors.js"),
|
||||
)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn angular_ts(b: &mut Bencher) {
|
||||
bench_module(
|
||||
b,
|
||||
Syntax::Typescript(Default::default()),
|
||||
include_str!("./files/angular-1.2.5.js"),
|
||||
)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn backbone_ts(b: &mut Bencher) {
|
||||
bench_module(
|
||||
b,
|
||||
Syntax::Typescript(Default::default()),
|
||||
include_str!("./files/backbone-1.1.0.js"),
|
||||
)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn jquery_ts(b: &mut Bencher) {
|
||||
bench_module(
|
||||
b,
|
||||
Syntax::Typescript(Default::default()),
|
||||
include_str!("./files/jquery-1.9.1.js"),
|
||||
)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn jquery_mobile_ts(b: &mut Bencher) {
|
||||
bench_module(
|
||||
b,
|
||||
Syntax::Typescript(Default::default()),
|
||||
include_str!("./files/jquery.mobile-1.4.2.js"),
|
||||
)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn mootools_ts(b: &mut Bencher) {
|
||||
bench_module(
|
||||
b,
|
||||
Syntax::Typescript(Default::default()),
|
||||
include_str!("./files/mootools-1.4.5.js"),
|
||||
)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn underscore_ts(b: &mut Bencher) {
|
||||
bench_module(
|
||||
b,
|
||||
Syntax::Typescript(Default::default()),
|
||||
include_str!("./files/underscore-1.5.2.js"),
|
||||
)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn yui_ts(b: &mut Bencher) {
|
||||
bench_module(
|
||||
b,
|
||||
Syntax::Typescript(Default::default()),
|
||||
include_str!("./files/yui-3.12.0.js"),
|
||||
)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn large(b: &mut Bencher) {
|
||||
bench_module(
|
||||
b,
|
||||
Syntax::Typescript(Default::default()),
|
||||
include_str!("../../codegen/benches/large-partial.js"),
|
||||
)
|
||||
}
|
||||
|
||||
fn bench_module(b: &mut Bencher, syntax: Syntax, src: &'static str) {
|
||||
b.bytes = src.len() as _;
|
||||
|
||||
let _ = ::testing::run_test(false, |cm, _| {
|
||||
let comments = SingleThreadedComments::default();
|
||||
let fm = cm.new_source_file(FileName::Anon, src.into());
|
||||
|
||||
b.iter(|| {
|
||||
let _ = test::black_box({
|
||||
let lexer = Lexer::new(syntax, Default::default(), StringInput::from(&*fm), None);
|
||||
let lexer = Lexer::new(
|
||||
syntax,
|
||||
Default::default(),
|
||||
StringInput::from(&*fm),
|
||||
Some(&comments),
|
||||
);
|
||||
let mut parser = Parser::new_from(lexer);
|
||||
parser.parse_module()
|
||||
});
|
||||
|
@ -60,7 +60,12 @@ macro_rules! add_to {
|
||||
}};
|
||||
}
|
||||
|
||||
scoped_thread_local!(pub static HELPERS: Helpers);
|
||||
scoped_thread_local!(
|
||||
/// This variable is used to manage helper scripts like `_inherits` from babel.
|
||||
///
|
||||
/// The instance contains flags where each flag denotes if a helper script should be injected.
|
||||
pub static HELPERS: Helpers
|
||||
);
|
||||
|
||||
/// Tracks used helper methods. (e.g. __extends)
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -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.16.1"
|
||||
version = "0.16.2"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
@ -1,6 +1,12 @@
|
||||
use swc_common::{Spanned, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::perf::Check;
|
||||
use swc_ecma_transforms_macros::fast_path;
|
||||
use swc_ecma_utils::UsageFinder;
|
||||
use swc_ecma_visit::noop_visit_type;
|
||||
use swc_ecma_visit::Node;
|
||||
use swc_ecma_visit::Visit;
|
||||
use swc_ecma_visit::VisitWith;
|
||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
||||
|
||||
pub fn block_scoped_functions() -> impl Fold {
|
||||
@ -10,6 +16,7 @@ pub fn block_scoped_functions() -> impl Fold {
|
||||
#[derive(Clone, Copy)]
|
||||
struct BlockScopedFns;
|
||||
|
||||
#[fast_path(BlockScopedFnFinder)]
|
||||
impl Fold for BlockScopedFns {
|
||||
noop_fold_type!();
|
||||
|
||||
@ -61,6 +68,32 @@ impl Fold for BlockScopedFns {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BlockScopedFnFinder {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl Visit for BlockScopedFnFinder {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_stmts(&mut self, stmts: &[Stmt], _: &dyn Node) {
|
||||
for n in stmts {
|
||||
n.visit_with(&Invalid { span: DUMMY_SP }, self);
|
||||
}
|
||||
|
||||
self.found |= stmts.iter().any(|stmt| match stmt {
|
||||
Stmt::Decl(Decl::Fn(..)) => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Check for BlockScopedFnFinder {
|
||||
fn should_handle(&self) -> bool {
|
||||
self.found
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -13,6 +13,8 @@ use swc_common::{Mark, Spanned, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::helper;
|
||||
use swc_ecma_transforms_base::native::is_native;
|
||||
use swc_ecma_transforms_base::perf::Check;
|
||||
use swc_ecma_transforms_macros::fast_path;
|
||||
use swc_ecma_utils::quote_expr;
|
||||
use swc_ecma_utils::quote_str;
|
||||
use swc_ecma_utils::{
|
||||
@ -187,6 +189,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[fast_path(ClassFinder)]
|
||||
impl<C> Fold for Classes<C>
|
||||
where
|
||||
C: Comments,
|
||||
@ -202,26 +205,6 @@ where
|
||||
}
|
||||
|
||||
fn fold_decl(&mut self, n: Decl) -> Decl {
|
||||
fn should_work(node: &Decl) -> bool {
|
||||
struct Visitor {
|
||||
found: bool,
|
||||
}
|
||||
impl Visit for Visitor {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_class(&mut self, _: &Class, _: &dyn Node) {
|
||||
self.found = true
|
||||
}
|
||||
}
|
||||
let mut v = Visitor { found: false };
|
||||
node.visit_with(&Invalid { span: DUMMY_SP } as _, &mut v);
|
||||
v.found
|
||||
}
|
||||
// fast path
|
||||
if !should_work(&n) {
|
||||
return n;
|
||||
}
|
||||
|
||||
let n = match n {
|
||||
Decl::Class(decl) => Decl::Var(self.fold_class_as_var_decl(decl.ident, decl.class)),
|
||||
_ => n,
|
||||
@ -968,3 +951,22 @@ fn escape_keywords(mut e: Box<Expr>) -> Box<Expr> {
|
||||
|
||||
e
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ClassFinder {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl Visit for ClassFinder {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_class(&mut self, _: &Class, _: &dyn Node) {
|
||||
self.found = true
|
||||
}
|
||||
}
|
||||
|
||||
impl Check for ClassFinder {
|
||||
fn should_handle(&self) -> bool {
|
||||
self.found
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ use std::iter;
|
||||
use swc_common::{Spanned, SyntaxContext, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::helper;
|
||||
use swc_ecma_transforms_base::perf::Check;
|
||||
use swc_ecma_transforms_macros::fast_path;
|
||||
use swc_ecma_utils::alias_ident_for;
|
||||
use swc_ecma_utils::alias_if_required;
|
||||
use swc_ecma_utils::has_rest_pat;
|
||||
@ -454,6 +456,7 @@ impl AssignFolder {
|
||||
}
|
||||
}
|
||||
|
||||
#[fast_path(DestructuringVisitor)]
|
||||
impl Fold for Destructuring {
|
||||
noop_fold_type!();
|
||||
|
||||
@ -527,6 +530,7 @@ struct AssignFolder {
|
||||
ignore_return_value: Option<()>,
|
||||
}
|
||||
|
||||
#[fast_path(DestructuringVisitor)]
|
||||
impl Fold for AssignFolder {
|
||||
noop_fold_type!();
|
||||
|
||||
@ -1129,6 +1133,7 @@ where
|
||||
v.found
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct DestructuringVisitor {
|
||||
found: bool,
|
||||
}
|
||||
@ -1144,3 +1149,9 @@ impl Visit for DestructuringVisitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Check for DestructuringVisitor {
|
||||
fn should_handle(&self) -> bool {
|
||||
self.found
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::collections::HashSet;
|
||||
use fxhash::FxHashSet;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::Spanned;
|
||||
use swc_ecma_ast::*;
|
||||
@ -34,8 +34,8 @@ impl Fold for DuplicateKeys {
|
||||
|
||||
#[derive(Default)]
|
||||
struct PropFolder {
|
||||
getter_props: HashSet<JsWord>,
|
||||
setter_props: HashSet<JsWord>,
|
||||
getter_props: FxHashSet<JsWord>,
|
||||
setter_props: FxHashSet<JsWord>,
|
||||
}
|
||||
|
||||
impl Fold for PropFolder {
|
||||
@ -85,7 +85,7 @@ impl Fold for PropFolder {
|
||||
}
|
||||
|
||||
struct PropNameFolder<'a> {
|
||||
props: &'a mut HashSet<JsWord>,
|
||||
props: &'a mut FxHashSet<JsWord>,
|
||||
}
|
||||
impl<'a> Fold for PropNameFolder<'a> {
|
||||
noop_fold_type!();
|
||||
|
@ -1,6 +1,7 @@
|
||||
use swc_common::DUMMY_SP;
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::helper;
|
||||
use swc_ecma_transforms_base::perf::Check;
|
||||
use swc_ecma_transforms_macros::fast_path;
|
||||
use swc_ecma_utils::ExprFactory;
|
||||
use swc_ecma_visit::noop_visit_type;
|
||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith, Node, Visit, VisitWith};
|
||||
@ -35,32 +36,11 @@ pub fn instance_of() -> impl Fold {
|
||||
}
|
||||
struct InstanceOf;
|
||||
|
||||
#[fast_path(InstnaceOfFinder)]
|
||||
impl Fold for InstanceOf {
|
||||
noop_fold_type!();
|
||||
|
||||
fn fold_expr(&mut self, expr: Expr) -> Expr {
|
||||
fn should_work(node: &Expr) -> bool {
|
||||
struct Visitor {
|
||||
found: bool,
|
||||
}
|
||||
impl Visit for Visitor {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_bin_expr(&mut self, e: &BinExpr, _: &dyn Node) {
|
||||
if e.op == op!("instanceof") {
|
||||
self.found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut v = Visitor { found: false };
|
||||
node.visit_with(&Invalid { span: DUMMY_SP } as _, &mut v);
|
||||
v.found
|
||||
}
|
||||
// fast path
|
||||
if !should_work(&expr) {
|
||||
return expr;
|
||||
}
|
||||
|
||||
let expr = expr.fold_children_with(self);
|
||||
|
||||
match expr {
|
||||
@ -79,3 +59,26 @@ impl Fold for InstanceOf {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,11 @@
|
||||
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_visit_type;
|
||||
use swc_ecma_visit::Node;
|
||||
use swc_ecma_visit::Visit;
|
||||
use swc_ecma_visit::VisitWith;
|
||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
||||
|
||||
/// Compile ES2015 shorthand properties to ES5
|
||||
@ -43,6 +49,7 @@ pub fn shorthand() -> impl 'static + Fold {
|
||||
#[derive(Clone, Copy)]
|
||||
struct Shorthand;
|
||||
|
||||
#[fast_path(ShorthandFinder)]
|
||||
impl Fold for Shorthand {
|
||||
noop_fold_type!();
|
||||
|
||||
@ -66,6 +73,27 @@ impl Fold for Shorthand {
|
||||
}
|
||||
}
|
||||
|
||||
#[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::*;
|
||||
|
@ -5,6 +5,8 @@ use swc_common::{util::move_map::MoveMap, Span, Spanned, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::ext::ExprRefExt;
|
||||
use swc_ecma_transforms_base::helper;
|
||||
use swc_ecma_transforms_base::perf::Check;
|
||||
use swc_ecma_transforms_macros::fast_path;
|
||||
use swc_ecma_utils::alias_ident_for;
|
||||
use swc_ecma_utils::is_literal;
|
||||
use swc_ecma_utils::member_expr;
|
||||
@ -13,6 +15,10 @@ use swc_ecma_utils::quote_ident;
|
||||
use swc_ecma_utils::undefined;
|
||||
use swc_ecma_utils::ExprFactory;
|
||||
use swc_ecma_utils::StmtLike;
|
||||
use swc_ecma_visit::noop_visit_type;
|
||||
use swc_ecma_visit::Node;
|
||||
use swc_ecma_visit::Visit;
|
||||
use swc_ecma_visit::VisitWith;
|
||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
||||
|
||||
pub fn spread(c: Config) -> impl Fold {
|
||||
@ -37,6 +43,7 @@ struct ActualFolder {
|
||||
vars: Vec<VarDeclarator>,
|
||||
}
|
||||
|
||||
#[fast_path(SpreadFinder)]
|
||||
impl Fold for Spread {
|
||||
noop_fold_type!();
|
||||
|
||||
@ -75,6 +82,7 @@ impl Spread {
|
||||
}
|
||||
}
|
||||
|
||||
#[fast_path(SpreadFinder)]
|
||||
impl Fold for ActualFolder {
|
||||
noop_fold_type!();
|
||||
|
||||
@ -455,3 +463,24 @@ 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
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,13 @@
|
||||
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;
|
||||
use swc_ecma_utils::ExprFactory;
|
||||
use swc_ecma_visit::noop_visit_type;
|
||||
use swc_ecma_visit::Node;
|
||||
use swc_ecma_visit::Visit;
|
||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
||||
|
||||
/// Compile ES2015 sticky regex to an ES5 RegExp constructor
|
||||
@ -26,6 +31,7 @@ pub fn sticky_regex() -> impl 'static + Fold {
|
||||
#[derive(Clone, Copy)]
|
||||
struct StickyRegex;
|
||||
|
||||
#[fast_path(StickyRegexVisitor)]
|
||||
impl Fold for StickyRegex {
|
||||
noop_fold_type!();
|
||||
|
||||
@ -61,6 +67,25 @@ impl Fold for StickyRegex {
|
||||
}
|
||||
}
|
||||
|
||||
#[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::*;
|
||||
|
@ -1,7 +1,8 @@
|
||||
use swc_atoms::js_word;
|
||||
use swc_common::DUMMY_SP;
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::helper;
|
||||
use swc_ecma_transforms_base::perf::Check;
|
||||
use swc_ecma_transforms_macros::fast_path;
|
||||
use swc_ecma_utils::ExprFactory;
|
||||
use swc_ecma_visit::noop_visit_type;
|
||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith, Node, Visit, VisitWith};
|
||||
@ -13,15 +14,11 @@ pub fn typeof_symbol() -> impl Fold {
|
||||
#[derive(Clone)]
|
||||
struct TypeOfSymbol;
|
||||
|
||||
#[fast_path(TypeOfFinder)]
|
||||
impl Fold for TypeOfSymbol {
|
||||
noop_fold_type!();
|
||||
|
||||
fn fold_expr(&mut self, expr: Expr) -> Expr {
|
||||
// fast path
|
||||
if !should_work(&expr) {
|
||||
return expr;
|
||||
}
|
||||
|
||||
let expr = expr.fold_children_with(self);
|
||||
|
||||
match expr {
|
||||
@ -71,22 +68,27 @@ impl Fold for TypeOfSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_work(node: &Expr) -> bool {
|
||||
struct Visitor {
|
||||
found: bool,
|
||||
}
|
||||
impl Visit for Visitor {
|
||||
noop_visit_type!();
|
||||
#[derive(Default)]
|
||||
struct TypeOfFinder {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
fn visit_unary_expr(&mut self, e: &UnaryExpr, _: &dyn Node) {
|
||||
if e.op == op!("typeof") {
|
||||
self.found = true
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
let mut v = Visitor { found: false };
|
||||
node.visit_with(&Invalid { span: DUMMY_SP } as _, &mut v);
|
||||
v.found
|
||||
}
|
||||
|
||||
impl Check for TypeOfFinder {
|
||||
fn should_handle(&self) -> bool {
|
||||
self.found
|
||||
}
|
||||
}
|
||||
|
||||
fn is_non_symbol_literal(e: &Expr) -> bool {
|
||||
|
@ -55,12 +55,47 @@ impl VisitMut for EsReservedWord {
|
||||
}
|
||||
|
||||
fn is_reserved(sym: &JsWord) -> bool {
|
||||
match &**sym {
|
||||
"enum" | "implements" | "package" | "protected" | "interface" | "private" | "public"
|
||||
| "await" | "break" | "case" | "catch" | "class" | "const" | "continue" | "debugger"
|
||||
| "default" | "delete" | "do" | "else" | "export" | "extends" | "finally" | "for"
|
||||
| "function" | "if" | "in" | "instanceof" | "new" | "return" | "super" | "switch"
|
||||
| "this" | "throw" | "try" | "typeof" | "var" | "void" | "while" | "with" | "yield" => true,
|
||||
match *sym {
|
||||
js_word!("enum")
|
||||
| js_word!("implements")
|
||||
| js_word!("package")
|
||||
| js_word!("protected")
|
||||
| js_word!("interface")
|
||||
| js_word!("private")
|
||||
| js_word!("public")
|
||||
| js_word!("await")
|
||||
| js_word!("break")
|
||||
| js_word!("case")
|
||||
| js_word!("catch")
|
||||
| js_word!("class")
|
||||
| js_word!("const")
|
||||
| js_word!("continue")
|
||||
| js_word!("debugger")
|
||||
| js_word!("default")
|
||||
| js_word!("delete")
|
||||
| js_word!("do")
|
||||
| js_word!("else")
|
||||
| js_word!("export")
|
||||
| js_word!("extends")
|
||||
| js_word!("finally")
|
||||
| js_word!("for")
|
||||
| js_word!("function")
|
||||
| js_word!("if")
|
||||
| js_word!("in")
|
||||
| js_word!("instanceof")
|
||||
| js_word!("new")
|
||||
| js_word!("return")
|
||||
| js_word!("super")
|
||||
| js_word!("switch")
|
||||
| js_word!("this")
|
||||
| js_word!("throw")
|
||||
| js_word!("try")
|
||||
| js_word!("typeof")
|
||||
| js_word!("var")
|
||||
| js_word!("void")
|
||||
| js_word!("while")
|
||||
| js_word!("with")
|
||||
| js_word!("yield") => true,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
|
@ -1701,8 +1701,10 @@ impl<'a> UsageFinder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Used for error reporting in transform.
|
||||
scoped_thread_local!(pub static HANDLER: Handler);
|
||||
scoped_thread_local!(
|
||||
/// Used for error reporting in transform.
|
||||
pub static HANDLER: Handler
|
||||
);
|
||||
|
||||
/// make a new expression which evaluates `val` preserving side effects, if any.
|
||||
pub fn preserve_effects<I>(span: Span, val: Expr, exprs: I) -> Expr
|
||||
|
Loading…
Reference in New Issue
Block a user