mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Use different types for path with and without generics
This commit is contained in:
parent
f720855e1e
commit
2619950b3b
18 changed files with 473 additions and 356 deletions
|
@ -578,7 +578,7 @@ fn apply_auto_import(
|
|||
|
||||
fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
|
||||
let mut ps = Vec::<SmolStr>::with_capacity(10);
|
||||
match path.kind {
|
||||
match path.kind() {
|
||||
hir::PathKind::Abs => ps.push("".into()),
|
||||
hir::PathKind::Crate => ps.push("crate".into()),
|
||||
hir::PathKind::Plain => {}
|
||||
|
@ -586,9 +586,7 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
|
|||
hir::PathKind::Super => ps.push("super".into()),
|
||||
hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None,
|
||||
}
|
||||
for s in path.segments.iter() {
|
||||
ps.push(s.name.to_string().into());
|
||||
}
|
||||
ps.extend(path.segments().iter().map(|it| it.name.to_string().into()));
|
||||
Some(ps)
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ pub use hir_def::{
|
|||
builtin_type::BuiltinType,
|
||||
docs::Documentation,
|
||||
nameres::ModuleSource,
|
||||
path::{Path, PathKind},
|
||||
path::{ModPath, Path, PathKind},
|
||||
type_ref::Mutability,
|
||||
};
|
||||
pub use hir_expand::{
|
||||
|
|
|
@ -258,7 +258,7 @@ impl SourceAnalyzer {
|
|||
) -> Option<MacroDef> {
|
||||
let hygiene = Hygiene::new(db, macro_call.file_id);
|
||||
let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?;
|
||||
self.resolver.resolve_path_as_macro(db, &path).map(|it| it.into())
|
||||
self.resolver.resolve_path_as_macro(db, path.mod_path()).map(|it| it.into())
|
||||
}
|
||||
|
||||
pub fn resolve_hir_path(
|
||||
|
@ -266,7 +266,8 @@ impl SourceAnalyzer {
|
|||
db: &impl HirDatabase,
|
||||
path: &crate::Path,
|
||||
) -> Option<PathResolution> {
|
||||
let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty {
|
||||
let types =
|
||||
self.resolver.resolve_path_in_type_ns_fully(db, path.mod_path()).map(|ty| match ty {
|
||||
TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
|
||||
TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
|
||||
TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
|
||||
|
@ -277,7 +278,8 @@ impl SourceAnalyzer {
|
|||
TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
|
||||
TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
|
||||
});
|
||||
let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
|
||||
let values =
|
||||
self.resolver.resolve_path_in_value_ns_fully(db, path.mod_path()).and_then(|val| {
|
||||
let res = match val {
|
||||
ValueNs::LocalBinding(pat_id) => {
|
||||
let var = Local { parent: self.body_owner?, pat_id };
|
||||
|
@ -294,12 +296,12 @@ impl SourceAnalyzer {
|
|||
|
||||
let items = self
|
||||
.resolver
|
||||
.resolve_module_path_in_items(db, &path)
|
||||
.resolve_module_path_in_items(db, path.mod_path())
|
||||
.take_types()
|
||||
.map(|it| PathResolution::Def(it.into()));
|
||||
types.or(values).or(items).or_else(|| {
|
||||
self.resolver
|
||||
.resolve_path_as_macro(db, &path)
|
||||
.resolve_path_as_macro(db, path.mod_path())
|
||||
.map(|def| PathResolution::Macro(def.into()))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use ra_syntax::{
|
|||
use tt::Subtree;
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase, path::Path, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup,
|
||||
db::DefDatabase, path::ModPath, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup,
|
||||
};
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -94,7 +94,7 @@ impl Attrs {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Attr {
|
||||
pub(crate) path: Path,
|
||||
pub(crate) path: ModPath,
|
||||
pub(crate) input: Option<AttrInput>,
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ pub enum AttrInput {
|
|||
|
||||
impl Attr {
|
||||
fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
|
||||
let path = Path::from_src(ast.path()?, hygiene)?;
|
||||
let path = ModPath::from_src(ast.path()?, hygiene)?;
|
||||
let input = match ast.input() {
|
||||
None => None,
|
||||
Some(ast::AttrInput::Literal(lit)) => {
|
||||
|
|
|
@ -83,7 +83,7 @@ impl Expander {
|
|||
|
||||
fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
|
||||
self.crate_def_map
|
||||
.resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
|
||||
.resolve_path(db, self.module.local_id, path.mod_path(), BuiltinShadowMode::Other)
|
||||
.0
|
||||
.take_macros()
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ use crate::{
|
|||
builtin_type::BuiltinType,
|
||||
db::DefDatabase,
|
||||
nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
|
||||
path::Path,
|
||||
path::ModPath,
|
||||
per_ns::PerNs,
|
||||
AstId, FunctionId, ImplId, LocalImportId, LocalModuleId, ModuleDefId, ModuleId, TraitId,
|
||||
};
|
||||
|
@ -329,7 +329,7 @@ impl CrateDefMap {
|
|||
&self,
|
||||
db: &impl DefDatabase,
|
||||
original_module: LocalModuleId,
|
||||
path: &Path,
|
||||
path: &ModPath,
|
||||
shadow: BuiltinShadowMode,
|
||||
) -> (PerNs, Option<usize>) {
|
||||
let res =
|
||||
|
|
|
@ -22,7 +22,7 @@ use crate::{
|
|||
diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
|
||||
raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, Resolution, ResolveMode,
|
||||
},
|
||||
path::{Path, PathKind},
|
||||
path::{ModPath, PathKind},
|
||||
per_ns::PerNs,
|
||||
AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
|
||||
LocalImportId, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc,
|
||||
|
@ -101,7 +101,7 @@ struct ImportDirective {
|
|||
struct MacroDirective {
|
||||
module_id: LocalModuleId,
|
||||
ast_id: AstId<ast::MacroCall>,
|
||||
path: Path,
|
||||
path: ModPath,
|
||||
legacy: Option<MacroCallId>,
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ struct DefCollector<'a, DB> {
|
|||
unresolved_imports: Vec<ImportDirective>,
|
||||
resolved_imports: Vec<ImportDirective>,
|
||||
unexpanded_macros: Vec<MacroDirective>,
|
||||
unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, Path)>,
|
||||
unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, ModPath)>,
|
||||
mod_dirs: FxHashMap<LocalModuleId, ModDir>,
|
||||
cfg_options: &'a CfgOptions,
|
||||
}
|
||||
|
@ -428,7 +428,7 @@ where
|
|||
} else {
|
||||
match import.path.segments.last() {
|
||||
Some(last_segment) => {
|
||||
let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
|
||||
let name = import.alias.clone().unwrap_or_else(|| last_segment.clone());
|
||||
log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
|
||||
|
||||
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
|
||||
|
@ -565,7 +565,7 @@ where
|
|||
res
|
||||
}
|
||||
|
||||
fn resolve_attribute_macro(&self, path: &Path) -> Option<MacroDefId> {
|
||||
fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> {
|
||||
// FIXME this is currently super hacky, just enough to support the
|
||||
// built-in derives
|
||||
if let Some(name) = path.as_ident() {
|
||||
|
@ -829,7 +829,7 @@ where
|
|||
tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok
|
||||
_ => continue, // anything else would be an error (which we currently ignore)
|
||||
};
|
||||
let path = Path::from_tt_ident(ident);
|
||||
let path = ModPath::from_tt_ident(ident);
|
||||
|
||||
let ast_id = AstId::new(self.file_id, def.kind.ast_id());
|
||||
self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path));
|
||||
|
@ -917,7 +917,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn is_macro_rules(path: &Path) -> bool {
|
||||
fn is_macro_rules(path: &ModPath) -> bool {
|
||||
path.as_ident() == Some(&name![macro_rules])
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ use test_utils::tested_by;
|
|||
use crate::{
|
||||
db::DefDatabase,
|
||||
nameres::{BuiltinShadowMode, CrateDefMap},
|
||||
path::{Path, PathKind},
|
||||
path::{ModPath, PathKind},
|
||||
per_ns::PerNs,
|
||||
AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
|
||||
};
|
||||
|
@ -69,7 +69,7 @@ impl CrateDefMap {
|
|||
db: &impl DefDatabase,
|
||||
mode: ResolveMode,
|
||||
original_module: LocalModuleId,
|
||||
path: &Path,
|
||||
path: &ModPath,
|
||||
shadow: BuiltinShadowMode,
|
||||
) -> ResolvePathResult {
|
||||
// if it is not the last segment, we prefer the module to the builtin
|
||||
|
@ -113,7 +113,7 @@ impl CrateDefMap {
|
|||
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
|
||||
};
|
||||
log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
|
||||
self.resolve_name_in_crate_root_or_extern_prelude(&segment.name, prefer_module(idx))
|
||||
self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx))
|
||||
}
|
||||
PathKind::Plain => {
|
||||
let (idx, segment) = match segments.next() {
|
||||
|
@ -121,7 +121,7 @@ impl CrateDefMap {
|
|||
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
|
||||
};
|
||||
log::debug!("resolving {:?} in module", segment);
|
||||
self.resolve_name_in_module(db, original_module, &segment.name, prefer_module(idx))
|
||||
self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx))
|
||||
}
|
||||
PathKind::Super => {
|
||||
if let Some(p) = self.modules[original_module].parent {
|
||||
|
@ -137,7 +137,7 @@ impl CrateDefMap {
|
|||
Some((_, segment)) => segment,
|
||||
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
|
||||
};
|
||||
if let Some(def) = self.extern_prelude.get(&segment.name) {
|
||||
if let Some(def) = self.extern_prelude.get(&segment) {
|
||||
log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
|
||||
PerNs::types(*def)
|
||||
} else {
|
||||
|
@ -168,8 +168,10 @@ impl CrateDefMap {
|
|||
curr_per_ns = match curr {
|
||||
ModuleDefId::ModuleId(module) => {
|
||||
if module.krate != self.krate {
|
||||
let path =
|
||||
Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
|
||||
let path = ModPath {
|
||||
segments: path.segments[i..].to_vec(),
|
||||
kind: PathKind::Self_,
|
||||
};
|
||||
log::debug!("resolving {:?} in other crate", path);
|
||||
let defp_map = db.crate_def_map(module.krate);
|
||||
let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
|
||||
|
@ -182,10 +184,10 @@ impl CrateDefMap {
|
|||
}
|
||||
|
||||
// Since it is a qualified path here, it should not contains legacy macros
|
||||
match self[module.local_id].scope.get(&segment.name, prefer_module(i)) {
|
||||
match self[module.local_id].scope.get(&segment, prefer_module(i)) {
|
||||
Some(res) => res.def,
|
||||
_ => {
|
||||
log::debug!("path segment {:?} not found", segment.name);
|
||||
log::debug!("path segment {:?} not found", segment);
|
||||
return ResolvePathResult::empty(ReachedFixedPoint::No);
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +196,7 @@ impl CrateDefMap {
|
|||
// enum variant
|
||||
tested_by!(can_import_enum_variant);
|
||||
let enum_data = db.enum_data(e);
|
||||
match enum_data.variant(&segment.name) {
|
||||
match enum_data.variant(&segment) {
|
||||
Some(local_id) => {
|
||||
let variant = EnumVariantId { parent: e, local_id };
|
||||
PerNs::both(variant.into(), variant.into())
|
||||
|
@ -214,7 +216,7 @@ impl CrateDefMap {
|
|||
// (`Struct::method`), or some other kind of associated item
|
||||
log::debug!(
|
||||
"path segment {:?} resolved to non-module {:?}, but is not last",
|
||||
segment.name,
|
||||
segment,
|
||||
curr,
|
||||
);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use ra_syntax::{
|
|||
use test_utils::tested_by;
|
||||
|
||||
use crate::{
|
||||
attr::Attrs, db::DefDatabase, path::Path, trace::Trace, FileAstId, HirFileId, InFile,
|
||||
attr::Attrs, db::DefDatabase, path::ModPath, trace::Trace, FileAstId, HirFileId, InFile,
|
||||
LocalImportId,
|
||||
};
|
||||
|
||||
|
@ -154,7 +154,7 @@ pub(super) enum ModuleData {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ImportData {
|
||||
pub(super) path: Path,
|
||||
pub(super) path: ModPath,
|
||||
pub(super) alias: Option<Name>,
|
||||
pub(super) is_glob: bool,
|
||||
pub(super) is_prelude: bool,
|
||||
|
@ -206,7 +206,7 @@ impl_arena_id!(Macro);
|
|||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(super) struct MacroData {
|
||||
pub(super) ast_id: FileAstId<ast::MacroCall>,
|
||||
pub(super) path: Path,
|
||||
pub(super) path: ModPath,
|
||||
pub(super) name: Option<Name>,
|
||||
pub(super) export: bool,
|
||||
pub(super) builtin: bool,
|
||||
|
@ -327,7 +327,7 @@ impl RawItemsCollector {
|
|||
let attrs = self.parse_attrs(&use_item);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
Path::expand_use_item(
|
||||
ModPath::expand_use_item(
|
||||
InFile { value: use_item, file_id: self.file_id },
|
||||
&self.hygiene,
|
||||
|path, use_tree, is_glob, alias| {
|
||||
|
@ -353,7 +353,7 @@ impl RawItemsCollector {
|
|||
extern_crate: ast::ExternCrateItem,
|
||||
) {
|
||||
if let Some(name_ref) = extern_crate.name_ref() {
|
||||
let path = Path::from_name_ref(&name_ref);
|
||||
let path = ModPath::from_name_ref(&name_ref);
|
||||
let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
|
||||
let attrs = self.parse_attrs(&extern_crate);
|
||||
// FIXME: cfg_attr
|
||||
|
@ -377,7 +377,7 @@ impl RawItemsCollector {
|
|||
|
||||
fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
|
||||
let attrs = self.parse_attrs(&m);
|
||||
let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) {
|
||||
let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) {
|
||||
Some(it) => it,
|
||||
_ => return,
|
||||
};
|
||||
|
|
|
@ -1,31 +1,78 @@
|
|||
//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
|
||||
mod lower_use;
|
||||
mod lower;
|
||||
|
||||
use std::{iter, sync::Arc};
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
hygiene::Hygiene,
|
||||
name::{name, AsName, Name},
|
||||
name::{AsName, Name},
|
||||
};
|
||||
use ra_db::CrateId;
|
||||
use ra_syntax::{
|
||||
ast::{self, TypeAscriptionOwner},
|
||||
AstNode,
|
||||
};
|
||||
use ra_syntax::ast;
|
||||
|
||||
use crate::{type_ref::TypeRef, InFile};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Path {
|
||||
pub struct ModPath {
|
||||
pub kind: PathKind,
|
||||
pub segments: Vec<PathSegment>,
|
||||
pub segments: Vec<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_simple_segments(
|
||||
kind: PathKind,
|
||||
segments: impl IntoIterator<Item = Name>,
|
||||
) -> ModPath {
|
||||
let segments = segments.into_iter().collect::<Vec<_>>();
|
||||
ModPath { kind, segments }
|
||||
}
|
||||
|
||||
pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
|
||||
name_ref.as_name().into()
|
||||
}
|
||||
|
||||
/// Converts an `tt::Ident` into a single-identifier `Path`.
|
||||
pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
|
||||
ident.as_name().into()
|
||||
}
|
||||
|
||||
/// Calls `cb` with all paths, represented by this use item.
|
||||
pub(crate) fn expand_use_item(
|
||||
item_src: InFile<ast::UseItem>,
|
||||
hygiene: &Hygiene,
|
||||
mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>),
|
||||
) {
|
||||
if let Some(tree) = item_src.value.use_tree() {
|
||||
lower::lower_use_tree(None, tree, hygiene, &mut cb);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ident(&self) -> bool {
|
||||
self.kind == PathKind::Plain && self.segments.len() == 1
|
||||
}
|
||||
|
||||
pub fn is_self(&self) -> bool {
|
||||
self.kind == PathKind::Self_ && 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 || self.segments.len() > 1 {
|
||||
return None;
|
||||
}
|
||||
self.segments.first()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct PathSegment {
|
||||
pub name: Name,
|
||||
pub args_and_bindings: Option<Arc<GenericArgs>>,
|
||||
pub struct Path {
|
||||
mod_path: ModPath,
|
||||
/// Invariant: the same len as self.path.segments
|
||||
generic_args: Vec<Option<Arc<GenericArgs>>>,
|
||||
}
|
||||
|
||||
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
|
||||
|
@ -65,221 +112,110 @@ pub enum PathKind {
|
|||
}
|
||||
|
||||
impl Path {
|
||||
/// Calls `cb` with all paths, represented by this use item.
|
||||
pub(crate) fn expand_use_item(
|
||||
item_src: InFile<ast::UseItem>,
|
||||
hygiene: &Hygiene,
|
||||
mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
|
||||
) {
|
||||
if let Some(tree) = item_src.value.use_tree() {
|
||||
lower_use::lower_use_tree(None, tree, hygiene, &mut cb);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> Path {
|
||||
Path {
|
||||
kind,
|
||||
segments: segments
|
||||
.into_iter()
|
||||
.map(|name| PathSegment { name, args_and_bindings: None })
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts an `ast::Path` to `Path`. Works with use trees.
|
||||
/// DEPRECATED: It does not handle `$crate` from macro call.
|
||||
pub fn from_ast(path: ast::Path) -> Option<Path> {
|
||||
Path::from_src(path, &Hygiene::new_unhygienic())
|
||||
lower::lower_path(path, &Hygiene::new_unhygienic())
|
||||
}
|
||||
|
||||
/// Converts an `ast::Path` to `Path`. Works with use trees.
|
||||
/// It correctly handles `$crate` based path from macro call.
|
||||
pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
|
||||
let mut kind = PathKind::Plain;
|
||||
let mut segments = Vec::new();
|
||||
loop {
|
||||
let segment = path.segment()?;
|
||||
|
||||
if segment.has_colon_colon() {
|
||||
kind = PathKind::Abs;
|
||||
}
|
||||
|
||||
match segment.kind()? {
|
||||
ast::PathSegmentKind::Name(name_ref) => {
|
||||
// FIXME: this should just return name
|
||||
match hygiene.name_ref_to_name(name_ref) {
|
||||
Either::Left(name) => {
|
||||
let args = segment
|
||||
.type_arg_list()
|
||||
.and_then(GenericArgs::from_ast)
|
||||
.or_else(|| {
|
||||
GenericArgs::from_fn_like_path_ast(
|
||||
segment.param_list(),
|
||||
segment.ret_type(),
|
||||
)
|
||||
})
|
||||
.map(Arc::new);
|
||||
let segment = PathSegment { name, args_and_bindings: args };
|
||||
segments.push(segment);
|
||||
}
|
||||
Either::Right(crate_id) => {
|
||||
kind = PathKind::DollarCrate(crate_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::PathSegmentKind::Type { type_ref, trait_ref } => {
|
||||
assert!(path.qualifier().is_none()); // this can only occur at the first segment
|
||||
|
||||
let self_type = TypeRef::from_ast(type_ref?);
|
||||
|
||||
match trait_ref {
|
||||
// <T>::foo
|
||||
None => {
|
||||
kind = PathKind::Type(Box::new(self_type));
|
||||
}
|
||||
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
|
||||
Some(trait_ref) => {
|
||||
let path = Path::from_src(trait_ref.path()?, hygiene)?;
|
||||
kind = path.kind;
|
||||
let mut prefix_segments = path.segments;
|
||||
prefix_segments.reverse();
|
||||
segments.extend(prefix_segments);
|
||||
// Insert the type reference (T in the above example) as Self parameter for the trait
|
||||
let mut last_segment = segments.last_mut()?;
|
||||
if last_segment.args_and_bindings.is_none() {
|
||||
last_segment.args_and_bindings =
|
||||
Some(Arc::new(GenericArgs::empty()));
|
||||
};
|
||||
let args = last_segment.args_and_bindings.as_mut().unwrap();
|
||||
let mut args_inner = Arc::make_mut(args);
|
||||
args_inner.has_self_type = true;
|
||||
args_inner.args.insert(0, GenericArg::Type(self_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::PathSegmentKind::CrateKw => {
|
||||
kind = PathKind::Crate;
|
||||
break;
|
||||
}
|
||||
ast::PathSegmentKind::SelfKw => {
|
||||
kind = PathKind::Self_;
|
||||
break;
|
||||
}
|
||||
ast::PathSegmentKind::SuperKw => {
|
||||
kind = PathKind::Super;
|
||||
break;
|
||||
}
|
||||
}
|
||||
path = match qualifier(&path) {
|
||||
Some(it) => it,
|
||||
None => break,
|
||||
};
|
||||
}
|
||||
segments.reverse();
|
||||
return Some(Path { kind, segments });
|
||||
|
||||
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
|
||||
if let Some(q) = path.qualifier() {
|
||||
return Some(q);
|
||||
}
|
||||
// FIXME: this bottom up traversal is not too precise.
|
||||
// Should we handle do a top-down analysis, recording results?
|
||||
let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
|
||||
let use_tree = use_tree_list.parent_use_tree();
|
||||
use_tree.path()
|
||||
}
|
||||
pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
|
||||
lower::lower_path(path, hygiene)
|
||||
}
|
||||
|
||||
/// Converts an `ast::NameRef` into a single-identifier `Path`.
|
||||
pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
|
||||
name_ref.as_name().into()
|
||||
}
|
||||
|
||||
/// Converts an `tt::Ident` into a single-identifier `Path`.
|
||||
pub(crate) fn from_tt_ident(ident: &tt::Ident) -> Path {
|
||||
ident.as_name().into()
|
||||
}
|
||||
|
||||
/// `true` is this path is a single identifier, like `foo`
|
||||
pub fn is_ident(&self) -> bool {
|
||||
self.kind == PathKind::Plain && self.segments.len() == 1
|
||||
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.kind == PathKind::Self_ && self.segments.is_empty()
|
||||
self.mod_path.is_self()
|
||||
}
|
||||
|
||||
/// If this path is a single identifier, like `foo`, return its name.
|
||||
pub fn as_ident(&self) -> Option<&Name> {
|
||||
if self.kind != PathKind::Plain || self.segments.len() > 1 {
|
||||
pub fn kind(&self) -> &PathKind {
|
||||
&self.mod_path.kind
|
||||
}
|
||||
|
||||
pub fn segments(&self) -> PathSegments<'_> {
|
||||
PathSegments {
|
||||
segments: self.mod_path.segments.as_slice(),
|
||||
generic_args: self.generic_args.as_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mod_path(&self) -> &ModPath {
|
||||
&self.mod_path
|
||||
}
|
||||
|
||||
pub fn qualifier(&self) -> Option<Path> {
|
||||
if self.mod_path.is_ident() {
|
||||
return None;
|
||||
}
|
||||
self.segments.first().map(|s| &s.name)
|
||||
let res = Path {
|
||||
mod_path: ModPath {
|
||||
kind: self.mod_path.kind.clone(),
|
||||
segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
|
||||
},
|
||||
generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_macro_expr(&self) -> Option<Name> {
|
||||
self.as_ident().and_then(|name| Some(name.clone()))
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct PathSegment<'a> {
|
||||
pub name: &'a Name,
|
||||
pub args_and_bindings: Option<&'a GenericArgs>,
|
||||
}
|
||||
|
||||
pub fn is_type_relative(&self) -> bool {
|
||||
match self.kind {
|
||||
PathKind::Type(_) => true,
|
||||
_ => false,
|
||||
pub struct PathSegments<'a> {
|
||||
segments: &'a [Name],
|
||||
generic_args: &'a [Option<Arc<GenericArgs>>],
|
||||
}
|
||||
|
||||
impl<'a> PathSegments<'a> {
|
||||
pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.segments.len()
|
||||
}
|
||||
pub fn first(&self) -> Option<PathSegment<'a>> {
|
||||
self.get(0)
|
||||
}
|
||||
pub fn last(&self) -> Option<PathSegment<'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),
|
||||
};
|
||||
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..] }
|
||||
}
|
||||
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] }
|
||||
}
|
||||
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),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericArgs {
|
||||
pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
|
||||
let mut args = Vec::new();
|
||||
for type_arg in node.type_args() {
|
||||
let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
|
||||
args.push(GenericArg::Type(type_ref));
|
||||
}
|
||||
// lifetimes ignored for now
|
||||
let mut bindings = Vec::new();
|
||||
for assoc_type_arg in node.assoc_type_args() {
|
||||
if let Some(name_ref) = assoc_type_arg.name_ref() {
|
||||
let name = name_ref.as_name();
|
||||
let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
|
||||
bindings.push((name, type_ref));
|
||||
}
|
||||
}
|
||||
if args.is_empty() && bindings.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(GenericArgs { args, has_self_type: false, bindings })
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
|
||||
/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
|
||||
pub(crate) fn from_fn_like_path_ast(
|
||||
params: Option<ast::ParamList>,
|
||||
ret_type: Option<ast::RetType>,
|
||||
) -> Option<GenericArgs> {
|
||||
let mut args = Vec::new();
|
||||
let mut bindings = Vec::new();
|
||||
if let Some(params) = params {
|
||||
let mut param_types = Vec::new();
|
||||
for param in params.params() {
|
||||
let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
|
||||
param_types.push(type_ref);
|
||||
}
|
||||
let arg = GenericArg::Type(TypeRef::Tuple(param_types));
|
||||
args.push(arg);
|
||||
}
|
||||
if let Some(ret_type) = ret_type {
|
||||
let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
|
||||
bindings.push((name![Output], type_ref))
|
||||
}
|
||||
if args.is_empty() && bindings.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(GenericArgs { args, has_self_type: false, bindings })
|
||||
}
|
||||
lower::lower_generic_args(node)
|
||||
}
|
||||
|
||||
pub(crate) fn empty() -> GenericArgs {
|
||||
|
@ -289,7 +225,16 @@ impl GenericArgs {
|
|||
|
||||
impl From<Name> for Path {
|
||||
fn from(name: Name) -> Path {
|
||||
Path::from_simple_segments(PathKind::Plain, iter::once(name))
|
||||
Path {
|
||||
mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
|
||||
generic_args: vec![None],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Name> for ModPath {
|
||||
fn from(name: Name) -> ModPath {
|
||||
ModPath::from_simple_segments(PathKind::Plain, iter::once(name))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,7 +264,7 @@ macro_rules! __known_path {
|
|||
macro_rules! __path {
|
||||
($start:ident $(:: $seg:ident)*) => ({
|
||||
$crate::__known_path!($start $(:: $seg)*);
|
||||
$crate::path::Path::from_simple_segments($crate::path::PathKind::Abs, vec![
|
||||
$crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![
|
||||
$crate::path::__name![$start], $($crate::path::__name![$seg],)*
|
||||
])
|
||||
});
|
||||
|
|
176
crates/ra_hir_def/src/path/lower.rs
Normal file
176
crates/ra_hir_def/src/path/lower.rs
Normal file
|
@ -0,0 +1,176 @@
|
|||
//! Transforms syntax into `Path` objects, ideally with accounting for hygiene
|
||||
|
||||
mod lower_use;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
hygiene::Hygiene,
|
||||
name::{name, AsName},
|
||||
};
|
||||
use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner};
|
||||
|
||||
use crate::{
|
||||
path::{GenericArg, GenericArgs, ModPath, Path, PathKind},
|
||||
type_ref::TypeRef,
|
||||
};
|
||||
|
||||
pub(super) use lower_use::lower_use_tree;
|
||||
|
||||
/// Converts an `ast::Path` to `Path`. Works with use trees.
|
||||
/// It correctly handles `$crate` based path from macro call.
|
||||
pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
|
||||
let mut kind = PathKind::Plain;
|
||||
let mut segments = Vec::new();
|
||||
let mut generic_args = Vec::new();
|
||||
loop {
|
||||
let segment = path.segment()?;
|
||||
|
||||
if segment.has_colon_colon() {
|
||||
kind = PathKind::Abs;
|
||||
}
|
||||
|
||||
match segment.kind()? {
|
||||
ast::PathSegmentKind::Name(name_ref) => {
|
||||
// FIXME: this should just return name
|
||||
match hygiene.name_ref_to_name(name_ref) {
|
||||
Either::Left(name) => {
|
||||
let args = segment
|
||||
.type_arg_list()
|
||||
.and_then(lower_generic_args)
|
||||
.or_else(|| {
|
||||
lower_generic_args_from_fn_path(
|
||||
segment.param_list(),
|
||||
segment.ret_type(),
|
||||
)
|
||||
})
|
||||
.map(Arc::new);
|
||||
segments.push(name);
|
||||
generic_args.push(args)
|
||||
}
|
||||
Either::Right(crate_id) => {
|
||||
kind = PathKind::DollarCrate(crate_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::PathSegmentKind::Type { type_ref, trait_ref } => {
|
||||
assert!(path.qualifier().is_none()); // this can only occur at the first segment
|
||||
|
||||
let self_type = TypeRef::from_ast(type_ref?);
|
||||
|
||||
match trait_ref {
|
||||
// <T>::foo
|
||||
None => {
|
||||
kind = PathKind::Type(Box::new(self_type));
|
||||
}
|
||||
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
|
||||
Some(trait_ref) => {
|
||||
let path = Path::from_src(trait_ref.path()?, hygiene)?;
|
||||
kind = path.mod_path.kind;
|
||||
|
||||
let mut prefix_segments = path.mod_path.segments;
|
||||
prefix_segments.reverse();
|
||||
segments.extend(prefix_segments);
|
||||
|
||||
let mut prefix_args = path.generic_args;
|
||||
prefix_args.reverse();
|
||||
generic_args.extend(prefix_args);
|
||||
|
||||
// Insert the type reference (T in the above example) as Self parameter for the trait
|
||||
let last_segment = generic_args.last_mut()?;
|
||||
if last_segment.is_none() {
|
||||
*last_segment = Some(Arc::new(GenericArgs::empty()));
|
||||
};
|
||||
let args = last_segment.as_mut().unwrap();
|
||||
let mut args_inner = Arc::make_mut(args);
|
||||
args_inner.has_self_type = true;
|
||||
args_inner.args.insert(0, GenericArg::Type(self_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::PathSegmentKind::CrateKw => {
|
||||
kind = PathKind::Crate;
|
||||
break;
|
||||
}
|
||||
ast::PathSegmentKind::SelfKw => {
|
||||
kind = PathKind::Self_;
|
||||
break;
|
||||
}
|
||||
ast::PathSegmentKind::SuperKw => {
|
||||
kind = PathKind::Super;
|
||||
break;
|
||||
}
|
||||
}
|
||||
path = match qualifier(&path) {
|
||||
Some(it) => it,
|
||||
None => break,
|
||||
};
|
||||
}
|
||||
segments.reverse();
|
||||
generic_args.reverse();
|
||||
let mod_path = ModPath { kind, segments };
|
||||
return Some(Path { mod_path, generic_args });
|
||||
|
||||
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
|
||||
if let Some(q) = path.qualifier() {
|
||||
return Some(q);
|
||||
}
|
||||
// FIXME: this bottom up traversal is not too precise.
|
||||
// Should we handle do a top-down analysis, recording results?
|
||||
let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
|
||||
let use_tree = use_tree_list.parent_use_tree();
|
||||
use_tree.path()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> {
|
||||
let mut args = Vec::new();
|
||||
for type_arg in node.type_args() {
|
||||
let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
|
||||
args.push(GenericArg::Type(type_ref));
|
||||
}
|
||||
// lifetimes ignored for now
|
||||
let mut bindings = Vec::new();
|
||||
for assoc_type_arg in node.assoc_type_args() {
|
||||
if let Some(name_ref) = assoc_type_arg.name_ref() {
|
||||
let name = name_ref.as_name();
|
||||
let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
|
||||
bindings.push((name, type_ref));
|
||||
}
|
||||
}
|
||||
if args.is_empty() && bindings.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(GenericArgs { args, has_self_type: false, bindings })
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
|
||||
/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
|
||||
fn lower_generic_args_from_fn_path(
|
||||
params: Option<ast::ParamList>,
|
||||
ret_type: Option<ast::RetType>,
|
||||
) -> Option<GenericArgs> {
|
||||
let mut args = Vec::new();
|
||||
let mut bindings = Vec::new();
|
||||
if let Some(params) = params {
|
||||
let mut param_types = Vec::new();
|
||||
for param in params.params() {
|
||||
let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
|
||||
param_types.push(type_ref);
|
||||
}
|
||||
let arg = GenericArg::Type(TypeRef::Tuple(param_types));
|
||||
args.push(arg);
|
||||
}
|
||||
if let Some(ret_type) = ret_type {
|
||||
let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
|
||||
bindings.push((name![Output], type_ref))
|
||||
}
|
||||
if args.is_empty() && bindings.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(GenericArgs { args, has_self_type: false, bindings })
|
||||
}
|
||||
}
|
|
@ -10,13 +10,13 @@ use hir_expand::{
|
|||
};
|
||||
use ra_syntax::ast::{self, NameOwner};
|
||||
|
||||
use crate::path::{Path, PathKind, PathSegment};
|
||||
use crate::path::{ModPath, PathKind};
|
||||
|
||||
pub(crate) fn lower_use_tree(
|
||||
prefix: Option<Path>,
|
||||
prefix: Option<ModPath>,
|
||||
tree: ast::UseTree,
|
||||
hygiene: &Hygiene,
|
||||
cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>),
|
||||
cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<Name>),
|
||||
) {
|
||||
if let Some(use_tree_list) = tree.use_tree_list() {
|
||||
let prefix = match tree.path() {
|
||||
|
@ -57,7 +57,7 @@ pub(crate) fn lower_use_tree(
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
|
||||
fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
|
||||
let prefix = if let Some(qual) = path.qualifier() {
|
||||
Some(convert_path(prefix, qual, hygiene)?)
|
||||
} else {
|
||||
|
@ -70,18 +70,15 @@ fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Opt
|
|||
match hygiene.name_ref_to_name(name_ref) {
|
||||
Either::Left(name) => {
|
||||
// no type args in use
|
||||
let mut res = prefix.unwrap_or_else(|| Path {
|
||||
let mut res = prefix.unwrap_or_else(|| ModPath {
|
||||
kind: PathKind::Plain,
|
||||
segments: Vec::with_capacity(1),
|
||||
});
|
||||
res.segments.push(PathSegment {
|
||||
name,
|
||||
args_and_bindings: None, // no type args in use
|
||||
});
|
||||
res.segments.push(name);
|
||||
res
|
||||
}
|
||||
Either::Right(crate_id) => {
|
||||
return Some(Path::from_simple_segments(
|
||||
return Some(ModPath::from_simple_segments(
|
||||
PathKind::DollarCrate(crate_id),
|
||||
iter::empty(),
|
||||
))
|
||||
|
@ -92,19 +89,19 @@ fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Opt
|
|||
if prefix.is_some() {
|
||||
return None;
|
||||
}
|
||||
Path::from_simple_segments(PathKind::Crate, iter::empty())
|
||||
ModPath::from_simple_segments(PathKind::Crate, iter::empty())
|
||||
}
|
||||
ast::PathSegmentKind::SelfKw => {
|
||||
if prefix.is_some() {
|
||||
return None;
|
||||
}
|
||||
Path::from_simple_segments(PathKind::Self_, iter::empty())
|
||||
ModPath::from_simple_segments(PathKind::Self_, iter::empty())
|
||||
}
|
||||
ast::PathSegmentKind::SuperKw => {
|
||||
if prefix.is_some() {
|
||||
return None;
|
||||
}
|
||||
Path::from_simple_segments(PathKind::Super, iter::empty())
|
||||
ModPath::from_simple_segments(PathKind::Super, iter::empty())
|
||||
}
|
||||
ast::PathSegmentKind::Type { .. } => {
|
||||
// not allowed in imports
|
|
@ -15,7 +15,7 @@ use crate::{
|
|||
expr::{ExprId, PatId},
|
||||
generics::GenericParams,
|
||||
nameres::{BuiltinShadowMode, CrateDefMap},
|
||||
path::{Path, PathKind},
|
||||
path::{ModPath, PathKind},
|
||||
per_ns::PerNs,
|
||||
AdtId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId,
|
||||
HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId,
|
||||
|
@ -91,7 +91,7 @@ pub enum ValueNs {
|
|||
|
||||
impl Resolver {
|
||||
/// Resolve known trait from std, like `std::futures::Future`
|
||||
pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &Path) -> Option<TraitId> {
|
||||
pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &ModPath) -> Option<TraitId> {
|
||||
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
|
||||
match res {
|
||||
ModuleDefId::TraitId(it) => Some(it),
|
||||
|
@ -100,7 +100,7 @@ impl Resolver {
|
|||
}
|
||||
|
||||
/// Resolve known struct from std, like `std::boxed::Box`
|
||||
pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &Path) -> Option<StructId> {
|
||||
pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &ModPath) -> Option<StructId> {
|
||||
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
|
||||
match res {
|
||||
ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it),
|
||||
|
@ -109,7 +109,7 @@ impl Resolver {
|
|||
}
|
||||
|
||||
/// Resolve known enum from std, like `std::result::Result`
|
||||
pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &Path) -> Option<EnumId> {
|
||||
pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &ModPath) -> Option<EnumId> {
|
||||
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
|
||||
match res {
|
||||
ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it),
|
||||
|
@ -120,33 +120,30 @@ impl Resolver {
|
|||
fn resolve_module_path(
|
||||
&self,
|
||||
db: &impl DefDatabase,
|
||||
path: &Path,
|
||||
path: &ModPath,
|
||||
shadow: BuiltinShadowMode,
|
||||
) -> PerNs {
|
||||
let (item_map, module) = match self.module() {
|
||||
Some(it) => it,
|
||||
None => return PerNs::none(),
|
||||
};
|
||||
let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
|
||||
let (module_res, segment_index) = item_map.resolve_path(db, module, &path, shadow);
|
||||
if segment_index.is_some() {
|
||||
return PerNs::none();
|
||||
}
|
||||
module_res
|
||||
}
|
||||
|
||||
pub fn resolve_module_path_in_items(&self, db: &impl DefDatabase, path: &Path) -> PerNs {
|
||||
pub fn resolve_module_path_in_items(&self, db: &impl DefDatabase, path: &ModPath) -> PerNs {
|
||||
self.resolve_module_path(db, path, BuiltinShadowMode::Module)
|
||||
}
|
||||
|
||||
pub fn resolve_path_in_type_ns(
|
||||
&self,
|
||||
db: &impl DefDatabase,
|
||||
path: &Path,
|
||||
path: &ModPath,
|
||||
) -> Option<(TypeNs, Option<usize>)> {
|
||||
if path.is_type_relative() {
|
||||
return None;
|
||||
}
|
||||
let first_name = &path.segments.first()?.name;
|
||||
let first_name = path.segments.first()?;
|
||||
let skip_to_mod = path.kind != PathKind::Plain;
|
||||
for scope in self.scopes.iter().rev() {
|
||||
match scope {
|
||||
|
@ -178,7 +175,7 @@ impl Resolver {
|
|||
let (module_def, idx) = m.crate_def_map.resolve_path(
|
||||
db,
|
||||
m.module_id,
|
||||
path,
|
||||
&path,
|
||||
BuiltinShadowMode::Other,
|
||||
);
|
||||
let res = match module_def.take_types()? {
|
||||
|
@ -205,7 +202,7 @@ impl Resolver {
|
|||
pub fn resolve_path_in_type_ns_fully(
|
||||
&self,
|
||||
db: &impl DefDatabase,
|
||||
path: &Path,
|
||||
path: &ModPath,
|
||||
) -> Option<TypeNs> {
|
||||
let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
|
||||
if unresolved.is_some() {
|
||||
|
@ -214,17 +211,14 @@ impl Resolver {
|
|||
Some(res)
|
||||
}
|
||||
|
||||
pub fn resolve_path_in_value_ns<'p>(
|
||||
pub fn resolve_path_in_value_ns(
|
||||
&self,
|
||||
db: &impl DefDatabase,
|
||||
path: &'p Path,
|
||||
path: &ModPath,
|
||||
) -> Option<ResolveValueResult> {
|
||||
if path.is_type_relative() {
|
||||
return None;
|
||||
}
|
||||
let n_segments = path.segments.len();
|
||||
let tmp = name![self];
|
||||
let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name };
|
||||
let first_name = if path.is_self() { &tmp } else { &path.segments.first()? };
|
||||
let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
|
||||
for scope in self.scopes.iter().rev() {
|
||||
match scope {
|
||||
|
@ -276,7 +270,7 @@ impl Resolver {
|
|||
let (module_def, idx) = m.crate_def_map.resolve_path(
|
||||
db,
|
||||
m.module_id,
|
||||
path,
|
||||
&path,
|
||||
BuiltinShadowMode::Other,
|
||||
);
|
||||
return match idx {
|
||||
|
@ -322,7 +316,7 @@ impl Resolver {
|
|||
pub fn resolve_path_in_value_ns_fully(
|
||||
&self,
|
||||
db: &impl DefDatabase,
|
||||
path: &Path,
|
||||
path: &ModPath,
|
||||
) -> Option<ValueNs> {
|
||||
match self.resolve_path_in_value_ns(db, path)? {
|
||||
ResolveValueResult::ValueNs(it) => Some(it),
|
||||
|
@ -330,9 +324,13 @@ impl Resolver {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
|
||||
pub fn resolve_path_as_macro(
|
||||
&self,
|
||||
db: &impl DefDatabase,
|
||||
path: &ModPath,
|
||||
) -> Option<MacroDefId> {
|
||||
let (item_map, module) = self.module()?;
|
||||
item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
|
||||
item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros()
|
||||
}
|
||||
|
||||
pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
|
||||
|
|
|
@ -386,7 +386,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
let resolver = &self.resolver;
|
||||
// FIXME: this should resolve assoc items as well, see this example:
|
||||
// https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
|
||||
match resolver.resolve_path_in_type_ns_fully(self.db, &path) {
|
||||
match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) {
|
||||
Some(TypeNs::AdtId(AdtId::StructId(strukt))) => {
|
||||
let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into());
|
||||
let ty = self.db.ty(strukt.into());
|
||||
|
|
|
@ -32,21 +32,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
path: &Path,
|
||||
id: ExprOrPatId,
|
||||
) -> Option<Ty> {
|
||||
let (value, self_subst) = if let PathKind::Type(type_ref) = &path.kind {
|
||||
if path.segments.is_empty() {
|
||||
let (value, self_subst) = if let PathKind::Type(type_ref) = path.kind() {
|
||||
if path.segments().is_empty() {
|
||||
// This can't actually happen syntax-wise
|
||||
return None;
|
||||
}
|
||||
let ty = self.make_ty(type_ref);
|
||||
let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1];
|
||||
let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
|
||||
let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
|
||||
self.resolve_ty_assoc_item(
|
||||
ty,
|
||||
&path.segments.last().expect("path had at least one segment").name,
|
||||
&path.segments().last().expect("path had at least one segment").name,
|
||||
id,
|
||||
)?
|
||||
} else {
|
||||
let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
|
||||
let value_or_partial = resolver.resolve_path_in_value_ns(self.db, path.mod_path())?;
|
||||
|
||||
match value_or_partial {
|
||||
ResolveValueResult::ValueNs(it) => (it, None),
|
||||
|
@ -85,13 +85,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
remaining_index: usize,
|
||||
id: ExprOrPatId,
|
||||
) -> Option<(ValueNs, Option<Substs>)> {
|
||||
assert!(remaining_index < path.segments.len());
|
||||
assert!(remaining_index < path.segments().len());
|
||||
// there may be more intermediate segments between the resolved one and
|
||||
// the end. Only the last segment needs to be resolved to a value; from
|
||||
// the segments before that, we need to get either a type or a trait ref.
|
||||
|
||||
let resolved_segment = &path.segments[remaining_index - 1];
|
||||
let remaining_segments = &path.segments[remaining_index..];
|
||||
let resolved_segment = path.segments().get(remaining_index - 1).unwrap();
|
||||
let remaining_segments = path.segments().skip(remaining_index);
|
||||
let is_before_last = remaining_segments.len() == 1;
|
||||
|
||||
match (def, is_before_last) {
|
||||
|
@ -112,7 +112,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
// trait but it's not the last segment, so the next segment
|
||||
// should resolve to an associated type of that trait (e.g. `<T
|
||||
// as Iterator>::Item::default`)
|
||||
let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1];
|
||||
let remaining_segments_for_ty =
|
||||
remaining_segments.take(remaining_segments.len() - 1);
|
||||
let ty = Ty::from_partly_resolved_hir_path(
|
||||
self.db,
|
||||
&self.resolver,
|
||||
|
@ -138,7 +139,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
fn resolve_trait_assoc_item(
|
||||
&mut self,
|
||||
trait_ref: TraitRef,
|
||||
segment: &PathSegment,
|
||||
segment: PathSegment<'_>,
|
||||
id: ExprOrPatId,
|
||||
) -> Option<(ValueNs, Option<Substs>)> {
|
||||
let trait_ = trait_ref.trait_;
|
||||
|
@ -150,7 +151,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
.map(|(_name, id)| (*id).into())
|
||||
.find_map(|item| match item {
|
||||
AssocItemId::FunctionId(func) => {
|
||||
if segment.name == self.db.function_data(func).name {
|
||||
if segment.name == &self.db.function_data(func).name {
|
||||
Some(AssocItemId::FunctionId(func))
|
||||
} else {
|
||||
None
|
||||
|
@ -158,7 +159,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
}
|
||||
|
||||
AssocItemId::ConstId(konst) => {
|
||||
if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == &segment.name)
|
||||
if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == segment.name)
|
||||
{
|
||||
Some(AssocItemId::ConstId(konst))
|
||||
} else {
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::sync::Arc;
|
|||
use hir_def::{
|
||||
builtin_type::BuiltinType,
|
||||
generics::WherePredicate,
|
||||
path::{GenericArg, Path, PathKind, PathSegment},
|
||||
path::{GenericArg, Path, PathKind, PathSegment, PathSegments},
|
||||
resolver::{HasResolver, Resolver, TypeNs},
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
|
||||
|
@ -101,13 +101,13 @@ impl Ty {
|
|||
TypeRef::Path(path) => path,
|
||||
_ => return None,
|
||||
};
|
||||
if let PathKind::Type(_) = &path.kind {
|
||||
if let PathKind::Type(_) = path.kind() {
|
||||
return None;
|
||||
}
|
||||
if path.segments.len() > 1 {
|
||||
if path.segments().len() > 1 {
|
||||
return None;
|
||||
}
|
||||
let resolution = match resolver.resolve_path_in_type_ns(db, path) {
|
||||
let resolution = match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
|
||||
Some((it, None)) => it,
|
||||
_ => return None,
|
||||
};
|
||||
|
@ -124,11 +124,11 @@ impl Ty {
|
|||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
ty: Ty,
|
||||
remaining_segments: &[PathSegment],
|
||||
remaining_segments: PathSegments<'_>,
|
||||
) -> Ty {
|
||||
if remaining_segments.len() == 1 {
|
||||
// resolve unselected assoc types
|
||||
let segment = &remaining_segments[0];
|
||||
let segment = remaining_segments.first().unwrap();
|
||||
Ty::select_associated_type(db, resolver, ty, segment)
|
||||
} else if remaining_segments.len() > 1 {
|
||||
// FIXME report error (ambiguous associated type)
|
||||
|
@ -142,15 +142,15 @@ impl Ty {
|
|||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolution: TypeNs,
|
||||
resolved_segment: &PathSegment,
|
||||
remaining_segments: &[PathSegment],
|
||||
resolved_segment: PathSegment<'_>,
|
||||
remaining_segments: PathSegments<'_>,
|
||||
) -> Ty {
|
||||
let ty = match resolution {
|
||||
TypeNs::TraitId(trait_) => {
|
||||
let trait_ref =
|
||||
TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None);
|
||||
return if remaining_segments.len() == 1 {
|
||||
let segment = &remaining_segments[0];
|
||||
let segment = remaining_segments.first().unwrap();
|
||||
let associated_ty = associated_type_by_name_including_super_traits(
|
||||
db,
|
||||
trait_ref.trait_,
|
||||
|
@ -202,21 +202,21 @@ 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 PathKind::Type(type_ref) = path.kind() {
|
||||
let ty = Ty::from_hir(db, resolver, &type_ref);
|
||||
let remaining_segments = &path.segments[..];
|
||||
return Ty::from_type_relative_path(db, resolver, ty, remaining_segments);
|
||||
return Ty::from_type_relative_path(db, resolver, ty, path.segments());
|
||||
}
|
||||
let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) {
|
||||
let (resolution, remaining_index) =
|
||||
match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
|
||||
Some(it) => it,
|
||||
None => return Ty::Unknown,
|
||||
};
|
||||
let (resolved_segment, remaining_segments) = match remaining_index {
|
||||
None => (
|
||||
path.segments.last().expect("resolved path has at least one element"),
|
||||
&[] as &[PathSegment],
|
||||
path.segments().last().expect("resolved path has at least one element"),
|
||||
PathSegments::EMPTY,
|
||||
),
|
||||
Some(i) => (&path.segments[i - 1], &path.segments[i..]),
|
||||
Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
|
||||
};
|
||||
Ty::from_partly_resolved_hir_path(
|
||||
db,
|
||||
|
@ -231,7 +231,7 @@ impl Ty {
|
|||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
self_ty: Ty,
|
||||
segment: &PathSegment,
|
||||
segment: PathSegment<'_>,
|
||||
) -> Ty {
|
||||
let param_idx = match self_ty {
|
||||
Ty::Param { idx, .. } => idx,
|
||||
|
@ -261,7 +261,7 @@ impl Ty {
|
|||
fn from_hir_path_inner(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
segment: &PathSegment,
|
||||
segment: PathSegment<'_>,
|
||||
typable: TyDefId,
|
||||
) -> Ty {
|
||||
let generic_def = match typable {
|
||||
|
@ -284,7 +284,7 @@ impl Ty {
|
|||
// special-case enum variants
|
||||
resolved: ValueTyDefId,
|
||||
) -> Substs {
|
||||
let last = path.segments.last().expect("path should have at least one segment");
|
||||
let last = path.segments().last().expect("path should have at least one segment");
|
||||
let (segment, generic_def) = match resolved {
|
||||
ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
|
||||
ValueTyDefId::StructId(it) => (last, Some(it.into())),
|
||||
|
@ -296,13 +296,11 @@ impl Ty {
|
|||
// referring to the variant. So `Option::<T>::None` and
|
||||
// `Option::None::<T>` are both allowed (though the former is
|
||||
// preferred). See also `def_ids_for_path_segments` in rustc.
|
||||
let len = path.segments.len();
|
||||
let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() {
|
||||
// Option::<T>::None
|
||||
&path.segments[len - 2]
|
||||
} else {
|
||||
// Option::None::<T>
|
||||
last
|
||||
let len = path.segments().len();
|
||||
let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None };
|
||||
let segment = match penultimate {
|
||||
Some(segment) if segment.args_and_bindings.is_some() => segment,
|
||||
_ => last,
|
||||
};
|
||||
(segment, Some(var.parent.into()))
|
||||
}
|
||||
|
@ -314,7 +312,7 @@ impl Ty {
|
|||
pub(super) fn substs_from_path_segment(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
segment: &PathSegment,
|
||||
segment: PathSegment<'_>,
|
||||
def_generic: Option<GenericDefId>,
|
||||
add_self_param: bool,
|
||||
) -> Substs {
|
||||
|
@ -372,11 +370,11 @@ impl TraitRef {
|
|||
path: &Path,
|
||||
explicit_self_ty: Option<Ty>,
|
||||
) -> Option<Self> {
|
||||
let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? {
|
||||
let resolved = match resolver.resolve_path_in_type_ns_fully(db, path.mod_path())? {
|
||||
TypeNs::TraitId(tr) => tr,
|
||||
_ => return None,
|
||||
};
|
||||
let segment = path.segments.last().expect("path should have at least one segment");
|
||||
let segment = path.segments().last().expect("path should have at least one segment");
|
||||
Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty))
|
||||
}
|
||||
|
||||
|
@ -384,7 +382,7 @@ impl TraitRef {
|
|||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolved: TraitId,
|
||||
segment: &PathSegment,
|
||||
segment: PathSegment<'_>,
|
||||
explicit_self_ty: Option<Ty>,
|
||||
) -> Self {
|
||||
let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved);
|
||||
|
@ -410,7 +408,7 @@ impl TraitRef {
|
|||
fn substs_from_path(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
segment: &PathSegment,
|
||||
segment: PathSegment<'_>,
|
||||
resolved: TraitId,
|
||||
) -> Substs {
|
||||
let has_self_param =
|
||||
|
@ -464,12 +462,12 @@ fn assoc_type_bindings_from_type_bound<'a>(
|
|||
trait_ref: TraitRef,
|
||||
) -> impl Iterator<Item = GenericPredicate> + 'a {
|
||||
let last_segment = match bound {
|
||||
TypeBound::Path(path) => path.segments.last(),
|
||||
TypeBound::Path(path) => path.segments().last(),
|
||||
TypeBound::Error => None,
|
||||
};
|
||||
last_segment
|
||||
.into_iter()
|
||||
.flat_map(|segment| segment.args_and_bindings.iter())
|
||||
.flat_map(|segment| segment.args_and_bindings.into_iter())
|
||||
.flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
|
||||
.map(move |(name, type_ref)| {
|
||||
let associated_ty =
|
||||
|
|
|
@ -6,6 +6,7 @@ use hir_def::{
|
|||
adt::VariantData,
|
||||
db::DefDatabase,
|
||||
generics::{GenericParams, TypeParamData},
|
||||
path::Path,
|
||||
resolver::{HasResolver, TypeNs},
|
||||
type_ref::TypeRef,
|
||||
ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
|
||||
|
@ -22,10 +23,10 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
|
|||
.where_predicates
|
||||
.iter()
|
||||
.filter_map(|pred| match &pred.type_ref {
|
||||
TypeRef::Path(p) if p.as_ident() == Some(&name![Self]) => pred.bound.as_path(),
|
||||
TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(),
|
||||
_ => None,
|
||||
})
|
||||
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
|
||||
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
|
||||
Some(TypeNs::TraitId(t)) => Some(t),
|
||||
_ => None,
|
||||
})
|
||||
|
|
|
@ -188,10 +188,9 @@ impl<'a> CompletionContext<'a> {
|
|||
self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
|
||||
self.has_type_args = segment.type_arg_list().is_some();
|
||||
|
||||
if let Some(mut path) = hir::Path::from_ast(path.clone()) {
|
||||
if !path.is_ident() {
|
||||
path.segments.pop().unwrap();
|
||||
self.path_prefix = Some(path);
|
||||
if let Some(path) = hir::Path::from_ast(path.clone()) {
|
||||
if let Some(path_prefix) = path.qualifier() {
|
||||
self.path_prefix = Some(path_prefix);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue