Skip to content

Commit ac7d6e1

Browse files
committed
refactor(es/ast): Remove Hash from ECMA AST nodes
1 parent 062c608 commit ac7d6e1

24 files changed

Lines changed: 405 additions & 409 deletions

File tree

.changeset/remove-ecma-ast-hash.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
swc_bundler: major
3+
swc_core: major
4+
swc_ecma_ast: major
5+
swc_ecma_lints: major
6+
swc_ecma_minifier: major
7+
swc_ecma_parser: major
8+
---
9+
10+
refactor(es/ast): Remove `Hash` implementations from ECMA AST nodes

crates/swc_bundler/src/bundler/export.rs

Lines changed: 82 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use indexmap::IndexMap;
22
use rustc_hash::FxBuildHasher;
3-
use swc_atoms::{atom, Atom};
4-
use swc_common::{FileName, SyntaxContext};
3+
use swc_atoms::{atom, Atom, Wtf8Atom};
4+
use swc_common::{FileName, Span, SyntaxContext};
55
use swc_ecma_ast::*;
66
use swc_ecma_utils::find_pat_ids;
77
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
@@ -42,8 +42,71 @@ where
4242

4343
#[derive(Debug, Default)]
4444
pub(super) struct RawExports {
45-
/// Key is None if it's exported from the module itself.
46-
pub items: IndexMap<Option<Str>, Vec<Specifier>, FxBuildHasher>,
45+
/// Exports declared by the module itself.
46+
pub items: Vec<Specifier>,
47+
48+
/// Exports forwarded from exactly matching source nodes, in declaration
49+
/// order.
50+
pub reexports: IndexMap<RawExportSource, Vec<Specifier>, FxBuildHasher>,
51+
}
52+
53+
impl RawExports {
54+
/// Returns the group for an exactly matching source node.
55+
///
56+
/// A private key preserves ordered-map performance and semantics without
57+
/// requiring [`Str`] to implement `Hash`.
58+
fn reexports_for(&mut self, src: Str) -> &mut Vec<Specifier> {
59+
self.reexports.entry(src.into()).or_default()
60+
}
61+
}
62+
63+
/// Hashable representation used only by the bundler's export index.
64+
///
65+
/// Exhaustive conversions ensure this key stays aligned with [`Str`] if the
66+
/// AST node gains or loses fields.
67+
#[derive(Debug, PartialEq, Eq, Hash)]
68+
pub(super) struct RawExportSource {
69+
span: Span,
70+
value: Wtf8Atom,
71+
raw: Option<Atom>,
72+
}
73+
74+
impl From<Str> for RawExportSource {
75+
fn from(src: Str) -> Self {
76+
let Str { span, value, raw } = src;
77+
78+
Self { span, value, raw }
79+
}
80+
}
81+
82+
impl From<RawExportSource> for Str {
83+
fn from(src: RawExportSource) -> Self {
84+
let RawExportSource { span, value, raw } = src;
85+
86+
Self { span, value, raw }
87+
}
88+
}
89+
90+
#[cfg(test)]
91+
mod tests {
92+
use swc_common::DUMMY_SP;
93+
94+
use super::*;
95+
96+
#[test]
97+
fn groups_identical_reexport_sources() {
98+
let src = Str {
99+
span: DUMMY_SP,
100+
value: "dependency".into(),
101+
raw: None,
102+
};
103+
let mut exports = RawExports::default();
104+
105+
let _ = exports.reexports_for(src.clone());
106+
let _ = exports.reexports_for(src);
107+
108+
assert_eq!(exports.reexports.len(), 1);
109+
}
47110
}
48111

49112
#[derive(Debug, Default)]
@@ -151,7 +214,7 @@ where
151214
// return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
152215
// }
153216
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(decl)) => {
154-
let v = self.info.items.entry(None).or_default();
217+
let v = &mut self.info.items;
155218
v.push({
156219
let i = match decl.decl {
157220
Decl::Class(ref c) => &c.ident,
@@ -179,25 +242,17 @@ where
179242
}
180243

181244
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(_decl)) => {
182-
self.info
183-
.items
184-
.entry(None)
185-
.or_default()
186-
.push(Specifier::Specific {
187-
local: Id::new(atom!("default"), SyntaxContext::empty()),
188-
alias: None,
189-
});
245+
self.info.items.push(Specifier::Specific {
246+
local: Id::new(atom!("default"), SyntaxContext::empty()),
247+
alias: None,
248+
});
190249
}
191250

192251
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(_expr)) => {
193-
self.info
194-
.items
195-
.entry(None)
196-
.or_default()
197-
.push(Specifier::Specific {
198-
local: Id::new(atom!("default"), SyntaxContext::empty()),
199-
alias: None,
200-
});
252+
self.info.items.push(Specifier::Specific {
253+
local: Id::new(atom!("default"), SyntaxContext::empty()),
254+
alias: None,
255+
});
201256
}
202257

203258
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(named)) => {
@@ -207,11 +262,11 @@ where
207262
});
208263
let mut need_wrapping = false;
209264

210-
let v = self
211-
.info
212-
.items
213-
.entry(named.src.clone().map(|v| *v))
214-
.or_default();
265+
let v = if let Some(src) = named.src.clone() {
266+
self.info.reexports_for(*src)
267+
} else {
268+
&mut self.info.items
269+
};
215270
for s in &mut named.specifiers {
216271
match s {
217272
ExportSpecifier::Namespace(n) => {
@@ -309,7 +364,7 @@ where
309364
.encode(&mut all.with);
310365
}
311366

312-
self.info.items.entry(Some(*all.src.clone())).or_default();
367+
let _ = self.info.reexports_for(*all.src.clone());
313368
}
314369
_ => {}
315370
}

crates/swc_bundler/src/bundler/load.rs

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -235,46 +235,35 @@ where
235235
let mut files = Vec::new();
236236

237237
let mut exports = Exports::default();
238+
exports.items.extend(raw.items);
238239

239-
let items = raw
240-
.items
240+
let reexports = raw
241+
.reexports
241242
.into_par_iter()
242243
.map(|(src, ss)| -> Result<_, Error> {
243244
self.run(|| {
244-
let info = match src {
245-
Some(src) => {
246-
let name = self.resolve(base, &src.value.to_string_lossy())?;
247-
let (id, local_mark, export_mark) =
248-
self.scope.module_id_gen.gen(&name);
249-
Some((id, local_mark, export_mark, name, src))
250-
}
251-
None => None,
252-
};
253-
254-
Ok((info, ss))
245+
let src: Str = src.into();
246+
let name = self.resolve(base, &src.value.to_string_lossy())?;
247+
let (id, local_mark, export_mark) = self.scope.module_id_gen.gen(&name);
248+
249+
Ok(((id, local_mark, export_mark, name, src), ss))
255250
})
256251
})
257252
.collect::<Vec<_>>();
258253

259-
for res in items {
260-
let (info, specifiers) = res?;
254+
for res in reexports {
255+
let ((id, local_mark, export_mark, name, src), specifiers) = res?;
261256

262-
match info {
263-
None => exports.items.extend(specifiers),
264-
Some((id, local_mark, export_mark, name, src)) => {
265-
//
266-
let src = Source {
267-
is_loaded_synchronously: true,
268-
is_unconditional: false,
269-
module_id: id,
270-
local_ctxt: SyntaxContext::empty().apply_mark(local_mark),
271-
export_ctxt: SyntaxContext::empty().apply_mark(export_mark),
272-
src,
273-
};
274-
exports.reexports.push((src.clone(), specifiers));
275-
files.push((src, name));
276-
}
277-
}
257+
let src = Source {
258+
is_loaded_synchronously: true,
259+
is_unconditional: false,
260+
module_id: id,
261+
local_ctxt: SyntaxContext::empty().apply_mark(local_mark),
262+
export_ctxt: SyntaxContext::empty().apply_mark(export_mark),
263+
src,
264+
};
265+
exports.reexports.push((src.clone(), specifiers));
266+
files.push((src, name));
278267
}
279268

280269
Ok((exports, files))
@@ -413,7 +402,7 @@ pub(crate) enum Specifier {
413402
},
414403
}
415404

416-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
405+
#[derive(Debug, Clone, PartialEq, Eq)]
417406
pub(crate) struct Source {
418407
pub is_loaded_synchronously: bool,
419408
pub is_unconditional: bool,

crates/swc_bundler/src/util.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use std::hash::Hash;
44

5+
#[cfg(feature = "concurrent")]
56
use rustc_hash::FxBuildHasher;
67
#[cfg(not(feature = "concurrent"))]
78
use rustc_hash::FxHashMap;

crates/swc_ecma_ast/src/class.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
};
1616

1717
#[ast_node]
18-
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
18+
#[derive(Eq, EqIgnoreSpan, Default)]
1919
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2020
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
2121
pub struct Class {
@@ -67,7 +67,7 @@ impl Take for Class {
6767
}
6868

6969
#[ast_node]
70-
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
70+
#[derive(Eq, Is, EqIgnoreSpan)]
7171
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
7272
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
7373
pub enum ClassMember {
@@ -104,7 +104,7 @@ impl Take for ClassMember {
104104
}
105105

106106
#[ast_node("ClassProperty")]
107-
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
107+
#[derive(Eq, EqIgnoreSpan, Default)]
108108
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
109109
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
110110
pub struct ClassProp {
@@ -162,7 +162,7 @@ pub struct ClassProp {
162162
}
163163

164164
#[ast_node("PrivateProperty")]
165-
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
165+
#[derive(Eq, EqIgnoreSpan, Default)]
166166
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
167167
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
168168
pub struct PrivateProp {
@@ -216,7 +216,7 @@ pub struct PrivateProp {
216216
}
217217

218218
#[ast_node("ClassMethod")]
219-
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
219+
#[derive(Eq, EqIgnoreSpan, Default)]
220220
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
221221
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
222222
pub struct ClassMethod {
@@ -244,7 +244,7 @@ pub struct ClassMethod {
244244
}
245245

246246
#[ast_node("PrivateMethod")]
247-
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
247+
#[derive(Eq, EqIgnoreSpan, Default)]
248248
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
249249
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
250250
pub struct PrivateMethod {
@@ -272,7 +272,7 @@ pub struct PrivateMethod {
272272
}
273273

274274
#[ast_node("Constructor")]
275-
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
275+
#[derive(Eq, EqIgnoreSpan, Default)]
276276
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
277277
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
278278
pub struct Constructor {
@@ -303,7 +303,7 @@ pub struct Constructor {
303303
}
304304

305305
#[ast_node("Decorator")]
306-
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
306+
#[derive(Eq, EqIgnoreSpan, Default)]
307307
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
308308
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
309309
pub struct Decorator {
@@ -313,7 +313,7 @@ pub struct Decorator {
313313
pub expr: Box<Expr>,
314314
}
315315

316-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EqIgnoreSpan, Default)]
316+
#[derive(Debug, Clone, Copy, PartialEq, Eq, EqIgnoreSpan, Default)]
317317
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
318318
#[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))]
319319
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
@@ -333,7 +333,7 @@ pub enum MethodKind {
333333
}
334334

335335
#[ast_node("StaticBlock")]
336-
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
336+
#[derive(Eq, EqIgnoreSpan, Default)]
337337
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
338338
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
339339
pub struct StaticBlock {
@@ -352,7 +352,7 @@ impl Take for StaticBlock {
352352

353353
/// Either a private name or a public name.
354354
#[ast_node]
355-
#[derive(Is, Eq, Hash, EqIgnoreSpan)]
355+
#[derive(Is, Eq, EqIgnoreSpan)]
356356
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
357357
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
358358
pub enum Key {
@@ -386,7 +386,7 @@ impl Default for Key {
386386
}
387387

388388
#[ast_node("AutoAccessor")]
389-
#[derive(Eq, Hash, EqIgnoreSpan, Default)]
389+
#[derive(Eq, EqIgnoreSpan, Default)]
390390
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
391391
#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
392392
pub struct AutoAccessor {

0 commit comments

Comments
 (0)