Skip to content

Commit 581aafb

Browse files
authored
perf(visit): Introduce Pass API and adjust visitor APIs for it (#9680)
**Description:** - `Pass`: `FnMut(&mut Program)`. **Breaking Changes:** - `chain!`: Use a tuple instead. You can replace all `chain!(` with `(` with IDE feature and it will work. - `chain!` with 13 or more args: Use nested tuples for items after 13th element. **Related issue:** - Related to #9601
1 parent b32a533 commit 581aafb

File tree

209 files changed

+2496
-2045
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

209 files changed

+2496
-2045
lines changed

.changeset/few-pigs-shout.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
swc_visit: major
3+
swc_common: major
4+
swc_plugin_proxy: major
5+
---
6+
7+
perf(visit): Introduce `Pass` API and adjust visitor APIs for it

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindings/binding_minifier_node/src/minify.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ fn do_work(
184184
let is_mangler_enabled = min_opts.mangle.is_some();
185185

186186
let module = {
187-
let module = module.fold_with(&mut resolver(unresolved_mark, top_level_mark, false));
187+
let module = module.apply(resolver(unresolved_mark, top_level_mark, false));
188188

189189
let mut module = swc_core::ecma::minifier::optimize(
190190
module,

crates/binding_macros/src/wasm.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ pub use swc_common::{
2525
};
2626
use swc_common::{sync::Lrc, FilePathMapping, SourceMap};
2727
#[doc(hidden)]
28+
pub use swc_ecma_ast::noop_pass;
29+
#[doc(hidden)]
2830
pub use swc_ecma_ast::{EsVersion, Program};
2931
#[doc(hidden)]
30-
pub use swc_ecma_transforms::{pass::noop, resolver};
32+
pub use swc_ecma_transforms::resolver;
3133
#[doc(hidden)]
3234
pub use swc_ecma_visit::VisitMutWith;
3335
#[doc(hidden)]
@@ -293,7 +295,7 @@ macro_rules! build_print {
293295
#[macro_export]
294296
macro_rules! build_transform_sync {
295297
($(#[$m:meta])*) => {
296-
build_transform_sync!($(#[$m])*, |_| $crate::wasm::noop(), |_| $crate::wasm::noop(), Default::default());
298+
build_transform_sync!($(#[$m])*, |_| $crate::wasm::noop_pass(), |_| $crate::wasm::noop_pass(), Default::default());
297299
};
298300
($(#[$m:meta])*, $before_pass: expr, $after_pass: expr) => {
299301
build_transform_sync!($(#[$m])*, $before_pass, $after_pass, Default::default());

crates/swc/benches/typescript.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use swc_compiler_base::PrintArgs;
1414
use swc_ecma_ast::{EsVersion, Program};
1515
use swc_ecma_parser::Syntax;
1616
use swc_ecma_transforms::{fixer, resolver, typescript};
17-
use swc_ecma_visit::FoldWith;
1817

1918
static SOURCE: &str = include_str!("assets/Observable.ts");
2019

@@ -52,8 +51,8 @@ fn as_es(c: &swc::Compiler) -> Program {
5251
let top_level_mark = Mark::new();
5352

5453
program
55-
.fold_with(&mut resolver(unresolved_mark, top_level_mark, true))
56-
.fold_with(&mut typescript::strip(unresolved_mark, top_level_mark))
54+
.apply(&mut resolver(unresolved_mark, top_level_mark, true))
55+
.apply(&mut typescript::strip(unresolved_mark, top_level_mark))
5756
}
5857

5958
fn base_tr_group(c: &mut Criterion) {
@@ -73,7 +72,7 @@ fn base_tr_fixer(b: &mut Bencher) {
7372
GLOBALS.set(&Default::default(), || {
7473
let handler = Handler::with_emitter_writer(Box::new(stderr()), Some(c.cm.clone()));
7574
black_box(c.run_transform(&handler, true, || {
76-
module.clone().fold_with(&mut fixer(Some(c.comments())))
75+
module.clone().apply(&mut fixer(Some(c.comments())))
7776
}))
7877
})
7978
});

crates/swc/src/builder.rs

+46-50
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ use either::Either;
55
use rustc_hash::FxHashMap;
66
use swc_atoms::JsWord;
77
use swc_common::{
8-
chain, comments::Comments, errors::Handler, sync::Lrc, util::take::Take, FileName, Mark,
9-
SourceMap,
8+
comments::Comments, errors::Handler, sync::Lrc, util::take::Take, FileName, Mark, SourceMap,
109
};
11-
use swc_ecma_ast::{EsVersion, Module, Script};
10+
use swc_ecma_ast::{EsVersion, Module, Pass, Script};
1211
use swc_ecma_minifier::option::{terser::TerserTopLevelOptions, MinifyOptions};
1312
use swc_ecma_parser::Syntax;
1413
use swc_ecma_transforms::{
@@ -19,15 +18,15 @@ use swc_ecma_transforms::{
1918
hygiene::{self, hygiene_with_config},
2019
modules::{self, path::ImportResolver},
2120
optimization::const_modules,
22-
pass::Optional,
2321
resolver, Assumptions,
2422
};
25-
use swc_ecma_visit::{as_folder, noop_visit_mut_type, VisitMut, VisitMutWith};
23+
use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
24+
use swc_visit::Optional;
2625

2726
use crate::config::{GlobalPassOption, JsMinifyOptions, ModuleConfig};
2827

2928
/// Builder is used to create a high performance `Compiler`.
30-
pub struct PassBuilder<'a, 'b, P: swc_ecma_visit::Fold> {
29+
pub struct PassBuilder<'a, 'b, P: Pass> {
3130
cm: &'a Arc<SourceMap>,
3231
handler: &'b Handler,
3332
env: Option<swc_ecma_preset_env::Config>,
@@ -48,7 +47,7 @@ pub struct PassBuilder<'a, 'b, P: swc_ecma_visit::Fold> {
4847
regenerator: regenerator::Config,
4948
}
5049

51-
impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
50+
impl<'a, 'b, P: Pass> PassBuilder<'a, 'b, P> {
5251
pub fn new(
5352
cm: &'a Arc<SourceMap>,
5453
handler: &'b Handler,
@@ -76,11 +75,11 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
7675
}
7776
}
7877

79-
pub fn then<N>(self, next: N) -> PassBuilder<'a, 'b, swc_visit::AndThen<P, N>>
78+
pub fn then<N>(self, next: N) -> PassBuilder<'a, 'b, (P, N)>
8079
where
81-
N: swc_ecma_visit::Fold,
80+
N: Pass,
8281
{
83-
let pass = chain!(self.pass, next);
82+
let pass = (self.pass, next);
8483
PassBuilder {
8584
cm: self.cm,
8685
handler: self.handler,
@@ -126,15 +125,12 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
126125
pub fn const_modules(
127126
self,
128127
globals: FxHashMap<JsWord, FxHashMap<JsWord, String>>,
129-
) -> PassBuilder<'a, 'b, impl swc_ecma_visit::Fold> {
128+
) -> PassBuilder<'a, 'b, (P, impl Pass)> {
130129
let cm = self.cm.clone();
131130
self.then(const_modules(cm, globals))
132131
}
133132

134-
pub fn inline_globals(
135-
self,
136-
c: GlobalPassOption,
137-
) -> PassBuilder<'a, 'b, impl swc_ecma_visit::Fold> {
133+
pub fn inline_globals(self, c: GlobalPassOption) -> PassBuilder<'a, 'b, (P, impl Pass)> {
138134
let pass = c.build(self.cm, self.handler);
139135
self.then(pass)
140136
}
@@ -172,7 +168,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
172168
module: Option<ModuleConfig>,
173169
comments: Option<&'cmt dyn Comments>,
174170
resolver: Option<(FileName, Arc<dyn ImportResolver>)>,
175-
) -> impl 'cmt + swc_ecma_visit::Fold
171+
) -> impl 'cmt + Pass
176172
where
177173
P: 'cmt,
178174
{
@@ -206,7 +202,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
206202

207203
feature_flag = enable_available_feature_from_es_version(self.target);
208204

209-
Either::Right(chain!(
205+
Either::Right((
210206
Optional::new(
211207
compat::class_fields_use_set::class_fields_use_set(assumptions.pure_getters),
212208
assumptions.set_public_class_fields,
@@ -221,60 +217,60 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
221217
no_document_all: assumptions.no_document_all,
222218
static_blocks_mark: Mark::new(),
223219
pure_getter: assumptions.pure_getters,
224-
}
220+
},
225221
},
226-
self.unresolved_mark
222+
self.unresolved_mark,
227223
),
228-
should_enable(self.target, EsVersion::Es2022)
224+
should_enable(self.target, EsVersion::Es2022),
229225
),
230226
Optional::new(
231227
compat::es2021::es2021(),
232-
should_enable(self.target, EsVersion::Es2021)
228+
should_enable(self.target, EsVersion::Es2021),
233229
),
234230
Optional::new(
235231
compat::es2020::es2020(
236232
compat::es2020::Config {
237233
nullish_coalescing: compat::es2020::nullish_coalescing::Config {
238-
no_document_all: assumptions.no_document_all
234+
no_document_all: assumptions.no_document_all,
239235
},
240236
optional_chaining: compat::es2020::optional_chaining::Config {
241237
no_document_all: assumptions.no_document_all,
242-
pure_getter: assumptions.pure_getters
243-
}
238+
pure_getter: assumptions.pure_getters,
239+
},
244240
},
245-
self.unresolved_mark
241+
self.unresolved_mark,
246242
),
247-
should_enable(self.target, EsVersion::Es2020)
243+
should_enable(self.target, EsVersion::Es2020),
248244
),
249245
Optional::new(
250246
compat::es2019::es2019(),
251-
should_enable(self.target, EsVersion::Es2019)
247+
should_enable(self.target, EsVersion::Es2019),
252248
),
253249
Optional::new(
254250
compat::es2018(compat::es2018::Config {
255251
object_rest_spread: compat::es2018::object_rest_spread::Config {
256252
no_symbol: assumptions.object_rest_no_symbols,
257253
set_property: assumptions.set_spread_properties,
258-
pure_getters: assumptions.pure_getters
259-
}
254+
pure_getters: assumptions.pure_getters,
255+
},
260256
}),
261-
should_enable(self.target, EsVersion::Es2018)
257+
should_enable(self.target, EsVersion::Es2018),
262258
),
263259
Optional::new(
264260
compat::es2017(
265261
compat::es2017::Config {
266262
async_to_generator: compat::es2017::async_to_generator::Config {
267263
ignore_function_name: assumptions.ignore_function_name,
268-
ignore_function_length: assumptions.ignore_function_length
264+
ignore_function_length: assumptions.ignore_function_length,
269265
},
270266
},
271-
self.unresolved_mark
267+
self.unresolved_mark,
272268
),
273-
should_enable(self.target, EsVersion::Es2017)
269+
should_enable(self.target, EsVersion::Es2017),
274270
),
275271
Optional::new(
276272
compat::es2016(),
277-
should_enable(self.target, EsVersion::Es2016)
273+
should_enable(self.target, EsVersion::Es2016),
278274
),
279275
Optional::new(
280276
compat::es2015(
@@ -286,36 +282,36 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
286282
no_class_calls: assumptions.no_class_calls,
287283
set_class_methods: assumptions.set_class_methods,
288284
super_is_callable_constructor: assumptions
289-
.super_is_callable_constructor
285+
.super_is_callable_constructor,
290286
},
291287
computed_props: compat::es2015::computed_props::Config {
292-
loose: self.loose
288+
loose: self.loose,
293289
},
294290
for_of: compat::es2015::for_of::Config {
295291
assume_array: false,
296-
loose: self.loose
292+
loose: self.loose,
297293
},
298294
spread: compat::es2015::spread::Config { loose: self.loose },
299295
destructuring: compat::es2015::destructuring::Config {
300-
loose: self.loose
296+
loose: self.loose,
301297
},
302298
regenerator: self.regenerator,
303299
template_literal: compat::es2015::template_literal::Config {
304300
ignore_to_primitive: assumptions.ignore_to_primitive_hint,
305-
mutable_template: assumptions.mutable_template_object
301+
mutable_template: assumptions.mutable_template_object,
306302
},
307303
parameters: compat::es2015::parameters::Config {
308304
ignore_function_length: assumptions.ignore_function_length,
309305
},
310-
typescript: syntax.typescript()
311-
}
306+
typescript: syntax.typescript(),
307+
},
312308
),
313-
should_enable(self.target, EsVersion::Es2015)
309+
should_enable(self.target, EsVersion::Es2015),
314310
),
315311
Optional::new(
316312
compat::es3(true),
317-
cfg!(feature = "es3") && self.target == EsVersion::Es3
318-
)
313+
cfg!(feature = "es3") && self.target == EsVersion::Es3,
314+
),
319315
))
320316
};
321317

@@ -325,21 +321,21 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
325321
.map(|v| v.mangle.is_obj() || v.mangle.is_true())
326322
.unwrap_or(false);
327323

328-
chain!(
324+
(
329325
self.pass,
330326
Optional::new(
331327
paren_remover(comments.map(|v| v as &dyn Comments)),
332-
self.fixer
328+
self.fixer,
333329
),
334330
compat_pass,
335331
// module / helper
336332
Optional::new(
337333
modules::import_analysis::import_analyzer(import_interop, ignore_dynamic),
338-
need_analyzer
334+
need_analyzer,
339335
),
340336
Optional::new(
341337
helpers::inject_helpers(self.unresolved_mark),
342-
self.inject_helpers
338+
self.inject_helpers,
343339
),
344340
ModuleConfig::build(
345341
self.cm.clone(),
@@ -349,7 +345,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
349345
feature_flag,
350346
resolver,
351347
),
352-
as_folder(MinifierPass {
348+
visit_mut_pass(MinifierPass {
353349
options: self.minify,
354350
cm: self.cm.clone(),
355351
comments,
@@ -360,7 +356,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
360356
top_level_mark: self.top_level_mark,
361357
..self.hygiene.clone().unwrap_or_default()
362358
}),
363-
self.hygiene.is_some() && !is_mangler_enabled
359+
self.hygiene.is_some() && !is_mangler_enabled,
364360
),
365361
Optional::new(fixer(comments.map(|v| v as &dyn Comments)), self.fixer),
366362
)

0 commit comments

Comments
 (0)