use std::{
fmt::{self, Display},
iter,
- sync::Arc,
};
-use crate::{body::LowerCtx, type_ref::LifetimeRef};
-use base_db::CrateId;
-use hir_expand::{
- hygiene::Hygiene,
- name::{name, Name},
-};
+use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef};
+use hir_expand::name::{name, Name};
use syntax::ast;
-use crate::{
- type_ref::{TypeBound, TypeRef},
- InFile,
-};
-
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct ModPath {
- pub kind: PathKind,
- segments: Vec<Name>,
-}
+use crate::type_ref::{TypeBound, TypeRef};
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum PathKind {
- Plain,
- /// `self::` is `Super(0)`
- Super(u8),
- Crate,
- /// Absolute path (::foo)
- Abs,
- /// `$crate` from macro expansion
- DollarCrate(CrateId),
-}
+pub use hir_expand::mod_path::{path, ModPath, PathKind};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ImportAlias {
Alias(Name),
}
-impl ModPath {
- pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
- lower::lower_path(path, hygiene).map(|it| it.mod_path)
- }
-
- pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
- let segments = segments.into_iter().collect::<Vec<_>>();
- ModPath { kind, segments }
- }
-
- /// Creates a `ModPath` from a `PathKind`, with no extra path segments.
- pub const fn from_kind(kind: PathKind) -> ModPath {
- ModPath { kind, segments: Vec::new() }
- }
-
- /// Calls `cb` with all paths, represented by this use item.
- pub(crate) fn expand_use_item(
- item_src: InFile<ast::Use>,
- hygiene: &Hygiene,
- mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
- ) {
- if let Some(tree) = item_src.value.use_tree() {
- lower::lower_use_tree(None, tree, hygiene, &mut cb);
- }
- }
-
- pub fn segments(&self) -> &[Name] {
- &self.segments
- }
-
- pub fn push_segment(&mut self, segment: Name) {
- self.segments.push(segment);
- }
-
- pub fn pop_segment(&mut self) -> Option<Name> {
- self.segments.pop()
- }
-
- /// Returns the number of segments in the path (counting special segments like `$crate` and
- /// `super`).
- pub fn len(&self) -> usize {
- self.segments.len()
- + match self.kind {
- PathKind::Plain => 0,
- PathKind::Super(i) => i as usize,
- PathKind::Crate => 1,
- PathKind::Abs => 0,
- PathKind::DollarCrate(_) => 1,
- }
- }
-
- pub fn is_ident(&self) -> bool {
- self.as_ident().is_some()
- }
-
- pub fn is_self(&self) -> bool {
- self.kind == PathKind::Super(0) && self.segments.is_empty()
- }
-
- /// If this path is a single identifier, like `foo`, return its name.
- pub fn as_ident(&self) -> Option<&Name> {
- if self.kind != PathKind::Plain {
- return None;
- }
-
- match &*self.segments {
- [name] => Some(name),
- _ => None,
+impl Display for ImportAlias {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ImportAlias::Underscore => f.write_str("_"),
+ ImportAlias::Alias(name) => f.write_str(&name.to_smol_str()),
}
}
}
pub struct Path {
/// Type based path like `<T>::foo`.
/// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
- type_anchor: Option<Box<TypeRef>>,
- mod_path: ModPath,
+ type_anchor: Option<Interned<TypeRef>>,
+ mod_path: Interned<ModPath>,
/// Invariant: the same len as `self.mod_path.segments`
- generic_args: Vec<Option<Arc<GenericArgs>>>,
+ generic_args: Box<[Option<Interned<GenericArgs>>]>,
}
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
pub has_self_type: bool,
/// Associated type bindings like in `Iterator<Item = T>`.
pub bindings: Vec<AssociatedTypeBinding>,
+ /// Whether these generic args were desugared from `Trait(Arg) -> Output`
+ /// parenthesis notation typically used for the `Fn` traits.
+ pub desugared_from_fn: bool,
}
/// An associated type binding like in `Iterator<Item = T>`.
/// Bounds for the associated type, like in `Iterator<Item:
/// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
/// feature.)
- pub bounds: Vec<TypeBound>,
+ pub bounds: Vec<Interned<TypeBound>>,
}
/// A single generic argument.
impl Path {
/// Converts an `ast::Path` to `Path`. Works with use trees.
/// It correctly handles `$crate` based path from macro call.
- pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
- lower::lower_path(path, hygiene)
+ pub fn from_src(path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
+ lower::lower_path(path, ctx)
}
/// Converts a known mod path to `Path`.
- pub(crate) fn from_known_path(
+ pub fn from_known_path(
path: ModPath,
- generic_args: Vec<Option<Arc<GenericArgs>>>,
+ generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>,
) -> Path {
- Path { type_anchor: None, mod_path: path, generic_args }
+ let generic_args = generic_args.into();
+ assert_eq!(path.len(), generic_args.len());
+ Path { type_anchor: None, mod_path: Interned::new(path), generic_args }
}
pub fn kind(&self) -> &PathKind {
}
pub fn segments(&self) -> PathSegments<'_> {
- PathSegments {
- segments: self.mod_path.segments.as_slice(),
- generic_args: self.generic_args.as_slice(),
- }
+ PathSegments { segments: self.mod_path.segments(), generic_args: &self.generic_args }
}
pub fn mod_path(&self) -> &ModPath {
}
let res = Path {
type_anchor: self.type_anchor.clone(),
- mod_path: ModPath::from_segments(
+ mod_path: Interned::new(ModPath::from_segments(
self.mod_path.kind.clone(),
- self.mod_path.segments[..self.mod_path.segments.len() - 1].iter().cloned(),
- ),
- generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
+ 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(),
};
Some(res)
}
pub fn is_self_type(&self) -> bool {
self.type_anchor.is_none()
- && self.generic_args == &[None]
+ && *self.generic_args == [None]
&& self.mod_path.as_ident() == Some(&name!(Self))
}
}
pub struct PathSegments<'a> {
segments: &'a [Name],
- generic_args: &'a [Option<Arc<GenericArgs>>],
+ generic_args: &'a [Option<Interned<GenericArgs>>],
}
impl<'a> PathSegments<'a> {
}
pub(crate) fn empty() -> GenericArgs {
- GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
+ GenericArgs {
+ args: Vec::new(),
+ has_self_type: false,
+ bindings: Vec::new(),
+ desugared_from_fn: false,
+ }
}
}
fn from(name: Name) -> Path {
Path {
type_anchor: None,
- mod_path: ModPath::from_segments(PathKind::Plain, iter::once(name)),
- generic_args: vec![None],
+ mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
+ generic_args: Box::new([None]),
}
}
}
-impl From<Name> for ModPath {
- fn from(name: Name) -> ModPath {
- ModPath::from_segments(PathKind::Plain, iter::once(name))
+impl From<Name> for Box<Path> {
+ fn from(name: Name) -> Box<Path> {
+ Box::new(Path::from(name))
}
}
-
-impl Display for ModPath {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut first_segment = true;
- let mut add_segment = |s| -> fmt::Result {
- if !first_segment {
- f.write_str("::")?;
- }
- first_segment = false;
- f.write_str(s)?;
- Ok(())
- };
- match self.kind {
- PathKind::Plain => {}
- PathKind::Super(0) => add_segment("self")?,
- PathKind::Super(n) => {
- for _ in 0..n {
- add_segment("super")?;
- }
- }
- PathKind::Crate => add_segment("crate")?,
- PathKind::Abs => add_segment("")?,
- PathKind::DollarCrate(_) => add_segment("$crate")?,
- }
- for segment in &self.segments {
- if !first_segment {
- f.write_str("::")?;
- }
- first_segment = false;
- write!(f, "{}", segment)?;
- }
- Ok(())
- }
-}
-
-pub use hir_expand::name as __name;
-
-#[macro_export]
-macro_rules! __known_path {
- (core::iter::IntoIterator) => {};
- (core::iter::Iterator) => {};
- (core::result::Result) => {};
- (core::option::Option) => {};
- (core::ops::Range) => {};
- (core::ops::RangeFrom) => {};
- (core::ops::RangeFull) => {};
- (core::ops::RangeTo) => {};
- (core::ops::RangeToInclusive) => {};
- (core::ops::RangeInclusive) => {};
- (core::future::Future) => {};
- (core::ops::Try) => {};
- ($path:path) => {
- compile_error!("Please register your known path in the path module")
- };
-}
-
-#[macro_export]
-macro_rules! __path {
- ($start:ident $(:: $seg:ident)*) => ({
- $crate::__known_path!($start $(:: $seg)*);
- $crate::path::ModPath::from_segments($crate::path::PathKind::Abs, vec![
- $crate::path::__name![$start], $($crate::path::__name![$seg],)*
- ])
- });
-}
-
-pub use crate::__path as path;