Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/path.rs')
| -rw-r--r-- | crates/hir-def/src/path.rs | 89 |
1 files changed, 60 insertions, 29 deletions
diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index f3197d1800..b9b8082549 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -7,15 +7,14 @@ use std::{ }; use crate::{ - body::LowerCtx, - type_ref::{ConstRefOrPath, LifetimeRef}, + lang_item::LangItemTarget, + lower::LowerCtx, + type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef}, }; use hir_expand::name::Name; use intern::Interned; use syntax::ast; -use crate::type_ref::{TypeBound, TypeRef}; - pub use hir_expand::mod_path::{path, ModPath, PathKind}; #[derive(Debug, Clone, PartialEq, Eq)] @@ -36,13 +35,19 @@ 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 desugared to `Trait::<Self=Type>::foo`. - type_anchor: Option<Interned<TypeRef>>, - mod_path: Interned<ModPath>, - /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`. - generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>, +pub enum Path { + /// A normal path + Normal { + /// Type based path like `<T>::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` or `None` if all segments are `None`. + generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>, + }, + /// A link to a lang item. It is used in desugaring of things like `x?`. We can show these + /// links via a normal path since they might be private and not accessible in the usage place. + LangItem(LangItemTarget), } /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This @@ -102,51 +107,77 @@ 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: Some(generic_args) } + Path::Normal { + type_anchor: None, + mod_path: Interned::new(path), + generic_args: Some(generic_args), + } + } + + /// Converts a known mod path to `Path`. + pub fn from_known_path_with_no_generic(path: ModPath) -> Path { + Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None } } pub fn kind(&self) -> &PathKind { - &self.mod_path.kind + match self { + Path::Normal { mod_path, .. } => &mod_path.kind, + Path::LangItem(_) => &PathKind::Abs, + } } pub fn type_anchor(&self) -> Option<&TypeRef> { - self.type_anchor.as_deref() + match self { + Path::Normal { type_anchor, .. } => type_anchor.as_deref(), + Path::LangItem(_) => None, + } } pub fn segments(&self) -> PathSegments<'_> { - let s = PathSegments { - segments: self.mod_path.segments(), - generic_args: self.generic_args.as_deref(), + let Path::Normal { mod_path, generic_args, .. } = self else { + return PathSegments { + segments: &[], + generic_args: None, + }; }; + let s = + PathSegments { segments: mod_path.segments(), generic_args: 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 { - &self.mod_path + pub fn mod_path(&self) -> Option<&ModPath> { + match self { + Path::Normal { mod_path, .. } => Some(&mod_path), + Path::LangItem(_) => None, + } } pub fn qualifier(&self) -> Option<Path> { - if self.mod_path.is_ident() { + let Path::Normal { mod_path, generic_args, type_anchor } = self else { + return None; + }; + if mod_path.is_ident() { return None; } - let res = Path { - type_anchor: self.type_anchor.clone(), + let res = Path::Normal { + type_anchor: type_anchor.clone(), mod_path: Interned::new(ModPath::from_segments( - self.mod_path.kind, - self.mod_path.segments()[..self.mod_path.segments().len() - 1].iter().cloned(), + mod_path.kind, + mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(), )), - generic_args: self.generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()), + generic_args: 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.as_deref().is_none() - && self.mod_path.is_Self() + let Path::Normal { mod_path, generic_args, type_anchor } = self else { + return false; + }; + type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self() } } @@ -222,7 +253,7 @@ impl GenericArgs { impl From<Name> for Path { fn from(name: Name) -> Path { - Path { + Path::Normal { type_anchor: None, mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))), generic_args: None, |