diff options
| -rw-r--r-- | crates/hir-def/src/path.rs | 52 | ||||
| -rw-r--r-- | crates/hir-def/src/path/lower.rs | 27 |
2 files changed, 52 insertions, 27 deletions
diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index 25a23fcd61a..f53bd4f6186 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -38,11 +38,11 @@ impl Display for ImportAlias { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { /// 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>>, mod_path: Interned<ModPath>, - /// Invariant: the same len as `self.mod_path.segments` - generic_args: Box<[Option<Interned<GenericArgs>>]>, + /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`. + generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>, } /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This @@ -102,7 +102,7 @@ impl Path { ) -> Path { let generic_args = generic_args.into(); 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 { @@ -114,7 +114,14 @@ impl Path { } 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 { @@ -131,13 +138,15 @@ impl Path { self.mod_path.kind, 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) } 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> { segments: &'a [Name], - generic_args: &'a [Option<Interned<GenericArgs>>], + generic_args: Option<&'a [Option<Interned<GenericArgs>>]>, } 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 { self.len() == 0 } @@ -167,26 +176,29 @@ impl<'a> PathSegments<'a> { self.get(self.len().checked_sub(1)?) } pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> { - assert_eq!(self.segments.len(), self.generic_args.len()); let res = PathSegment { 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) } pub fn skip(&self, len: usize) -> PathSegments<'a> { - assert_eq!(self.segments.len(), self.generic_args.len()); - PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] } + PathSegments { + 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> { - assert_eq!(self.segments.len(), self.generic_args.len()); - PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] } + PathSegments { + 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>> { - self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment { - name, - args_and_bindings: args.as_ref().map(|it| &**it), - }) + self.segments + .iter() + .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 { type_anchor: None, mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))), - generic_args: Box::new([None]), + generic_args: None, } } } diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index d570191595b..334750a5915 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -45,8 +45,11 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path ) }) .map(Interned::new); + if let Some(_) = args { + generic_args.resize(segments.len(), None); + generic_args.push(args); + } segments.push(name); - generic_args.push(args) } Either::Right(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 => { segments.push(name![Self]); - generic_args.push(None) } ast::PathSegmentKind::Type { type_ref, trait_ref } => { 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; 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 - let last_segment = - generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; + let last_segment = generic_args.get_mut(segments.len() - num_segments)?; let mut args_inner = match last_segment { Some(it) => it.as_ref().clone(), None => GenericArgs::empty(), @@ -115,7 +121,10 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path }; } 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() { // 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)); - 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> { if let Some(q) = path.qualifier() { |
