diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index ceffee9b8760..b8752cbad52a 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs @@ -590,7 +590,7 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option> { } ps.push(chain.into()); } - hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None, + hir::PathKind::DollarCrate(_) => return None, } ps.extend(path.segments().iter().map(|it| it.name.to_string().into())); Some(ps) diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 7787cb87ffe1..d4cab0561409 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -15,7 +15,7 @@ use crate::{ db::DefDatabase, expr::{Expr, ExprId, Pat, PatId}, nameres::{BuiltinShadowMode, CrateDefMap}, - path::Path, + path::{ModPath, Path}, src::HasSource, DefWithBodyId, HasModule, Lookup, ModuleId, }; @@ -44,7 +44,7 @@ impl Expander { db.ast_id_map(self.current_file_id).ast_id(¯o_call), ); - if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) { + if let Some(path) = macro_call.path().and_then(|path| self.parse_mod_path(path)) { if let Some(def) = self.resolve_path_as_macro(db, &path) { let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id)); let file_id = call_id.as_file(); @@ -81,9 +81,13 @@ impl Expander { Path::from_src(path, &self.hygiene) } - fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option { + fn parse_mod_path(&mut self, path: ast::Path) -> Option { + ModPath::from_src(path, &self.hygiene) + } + + fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &ModPath) -> Option { self.crate_def_map - .resolve_path(db, self.module.local_id, path.mod_path(), BuiltinShadowMode::Other) + .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other) .0 .take_macros() } diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs index 1dbc4f3715ec..2dd779b66e66 100644 --- a/crates/ra_hir_def/src/nameres/path_resolution.rs +++ b/crates/ra_hir_def/src/nameres/path_resolution.rs @@ -145,11 +145,6 @@ impl CrateDefMap { return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude } } - PathKind::Type(_) => { - // This is handled in `infer::infer_path_expr` - // The result returned here does not matter - return ResolvePathResult::empty(ReachedFixedPoint::Yes); - } }; for (i, segment) in segments { diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 3b26e8337fbf..7302cf0f187f 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -18,6 +18,18 @@ pub struct ModPath { pub segments: Vec, } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum PathKind { + Plain, + /// `self::` is `Super(0)` + Super(u8), + Crate, + /// Absolute path (::foo) + Abs, + /// `$crate` from macro expansion + DollarCrate(CrateId), +} + impl ModPath { pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option { lower::lower_path(path, hygiene).map(|it| it.mod_path) @@ -70,6 +82,9 @@ impl ModPath { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { + /// Type based path like `::foo`. + /// Note that paths like `::foo` are desugard to `Trait::::foo`. + type_anchor: Option>, mod_path: ModPath, /// Invariant: the same len as self.path.segments generic_args: Vec>>, @@ -97,19 +112,6 @@ pub enum GenericArg { // or lifetime... } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum PathKind { - Plain, - Super(u8), - Crate, - // Absolute path - Abs, - // Type based path like `::foo` - Type(Box), - // `$crate` from macro expansion - DollarCrate(CrateId), -} - impl Path { /// Converts an `ast::Path` to `Path`. Works with use trees. /// DEPRECATED: It does not handle `$crate` from macro call. @@ -125,18 +127,17 @@ impl Path { /// Converts an `ast::NameRef` into a single-identifier `Path`. pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path { - Path { mod_path: name_ref.as_name().into(), generic_args: vec![None] } - } - - /// `true` if this path is just a standalone `self` - pub fn is_self(&self) -> bool { - self.mod_path.is_self() + Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] } } pub fn kind(&self) -> &PathKind { &self.mod_path.kind } + pub fn type_anchor(&self) -> Option<&TypeRef> { + self.type_anchor.as_ref().map(|it| &**it) + } + pub fn segments(&self) -> PathSegments<'_> { PathSegments { segments: self.mod_path.segments.as_slice(), @@ -153,6 +154,7 @@ impl Path { return None; } let res = Path { + type_anchor: self.type_anchor.clone(), mod_path: ModPath { kind: self.mod_path.kind.clone(), segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(), @@ -225,6 +227,7 @@ impl GenericArgs { impl From for Path { fn from(name: Name) -> Path { Path { + type_anchor: None, mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)), generic_args: vec![None], } diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index c71b52d8988e..62aafd508e14 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs @@ -22,6 +22,7 @@ pub(super) use lower_use::lower_use_tree; /// It correctly handles `$crate` based path from macro call. pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option { let mut kind = PathKind::Plain; + let mut type_anchor = None; let mut segments = Vec::new(); let mut generic_args = Vec::new(); loop { @@ -63,7 +64,8 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option match trait_ref { // ::foo None => { - kind = PathKind::Type(Box::new(self_type)); + type_anchor = Some(Box::new(self_type)); + kind = PathKind::Plain; } // >::Foo desugars to Trait::Foo Some(trait_ref) => { @@ -111,7 +113,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option segments.reverse(); generic_args.reverse(); let mod_path = ModPath { kind, segments }; - return Some(Path { mod_path, generic_args }); + return Some(Path { type_anchor, mod_path, generic_args }); fn qualifier(path: &ast::Path) -> Option { if let Some(q) = path.qualifier() { diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 3bae0ca6c291..402a89386ba6 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -3,7 +3,7 @@ use std::iter; use hir_def::{ - path::{Path, PathKind, PathSegment}, + path::{Path, PathSegment}, resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, AssocItemId, ContainerId, Lookup, }; @@ -32,7 +32,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { path: &Path, id: ExprOrPatId, ) -> Option { - let (value, self_subst) = if let PathKind::Type(type_ref) = path.kind() { + let (value, self_subst) = if let Some(type_ref) = path.type_anchor() { if path.segments().is_empty() { // This can't actually happen syntax-wise return None; diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index a4ddfc8efb65..2b84309d7aac 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use hir_def::{ builtin_type::BuiltinType, generics::WherePredicate, - path::{GenericArg, Path, PathKind, PathSegment, PathSegments}, + path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, @@ -101,7 +101,7 @@ impl Ty { TypeRef::Path(path) => path, _ => return None, }; - if let PathKind::Type(_) = path.kind() { + if path.type_anchor().is_some() { return None; } if path.segments().len() > 1 { @@ -202,7 +202,7 @@ impl Ty { pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { // Resolve the path (in type namespace) - if let PathKind::Type(type_ref) = path.kind() { + if let Some(type_ref) = path.type_anchor() { let ty = Ty::from_hir(db, resolver, &type_ref); return Ty::from_type_relative_path(db, resolver, ty, path.segments()); }