Auto merge of #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
This commit is contained in:
bors 2023-02-14 16:02:02 +00:00
commit 9548388534
2 changed files with 52 additions and 27 deletions

View file

@ -38,11 +38,11 @@ impl Display for ImportAlias {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path { pub struct Path {
/// Type based path like `<T>::foo`. /// Type based path like `<T>::foo`.
/// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`. /// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
type_anchor: Option<Interned<TypeRef>>, type_anchor: Option<Interned<TypeRef>>,
mod_path: Interned<ModPath>, mod_path: Interned<ModPath>,
/// Invariant: the same len as `self.mod_path.segments` /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
generic_args: Box<[Option<Interned<GenericArgs>>]>, generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
} }
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
@ -102,7 +102,7 @@ impl Path {
) -> Path { ) -> Path {
let generic_args = generic_args.into(); let generic_args = generic_args.into();
assert_eq!(path.len(), generic_args.len()); assert_eq!(path.len(), generic_args.len());
Path { type_anchor: None, mod_path: Interned::new(path), generic_args } Path { type_anchor: None, mod_path: Interned::new(path), generic_args: Some(generic_args) }
} }
pub fn kind(&self) -> &PathKind { pub fn kind(&self) -> &PathKind {
@ -114,7 +114,14 @@ impl Path {
} }
pub fn segments(&self) -> PathSegments<'_> { pub fn segments(&self) -> PathSegments<'_> {
PathSegments { segments: self.mod_path.segments(), generic_args: &self.generic_args } let s = PathSegments {
segments: self.mod_path.segments(),
generic_args: self.generic_args.as_deref(),
};
if let Some(generic_args) = s.generic_args {
assert_eq!(s.segments.len(), generic_args.len());
}
s
} }
pub fn mod_path(&self) -> &ModPath { pub fn mod_path(&self) -> &ModPath {
@ -131,13 +138,15 @@ impl Path {
self.mod_path.kind, self.mod_path.kind,
self.mod_path.segments()[..self.mod_path.segments().len() - 1].iter().cloned(), self.mod_path.segments()[..self.mod_path.segments().len() - 1].iter().cloned(),
)), )),
generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec().into(), generic_args: self.generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()),
}; };
Some(res) Some(res)
} }
pub fn is_self_type(&self) -> bool { pub fn is_self_type(&self) -> bool {
self.type_anchor.is_none() && *self.generic_args == [None] && self.mod_path.is_Self() self.type_anchor.is_none()
&& self.generic_args.as_deref().is_none()
&& self.mod_path.is_Self()
} }
} }
@ -149,11 +158,11 @@ pub struct PathSegment<'a> {
pub struct PathSegments<'a> { pub struct PathSegments<'a> {
segments: &'a [Name], segments: &'a [Name],
generic_args: &'a [Option<Interned<GenericArgs>>], generic_args: Option<&'a [Option<Interned<GenericArgs>>]>,
} }
impl<'a> PathSegments<'a> { impl<'a> PathSegments<'a> {
pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] }; pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: None };
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len() == 0 self.len() == 0
} }
@ -167,26 +176,29 @@ impl<'a> PathSegments<'a> {
self.get(self.len().checked_sub(1)?) self.get(self.len().checked_sub(1)?)
} }
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> { pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
assert_eq!(self.segments.len(), self.generic_args.len());
let res = PathSegment { let res = PathSegment {
name: self.segments.get(idx)?, name: self.segments.get(idx)?,
args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it), args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()),
}; };
Some(res) Some(res)
} }
pub fn skip(&self, len: usize) -> PathSegments<'a> { pub fn skip(&self, len: usize) -> PathSegments<'a> {
assert_eq!(self.segments.len(), self.generic_args.len()); PathSegments {
PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] } segments: &self.segments.get(len..).unwrap_or(&[]),
generic_args: self.generic_args.and_then(|it| it.get(len..)),
}
} }
pub fn take(&self, len: usize) -> PathSegments<'a> { pub fn take(&self, len: usize) -> PathSegments<'a> {
assert_eq!(self.segments.len(), self.generic_args.len()); PathSegments {
PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] } segments: &self.segments.get(..len).unwrap_or(&self.segments),
generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)),
}
} }
pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> { pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment { self.segments
name, .iter()
args_and_bindings: args.as_ref().map(|it| &**it), .zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
}) .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() })
} }
} }
@ -213,7 +225,7 @@ impl From<Name> for Path {
Path { Path {
type_anchor: None, type_anchor: None,
mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))), mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
generic_args: Box::new([None]), generic_args: None,
} }
} }
} }

View file

@ -45,8 +45,11 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
) )
}) })
.map(Interned::new); .map(Interned::new);
if let Some(_) = args {
generic_args.resize(segments.len(), None);
generic_args.push(args);
}
segments.push(name); segments.push(name);
generic_args.push(args)
} }
Either::Right(crate_id) => { Either::Right(crate_id) => {
kind = PathKind::DollarCrate(crate_id); kind = PathKind::DollarCrate(crate_id);
@ -56,7 +59,6 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
} }
ast::PathSegmentKind::SelfTypeKw => { ast::PathSegmentKind::SelfTypeKw => {
segments.push(name![Self]); segments.push(name![Self]);
generic_args.push(None)
} }
ast::PathSegmentKind::Type { type_ref, trait_ref } => { ast::PathSegmentKind::Type { type_ref, trait_ref } => {
assert!(path.qualifier().is_none()); // this can only occur at the first segment 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
kind = mod_path.kind; kind = mod_path.kind;
segments.extend(mod_path.segments().iter().cloned().rev()); segments.extend(mod_path.segments().iter().cloned().rev());
generic_args.extend(Vec::from(path_generic_args).into_iter().rev()); if let Some(path_generic_args) = path_generic_args {
generic_args.resize(segments.len() - num_segments, None);
generic_args.extend(Vec::from(path_generic_args).into_iter().rev());
} else {
generic_args.resize(segments.len(), None);
}
// Insert the type reference (T in the above example) as Self parameter for the trait // Insert the type reference (T in the above example) as Self parameter for the trait
let last_segment = let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?;
let mut args_inner = match last_segment { let mut args_inner = match last_segment {
Some(it) => it.as_ref().clone(), Some(it) => it.as_ref().clone(),
None => GenericArgs::empty(), None => GenericArgs::empty(),
@ -115,7 +121,10 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
}; };
} }
segments.reverse(); segments.reverse();
generic_args.reverse(); if !generic_args.is_empty() {
generic_args.resize(segments.len(), None);
generic_args.reverse();
}
if segments.is_empty() && kind == PathKind::Plain && type_anchor.is_none() { if segments.is_empty() && kind == PathKind::Plain && type_anchor.is_none() {
// plain empty paths don't exist, this means we got a single `self` segment as our path // 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
} }
let mod_path = Interned::new(ModPath::from_segments(kind, segments)); let mod_path = Interned::new(ModPath::from_segments(kind, segments));
return Some(Path { type_anchor, mod_path, generic_args: generic_args.into() }); return Some(Path {
type_anchor,
mod_path,
generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) },
});
fn qualifier(path: &ast::Path) -> Option<ast::Path> { fn qualifier(path: &ast::Path) -> Option<ast::Path> {
if let Some(q) = path.qualifier() { if let Some(q) = path.qualifier() {