hir_def/expr_store/
path.rs

1//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
2
3use std::iter;
4
5use crate::{
6    lang_item::LangItemTarget,
7    type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
8};
9use hir_expand::{
10    mod_path::{ModPath, PathKind},
11    name::Name,
12};
13use intern::Interned;
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16pub enum Path {
17    /// `BarePath` is used when the path has neither generics nor type anchor, since the vast majority of paths
18    /// are in this category, and splitting `Path` this way allows it to be more thin. When the path has either generics
19    /// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically
20    /// this is not a problem since many more paths have generics than a type anchor).
21    BarePath(Interned<ModPath>),
22    /// `Path::Normal` will always have either generics or type anchor.
23    Normal(Box<NormalPath>),
24    /// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
25    /// links via a normal path since they might be private and not accessible in the usage place.
26    LangItem(LangItemTarget, Option<Name>),
27}
28
29// This type is being used a lot, make sure it doesn't grow unintentionally.
30#[cfg(target_arch = "x86_64")]
31const _: () = {
32    assert!(size_of::<Path>() == 16);
33    assert!(size_of::<Option<Path>>() == 16);
34};
35
36#[derive(Debug, Clone, PartialEq, Eq, Hash)]
37pub struct NormalPath {
38    pub generic_args: Box<[Option<GenericArgs>]>,
39    pub type_anchor: Option<TypeRefId>,
40    pub mod_path: Interned<ModPath>,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub enum GenericArgsParentheses {
45    No,
46    /// Bounds of the form `Type::method(..): Send` or `impl Trait<method(..): Send>`,
47    /// aka. Return Type Notation or RTN.
48    ReturnTypeNotation,
49    /// `Fn`-family parenthesized traits, e.g. `impl Fn(u32) -> String`.
50    ///
51    /// This is desugared into one generic argument containing a tuple of all arguments,
52    /// and an associated type binding for `Output` for the return type.
53    ParenSugar,
54}
55
56/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
57/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
58#[derive(Debug, Clone, PartialEq, Eq, Hash)]
59pub struct GenericArgs {
60    pub args: Box<[GenericArg]>,
61    /// This specifies whether the args contain a Self type as the first
62    /// element. This is the case for path segments like `<T as Trait>`, where
63    /// `T` is actually a type parameter for the path `Trait` specifying the
64    /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
65    /// is left out.
66    pub has_self_type: bool,
67    /// Associated type bindings like in `Iterator<Item = T>`.
68    pub bindings: Box<[AssociatedTypeBinding]>,
69    /// Whether these generic args were written with parentheses and how.
70    pub parenthesized: GenericArgsParentheses,
71}
72
73/// An associated type binding like in `Iterator<Item = T>`.
74#[derive(Debug, Clone, PartialEq, Eq, Hash)]
75pub struct AssociatedTypeBinding {
76    /// The name of the associated type.
77    pub name: Name,
78    /// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this
79    /// would be `['a, T]`.
80    pub args: Option<GenericArgs>,
81    /// The type bound to this associated type (in `Item = T`, this would be the
82    /// `T`). This can be `None` if there are bounds instead.
83    pub type_ref: Option<TypeRefId>,
84    /// Bounds for the associated type, like in `Iterator<Item:
85    /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
86    /// feature.)
87    pub bounds: Box<[TypeBound]>,
88}
89
90/// A single generic argument.
91#[derive(Debug, Clone, PartialEq, Eq, Hash)]
92pub enum GenericArg {
93    Type(TypeRefId),
94    Lifetime(LifetimeRef),
95    Const(ConstRef),
96}
97
98impl Path {
99    /// Converts a known mod path to `Path`.
100    pub fn from_known_path(path: ModPath, generic_args: Vec<Option<GenericArgs>>) -> Path {
101        Path::Normal(Box::new(NormalPath {
102            generic_args: generic_args.into_boxed_slice(),
103            type_anchor: None,
104            mod_path: Interned::new(path),
105        }))
106    }
107
108    /// Converts a known mod path to `Path`.
109    pub fn from_known_path_with_no_generic(path: ModPath) -> Path {
110        Path::BarePath(Interned::new(path))
111    }
112
113    #[inline]
114    pub fn kind(&self) -> &PathKind {
115        match self {
116            Path::BarePath(mod_path) => &mod_path.kind,
117            Path::Normal(path) => &path.mod_path.kind,
118            Path::LangItem(..) => &PathKind::Abs,
119        }
120    }
121
122    #[inline]
123    pub fn type_anchor(&self) -> Option<TypeRefId> {
124        match self {
125            Path::Normal(path) => path.type_anchor,
126            Path::LangItem(..) | Path::BarePath(_) => None,
127        }
128    }
129
130    #[inline]
131    pub fn generic_args(&self) -> Option<&[Option<GenericArgs>]> {
132        match self {
133            Path::Normal(path) => Some(&path.generic_args),
134            Path::LangItem(..) | Path::BarePath(_) => None,
135        }
136    }
137
138    pub fn segments(&self) -> PathSegments<'_> {
139        match self {
140            Path::BarePath(mod_path) => {
141                PathSegments { segments: mod_path.segments(), generic_args: None }
142            }
143            Path::Normal(path) => PathSegments {
144                segments: path.mod_path.segments(),
145                generic_args: Some(&path.generic_args),
146            },
147            Path::LangItem(_, seg) => PathSegments { segments: seg.as_slice(), generic_args: None },
148        }
149    }
150
151    pub fn mod_path(&self) -> Option<&ModPath> {
152        match self {
153            Path::BarePath(mod_path) => Some(mod_path),
154            Path::Normal(path) => Some(&path.mod_path),
155            Path::LangItem(..) => None,
156        }
157    }
158
159    pub fn qualifier(&self) -> Option<Path> {
160        match self {
161            Path::BarePath(mod_path) => {
162                if mod_path.is_ident() {
163                    return None;
164                }
165                Some(Path::BarePath(Interned::new(ModPath::from_segments(
166                    mod_path.kind,
167                    mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
168                ))))
169            }
170            Path::Normal(path) => {
171                let mod_path = &path.mod_path;
172                if mod_path.is_ident() {
173                    return None;
174                }
175                let type_anchor = path.type_anchor;
176                let generic_args = &path.generic_args;
177                let qualifier_mod_path = Interned::new(ModPath::from_segments(
178                    mod_path.kind,
179                    mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
180                ));
181                let qualifier_generic_args = &generic_args[..generic_args.len() - 1];
182                if type_anchor.is_none() && qualifier_generic_args.iter().all(|it| it.is_none()) {
183                    Some(Path::BarePath(qualifier_mod_path))
184                } else {
185                    Some(Path::Normal(Box::new(NormalPath {
186                        type_anchor,
187                        mod_path: qualifier_mod_path,
188                        generic_args: qualifier_generic_args.iter().cloned().collect(),
189                    })))
190                }
191            }
192            Path::LangItem(..) => None,
193        }
194    }
195
196    pub fn is_self_type(&self) -> bool {
197        match self {
198            Path::BarePath(mod_path) => mod_path.is_Self(),
199            Path::Normal(path) => {
200                path.type_anchor.is_none()
201                    && path.mod_path.is_Self()
202                    && path.generic_args.iter().all(|args| args.is_none())
203            }
204            Path::LangItem(..) => false,
205        }
206    }
207}
208
209#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
210pub struct PathSegment<'a> {
211    pub name: &'a Name,
212    pub args_and_bindings: Option<&'a GenericArgs>,
213}
214
215impl PathSegment<'_> {
216    pub const MISSING: PathSegment<'static> =
217        PathSegment { name: &Name::missing(), args_and_bindings: None };
218}
219
220#[derive(Debug, Clone, Copy)]
221pub struct PathSegments<'a> {
222    segments: &'a [Name],
223    generic_args: Option<&'a [Option<GenericArgs>]>,
224}
225
226impl<'a> PathSegments<'a> {
227    pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: None };
228    pub fn is_empty(&self) -> bool {
229        self.len() == 0
230    }
231    pub fn len(&self) -> usize {
232        self.segments.len()
233    }
234    pub fn first(&self) -> Option<PathSegment<'a>> {
235        self.get(0)
236    }
237    pub fn last(&self) -> Option<PathSegment<'a>> {
238        self.get(self.len().checked_sub(1)?)
239    }
240
241    pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
242        let res = PathSegment {
243            name: self.segments.get(idx)?,
244            args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_ref()),
245        };
246        Some(res)
247    }
248
249    pub fn skip(&self, len: usize) -> PathSegments<'a> {
250        PathSegments {
251            segments: self.segments.get(len..).unwrap_or(&[]),
252            generic_args: self.generic_args.and_then(|it| it.get(len..)),
253        }
254    }
255
256    pub fn take(&self, len: usize) -> PathSegments<'a> {
257        PathSegments {
258            segments: self.segments.get(..len).unwrap_or(self.segments),
259            generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)),
260        }
261    }
262
263    pub fn strip_last(&self) -> PathSegments<'a> {
264        PathSegments {
265            segments: self.segments.split_last().map_or(&[], |it| it.1),
266            generic_args: self.generic_args.map(|it| it.split_last().map_or(&[][..], |it| it.1)),
267        }
268    }
269
270    pub fn strip_last_two(&self) -> PathSegments<'a> {
271        PathSegments {
272            segments: self.segments.get(..self.segments.len().saturating_sub(2)).unwrap_or(&[]),
273            generic_args: self
274                .generic_args
275                .map(|it| it.get(..it.len().saturating_sub(2)).unwrap_or(&[])),
276        }
277    }
278
279    pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
280        self.segments
281            .iter()
282            .zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
283            .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_ref() })
284    }
285}
286
287impl GenericArgs {
288    pub(crate) fn empty() -> GenericArgs {
289        GenericArgs {
290            args: Box::default(),
291            has_self_type: false,
292            bindings: Box::default(),
293            parenthesized: GenericArgsParentheses::No,
294        }
295    }
296
297    pub(crate) fn return_type_notation() -> GenericArgs {
298        GenericArgs {
299            args: Box::default(),
300            has_self_type: false,
301            bindings: Box::default(),
302            parenthesized: GenericArgsParentheses::ReturnTypeNotation,
303        }
304    }
305}
306
307impl From<Name> for Path {
308    fn from(name: Name) -> Path {
309        Path::BarePath(Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))))
310    }
311}