Skip to content

Commit 9548388

Browse files
committed
Auto merge of rust-lang#14150 - Veykril:path, r=Veykril
internal: Don't allocate the generic_args vec in `hir_def::Path` if it consists only of `None` args Saves roughly 5mb on self
2 parents e7bc68f + a18ebf4 commit 9548388

File tree

2 files changed

+52
-27
lines changed

2 files changed

+52
-27
lines changed

crates/hir-def/src/path.rs

+32-20
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ impl Display for ImportAlias {
3838
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3939
pub struct Path {
4040
/// Type based path like `<T>::foo`.
41-
/// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
41+
/// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
4242
type_anchor: Option<Interned<TypeRef>>,
4343
mod_path: Interned<ModPath>,
44-
/// Invariant: the same len as `self.mod_path.segments`
45-
generic_args: Box<[Option<Interned<GenericArgs>>]>,
44+
/// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
45+
generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
4646
}
4747

4848
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
@@ -102,7 +102,7 @@ impl Path {
102102
) -> Path {
103103
let generic_args = generic_args.into();
104104
assert_eq!(path.len(), generic_args.len());
105-
Path { type_anchor: None, mod_path: Interned::new(path), generic_args }
105+
Path { type_anchor: None, mod_path: Interned::new(path), generic_args: Some(generic_args) }
106106
}
107107

108108
pub fn kind(&self) -> &PathKind {
@@ -114,7 +114,14 @@ impl Path {
114114
}
115115

116116
pub fn segments(&self) -> PathSegments<'_> {
117-
PathSegments { segments: self.mod_path.segments(), generic_args: &self.generic_args }
117+
let s = PathSegments {
118+
segments: self.mod_path.segments(),
119+
generic_args: self.generic_args.as_deref(),
120+
};
121+
if let Some(generic_args) = s.generic_args {
122+
assert_eq!(s.segments.len(), generic_args.len());
123+
}
124+
s
118125
}
119126

120127
pub fn mod_path(&self) -> &ModPath {
@@ -131,13 +138,15 @@ impl Path {
131138
self.mod_path.kind,
132139
self.mod_path.segments()[..self.mod_path.segments().len() - 1].iter().cloned(),
133140
)),
134-
generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec().into(),
141+
generic_args: self.generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()),
135142
};
136143
Some(res)
137144
}
138145

139146
pub fn is_self_type(&self) -> bool {
140-
self.type_anchor.is_none() && *self.generic_args == [None] && self.mod_path.is_Self()
147+
self.type_anchor.is_none()
148+
&& self.generic_args.as_deref().is_none()
149+
&& self.mod_path.is_Self()
141150
}
142151
}
143152

@@ -149,11 +158,11 @@ pub struct PathSegment<'a> {
149158

150159
pub struct PathSegments<'a> {
151160
segments: &'a [Name],
152-
generic_args: &'a [Option<Interned<GenericArgs>>],
161+
generic_args: Option<&'a [Option<Interned<GenericArgs>>]>,
153162
}
154163

155164
impl<'a> PathSegments<'a> {
156-
pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
165+
pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: None };
157166
pub fn is_empty(&self) -> bool {
158167
self.len() == 0
159168
}
@@ -167,26 +176,29 @@ impl<'a> PathSegments<'a> {
167176
self.get(self.len().checked_sub(1)?)
168177
}
169178
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
170-
assert_eq!(self.segments.len(), self.generic_args.len());
171179
let res = PathSegment {
172180
name: self.segments.get(idx)?,
173-
args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
181+
args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()),
174182
};
175183
Some(res)
176184
}
177185
pub fn skip(&self, len: usize) -> PathSegments<'a> {
178-
assert_eq!(self.segments.len(), self.generic_args.len());
179-
PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
186+
PathSegments {
187+
segments: &self.segments.get(len..).unwrap_or(&[]),
188+
generic_args: self.generic_args.and_then(|it| it.get(len..)),
189+
}
180190
}
181191
pub fn take(&self, len: usize) -> PathSegments<'a> {
182-
assert_eq!(self.segments.len(), self.generic_args.len());
183-
PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
192+
PathSegments {
193+
segments: &self.segments.get(..len).unwrap_or(&self.segments),
194+
generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)),
195+
}
184196
}
185197
pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
186-
self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
187-
name,
188-
args_and_bindings: args.as_ref().map(|it| &**it),
189-
})
198+
self.segments
199+
.iter()
200+
.zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
201+
.map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() })
190202
}
191203
}
192204

@@ -213,7 +225,7 @@ impl From<Name> for Path {
213225
Path {
214226
type_anchor: None,
215227
mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
216-
generic_args: Box::new([None]),
228+
generic_args: None,
217229
}
218230
}
219231
}

crates/hir-def/src/path/lower.rs

+20-7
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,11 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
4545
)
4646
})
4747
.map(Interned::new);
48+
if let Some(_) = args {
49+
generic_args.resize(segments.len(), None);
50+
generic_args.push(args);
51+
}
4852
segments.push(name);
49-
generic_args.push(args)
5053
}
5154
Either::Right(crate_id) => {
5255
kind = PathKind::DollarCrate(crate_id);
@@ -56,7 +59,6 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
5659
}
5760
ast::PathSegmentKind::SelfTypeKw => {
5861
segments.push(name![Self]);
59-
generic_args.push(None)
6062
}
6163
ast::PathSegmentKind::Type { type_ref, trait_ref } => {
6264
assert!(path.qualifier().is_none()); // this can only occur at the first segment
@@ -77,11 +79,15 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
7779
kind = mod_path.kind;
7880

7981
segments.extend(mod_path.segments().iter().cloned().rev());
80-
generic_args.extend(Vec::from(path_generic_args).into_iter().rev());
82+
if let Some(path_generic_args) = path_generic_args {
83+
generic_args.resize(segments.len() - num_segments, None);
84+
generic_args.extend(Vec::from(path_generic_args).into_iter().rev());
85+
} else {
86+
generic_args.resize(segments.len(), None);
87+
}
8188

8289
// Insert the type reference (T in the above example) as Self parameter for the trait
83-
let last_segment =
84-
generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?;
90+
let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
8591
let mut args_inner = match last_segment {
8692
Some(it) => it.as_ref().clone(),
8793
None => GenericArgs::empty(),
@@ -115,7 +121,10 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
115121
};
116122
}
117123
segments.reverse();
118-
generic_args.reverse();
124+
if !generic_args.is_empty() {
125+
generic_args.resize(segments.len(), None);
126+
generic_args.reverse();
127+
}
119128

120129
if segments.is_empty() && kind == PathKind::Plain && type_anchor.is_none() {
121130
// plain empty paths don't exist, this means we got a single `self` segment as our path
@@ -135,7 +144,11 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
135144
}
136145

137146
let mod_path = Interned::new(ModPath::from_segments(kind, segments));
138-
return Some(Path { type_anchor, mod_path, generic_args: generic_args.into() });
147+
return Some(Path {
148+
type_anchor,
149+
mod_path,
150+
generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) },
151+
});
139152

140153
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
141154
if let Some(q) = path.qualifier() {

0 commit comments

Comments
 (0)