mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 14:33:29 +00:00
Merge #1833
1833: Specify desirable namespace when calling resolve r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
b31f9872ec
13 changed files with 542 additions and 472 deletions
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
U8, USIZE,
|
U8, USIZE,
|
||||||
},
|
},
|
||||||
nameres::{CrateModuleId, ImportId, ModuleScope, Namespace},
|
nameres::{CrateModuleId, ImportId, ModuleScope, Namespace},
|
||||||
resolve::Resolver,
|
resolve::{Resolver, TypeNs},
|
||||||
traits::{TraitData, TraitItem},
|
traits::{TraitData, TraitItem},
|
||||||
ty::{
|
ty::{
|
||||||
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
|
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
|
||||||
|
@ -868,11 +868,9 @@ impl Trait {
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.filter_map(|path| {
|
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
|
||||||
match resolver.resolve_path_without_assoc_items(db, path).take_types() {
|
Some(TypeNs::Trait(t)) => Some(t),
|
||||||
Some(crate::Resolution::Def(ModuleDef::Trait(t))) => Some(t),
|
_ => None,
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub use self::{
|
||||||
name::Name,
|
name::Name,
|
||||||
nameres::{ImportId, Namespace, PerNs},
|
nameres::{ImportId, Namespace, PerNs},
|
||||||
path::{Path, PathKind},
|
path::{Path, PathKind},
|
||||||
resolve::Resolution,
|
resolve::ScopeDef,
|
||||||
source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
|
source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
|
||||||
source_id::{AstIdMap, ErasedFileAstId},
|
source_id::{AstIdMap, ErasedFileAstId},
|
||||||
ty::{
|
ty::{
|
||||||
|
|
|
@ -279,10 +279,6 @@ impl CrateDefMap {
|
||||||
self.root
|
self.root
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module {
|
|
||||||
Module { krate: self.krate, module_id }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn prelude(&self) -> Option<Module> {
|
pub(crate) fn prelude(&self) -> Option<Module> {
|
||||||
self.prelude
|
self.prelude
|
||||||
}
|
}
|
||||||
|
@ -389,7 +385,7 @@ impl CrateDefMap {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i, segment) in segments {
|
for (i, segment) in segments {
|
||||||
let curr = match curr_per_ns.as_ref().take_types() {
|
let curr = match curr_per_ns.take_types() {
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
None => {
|
None => {
|
||||||
// we still have path segments left, but the path so far
|
// we still have path segments left, but the path so far
|
||||||
|
@ -433,7 +429,7 @@ impl CrateDefMap {
|
||||||
Some(variant) => PerNs::both(variant.into(), variant.into()),
|
Some(variant) => PerNs::both(variant.into(), variant.into()),
|
||||||
None => {
|
None => {
|
||||||
return ResolvePathResult::with(
|
return ResolvePathResult::with(
|
||||||
PerNs::types((*e).into()),
|
PerNs::types(e.into()),
|
||||||
ReachedFixedPoint::Yes,
|
ReachedFixedPoint::Yes,
|
||||||
Some(i),
|
Some(i),
|
||||||
);
|
);
|
||||||
|
@ -450,7 +446,7 @@ impl CrateDefMap {
|
||||||
);
|
);
|
||||||
|
|
||||||
return ResolvePathResult::with(
|
return ResolvePathResult::with(
|
||||||
PerNs::types(*s),
|
PerNs::types(s),
|
||||||
ReachedFixedPoint::Yes,
|
ReachedFixedPoint::Yes,
|
||||||
Some(i),
|
Some(i),
|
||||||
);
|
);
|
||||||
|
|
|
@ -68,10 +68,6 @@ impl<T> PerNs<T> {
|
||||||
PerNs { types: None, values: None, macros: self.macros }
|
PerNs { types: None, values: None, macros: self.macros }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ref(&self) -> PerNs<&T> {
|
|
||||||
PerNs { types: self.types.as_ref(), values: self.values.as_ref(), macros: self.macros }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn or(self, other: PerNs<T>) -> PerNs<T> {
|
pub fn or(self, other: PerNs<T>) -> PerNs<T> {
|
||||||
PerNs {
|
PerNs {
|
||||||
types: self.types.or(other.types),
|
types: self.types.or(other.types),
|
||||||
|
@ -79,9 +75,4 @@ impl<T> PerNs<T> {
|
||||||
macros: self.macros.or(other.macros),
|
macros: self.macros.or(other.macros),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map types and values. Leave macros unchanged.
|
|
||||||
pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
|
|
||||||
PerNs { types: self.types.map(&f), values: self.values.map(&f), macros: self.macros }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Name resolution.
|
//! Name resolution.
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
code_model::Crate,
|
code_model::Crate,
|
||||||
|
@ -14,8 +14,9 @@ use crate::{
|
||||||
impl_block::ImplBlock,
|
impl_block::ImplBlock,
|
||||||
name::{Name, SELF_PARAM, SELF_TYPE},
|
name::{Name, SELF_PARAM, SELF_TYPE},
|
||||||
nameres::{CrateDefMap, CrateModuleId, PerNs},
|
nameres::{CrateDefMap, CrateModuleId, PerNs},
|
||||||
path::Path,
|
path::{Path, PathKind},
|
||||||
Adt, Enum, MacroDef, ModuleDef, Struct, Trait,
|
Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct,
|
||||||
|
Trait, TypeAlias,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
|
@ -36,69 +37,6 @@ pub(crate) struct ExprScope {
|
||||||
scope_id: ScopeId,
|
scope_id: ScopeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub(crate) struct PathResult {
|
|
||||||
/// The actual path resolution
|
|
||||||
// FIXME: `PerNs<Resolution>` type doesn't make sense, as not every
|
|
||||||
// Resolution variant can appear in every namespace
|
|
||||||
resolution: PerNs<Resolution>,
|
|
||||||
/// The first index in the path that we
|
|
||||||
/// were unable to resolve.
|
|
||||||
/// When path is fully resolved, this is 0.
|
|
||||||
remaining_index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PathResult {
|
|
||||||
/// Returns the remaining index in the result
|
|
||||||
/// returns None if the path was fully resolved
|
|
||||||
pub(crate) fn remaining_index(&self) -> Option<usize> {
|
|
||||||
if self.remaining_index > 0 {
|
|
||||||
Some(self.remaining_index)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes `PathResult` and returns the contained `PerNs<Resolution>`
|
|
||||||
/// if the path was fully resolved, meaning we have no remaining items
|
|
||||||
pub(crate) fn into_fully_resolved(self) -> PerNs<Resolution> {
|
|
||||||
if self.is_fully_resolved() {
|
|
||||||
self.resolution
|
|
||||||
} else {
|
|
||||||
PerNs::none()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes `PathResult` and returns the resolution and the
|
|
||||||
/// remaining_index as a tuple.
|
|
||||||
pub(crate) fn into_inner(self) -> (PerNs<Resolution>, Option<usize>) {
|
|
||||||
let index = self.remaining_index();
|
|
||||||
(self.resolution, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Path is fully resolved when `remaining_index` is none
|
|
||||||
/// and the resolution contains anything
|
|
||||||
pub(crate) fn is_fully_resolved(&self) -> bool {
|
|
||||||
!self.resolution.is_none() && self.remaining_index().is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn empty() -> PathResult {
|
|
||||||
PathResult { resolution: PerNs::none(), remaining_index: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_resolution(res: PerNs<Resolution>) -> PathResult {
|
|
||||||
PathResult::from_resolution_with_index(res, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_resolution_with_index(res: PerNs<Resolution>, remaining_index: usize) -> PathResult {
|
|
||||||
if res.is_none() {
|
|
||||||
PathResult::empty()
|
|
||||||
} else {
|
|
||||||
PathResult { resolution: res, remaining_index }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) enum Scope {
|
pub(crate) enum Scope {
|
||||||
/// All the items and imported names of a module
|
/// All the items and imported names of a module
|
||||||
|
@ -112,25 +50,41 @@ pub(crate) enum Scope {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Resolution {
|
pub enum TypeNs {
|
||||||
/// An item
|
|
||||||
Def(ModuleDef),
|
|
||||||
|
|
||||||
// FIXME: there's no way we can syntactically confuse a local with generic
|
|
||||||
// param, so these two should not be members of the single enum
|
|
||||||
/// A local binding (only value namespace)
|
|
||||||
LocalBinding(PatId),
|
|
||||||
/// A generic parameter
|
|
||||||
GenericParam(u32),
|
|
||||||
SelfType(ImplBlock),
|
SelfType(ImplBlock),
|
||||||
|
GenericParam(u32),
|
||||||
|
Adt(Adt),
|
||||||
|
EnumVariant(EnumVariant),
|
||||||
|
TypeAlias(TypeAlias),
|
||||||
|
BuiltinType(BuiltinType),
|
||||||
|
Trait(Trait),
|
||||||
|
// Module belong to type ns, but the resovler is used when all module paths
|
||||||
|
// are fully resolved.
|
||||||
|
// Module(Module)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ValueOrPartial {
|
||||||
|
ValueNs(ValueNs),
|
||||||
|
Partial(TypeNs, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ValueNs {
|
||||||
|
LocalBinding(PatId),
|
||||||
|
Function(Function),
|
||||||
|
Const(Const),
|
||||||
|
Static(Static),
|
||||||
|
Struct(Struct),
|
||||||
|
EnumVariant(EnumVariant),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Resolver {
|
impl Resolver {
|
||||||
/// Resolve known trait from std, like `std::futures::Future`
|
/// Resolve known trait from std, like `std::futures::Future`
|
||||||
pub(crate) fn resolve_known_trait(&self, db: &impl HirDatabase, path: &Path) -> Option<Trait> {
|
pub(crate) fn resolve_known_trait(&self, db: &impl HirDatabase, path: &Path) -> Option<Trait> {
|
||||||
let res = self.resolve_path_segments(db, path).into_fully_resolved().take_types()?;
|
let res = self.resolve_module_path(db, path).take_types()?;
|
||||||
match res {
|
match res {
|
||||||
Resolution::Def(ModuleDef::Trait(it)) => Some(it),
|
ModuleDef::Trait(it) => Some(it),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,31 +95,195 @@ impl Resolver {
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> Option<Struct> {
|
) -> Option<Struct> {
|
||||||
let res = self.resolve_path_segments(db, path).into_fully_resolved().take_types()?;
|
let res = self.resolve_module_path(db, path).take_types()?;
|
||||||
match res {
|
match res {
|
||||||
Resolution::Def(ModuleDef::Adt(Adt::Struct(it))) => Some(it),
|
ModuleDef::Adt(Adt::Struct(it)) => Some(it),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve known enum from std, like `std::result::Result`
|
/// Resolve known enum from std, like `std::result::Result`
|
||||||
pub(crate) fn resolve_known_enum(&self, db: &impl HirDatabase, path: &Path) -> Option<Enum> {
|
pub(crate) fn resolve_known_enum(&self, db: &impl HirDatabase, path: &Path) -> Option<Enum> {
|
||||||
let res = self.resolve_path_segments(db, path).into_fully_resolved().take_types()?;
|
let res = self.resolve_module_path(db, path).take_types()?;
|
||||||
match res {
|
match res {
|
||||||
Resolution::Def(ModuleDef::Adt(Adt::Enum(it))) => Some(it),
|
ModuleDef::Adt(Adt::Enum(it)) => Some(it),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
|
/// pub only for source-binder
|
||||||
let mut resolution = PerNs::none();
|
pub(crate) fn resolve_module_path(
|
||||||
|
&self,
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
path: &Path,
|
||||||
|
) -> PerNs<ModuleDef> {
|
||||||
|
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);
|
||||||
|
if segment_index.is_some() {
|
||||||
|
return PerNs::none();
|
||||||
|
}
|
||||||
|
module_res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_path_in_type_ns(
|
||||||
|
&self,
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
path: &Path,
|
||||||
|
) -> Option<(TypeNs, Option<usize>)> {
|
||||||
|
let first_name = &path.segments.first()?.name;
|
||||||
|
let skip_to_mod = path.kind != PathKind::Plain;
|
||||||
for scope in self.scopes.iter().rev() {
|
for scope in self.scopes.iter().rev() {
|
||||||
resolution = resolution.or(scope.resolve_name(db, name));
|
match scope {
|
||||||
if resolution.is_all() {
|
Scope::ExprScope(_) => continue,
|
||||||
return resolution;
|
Scope::GenericParams(_) | Scope::ImplBlockScope(_) if skip_to_mod => continue,
|
||||||
|
|
||||||
|
Scope::GenericParams(params) => {
|
||||||
|
if let Some(param) = params.find_by_name(first_name) {
|
||||||
|
let idx = if path.segments.len() == 1 { None } else { Some(1) };
|
||||||
|
return Some((TypeNs::GenericParam(param.idx), idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Scope::ImplBlockScope(impl_) => {
|
||||||
|
if first_name == &SELF_TYPE {
|
||||||
|
let idx = if path.segments.len() == 1 { None } else { Some(1) };
|
||||||
|
return Some((TypeNs::SelfType(*impl_), idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Scope::ModuleScope(m) => {
|
||||||
|
let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
|
||||||
|
let res = match module_def.take_types()? {
|
||||||
|
ModuleDef::Adt(it) => TypeNs::Adt(it),
|
||||||
|
ModuleDef::EnumVariant(it) => TypeNs::EnumVariant(it),
|
||||||
|
|
||||||
|
ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it),
|
||||||
|
ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it),
|
||||||
|
|
||||||
|
ModuleDef::Trait(it) => TypeNs::Trait(it),
|
||||||
|
|
||||||
|
ModuleDef::Function(_)
|
||||||
|
| ModuleDef::Const(_)
|
||||||
|
| ModuleDef::Static(_)
|
||||||
|
| ModuleDef::Module(_) => return None,
|
||||||
|
};
|
||||||
|
return Some((res, idx));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolution
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_path_in_type_ns_fully(
|
||||||
|
&self,
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
path: &Path,
|
||||||
|
) -> Option<TypeNs> {
|
||||||
|
let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
|
||||||
|
if unresolved.is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_path_in_value_ns(
|
||||||
|
&self,
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
path: &Path,
|
||||||
|
) -> Option<ValueOrPartial> {
|
||||||
|
let n_segments = path.segments.len();
|
||||||
|
let tmp = SELF_PARAM;
|
||||||
|
let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name };
|
||||||
|
let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
|
||||||
|
for scope in self.scopes.iter().rev() {
|
||||||
|
match scope {
|
||||||
|
Scope::ExprScope(_) | Scope::GenericParams(_) | Scope::ImplBlockScope(_)
|
||||||
|
if skip_to_mod =>
|
||||||
|
{
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope::ExprScope(scope) if n_segments <= 1 => {
|
||||||
|
let entry = scope
|
||||||
|
.expr_scopes
|
||||||
|
.entries(scope.scope_id)
|
||||||
|
.iter()
|
||||||
|
.find(|entry| entry.name() == first_name);
|
||||||
|
|
||||||
|
if let Some(e) = entry {
|
||||||
|
return Some(ValueOrPartial::ValueNs(ValueNs::LocalBinding(e.pat())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Scope::ExprScope(_) => continue,
|
||||||
|
|
||||||
|
Scope::GenericParams(params) if n_segments > 1 => {
|
||||||
|
if let Some(param) = params.find_by_name(first_name) {
|
||||||
|
let ty = TypeNs::GenericParam(param.idx);
|
||||||
|
return Some(ValueOrPartial::Partial(ty, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Scope::GenericParams(_) => continue,
|
||||||
|
|
||||||
|
Scope::ImplBlockScope(impl_) if n_segments > 1 => {
|
||||||
|
if first_name == &SELF_TYPE {
|
||||||
|
let ty = TypeNs::SelfType(*impl_);
|
||||||
|
return Some(ValueOrPartial::Partial(ty, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Scope::ImplBlockScope(_) => continue,
|
||||||
|
|
||||||
|
Scope::ModuleScope(m) => {
|
||||||
|
let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
|
||||||
|
return match idx {
|
||||||
|
None => {
|
||||||
|
let value = match module_def.take_values()? {
|
||||||
|
ModuleDef::Function(it) => ValueNs::Function(it),
|
||||||
|
ModuleDef::Adt(Adt::Struct(it)) => ValueNs::Struct(it),
|
||||||
|
ModuleDef::EnumVariant(it) => ValueNs::EnumVariant(it),
|
||||||
|
ModuleDef::Const(it) => ValueNs::Const(it),
|
||||||
|
ModuleDef::Static(it) => ValueNs::Static(it),
|
||||||
|
|
||||||
|
ModuleDef::Adt(Adt::Enum(_))
|
||||||
|
| ModuleDef::Adt(Adt::Union(_))
|
||||||
|
| ModuleDef::Trait(_)
|
||||||
|
| ModuleDef::TypeAlias(_)
|
||||||
|
| ModuleDef::BuiltinType(_)
|
||||||
|
| ModuleDef::Module(_) => return None,
|
||||||
|
};
|
||||||
|
Some(ValueOrPartial::ValueNs(value))
|
||||||
|
}
|
||||||
|
Some(idx) => {
|
||||||
|
let ty = match module_def.take_types()? {
|
||||||
|
ModuleDef::Adt(it) => TypeNs::Adt(it),
|
||||||
|
ModuleDef::Trait(it) => TypeNs::Trait(it),
|
||||||
|
ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it),
|
||||||
|
ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it),
|
||||||
|
|
||||||
|
ModuleDef::Module(_)
|
||||||
|
| ModuleDef::Function(_)
|
||||||
|
| ModuleDef::EnumVariant(_)
|
||||||
|
| ModuleDef::Const(_)
|
||||||
|
| ModuleDef::Static(_) => return None,
|
||||||
|
};
|
||||||
|
Some(ValueOrPartial::Partial(ty, idx))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_path_in_value_ns_fully(
|
||||||
|
&self,
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
path: &Path,
|
||||||
|
) -> Option<ValueNs> {
|
||||||
|
match self.resolve_path_in_value_ns(db, path)? {
|
||||||
|
ValueOrPartial::ValueNs(it) => Some(it),
|
||||||
|
ValueOrPartial::Partial(..) => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_path_as_macro(
|
pub(crate) fn resolve_path_as_macro(
|
||||||
|
@ -177,58 +295,14 @@ impl Resolver {
|
||||||
item_map.resolve_path(db, module, path).0.get_macros()
|
item_map.resolve_path(db, module, path).0.get_macros()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the resolved path segments
|
pub(crate) fn process_all_names(
|
||||||
/// Which may be fully resolved, empty or partially resolved.
|
|
||||||
pub(crate) fn resolve_path_segments(&self, db: &impl HirDatabase, path: &Path) -> PathResult {
|
|
||||||
if let Some(name) = path.as_ident() {
|
|
||||||
PathResult::from_resolution(self.resolve_name(db, name))
|
|
||||||
} else if path.is_self() {
|
|
||||||
PathResult::from_resolution(self.resolve_name(db, &SELF_PARAM))
|
|
||||||
} else {
|
|
||||||
let (item_map, module) = match self.module() {
|
|
||||||
Some(it) => it,
|
|
||||||
None => return PathResult::empty(),
|
|
||||||
};
|
|
||||||
let (module_res, segment_index) = item_map.resolve_path(db, module, path);
|
|
||||||
|
|
||||||
let def = module_res.map(Resolution::Def);
|
|
||||||
|
|
||||||
if let Some(index) = segment_index {
|
|
||||||
PathResult::from_resolution_with_index(def, index)
|
|
||||||
} else {
|
|
||||||
PathResult::from_resolution(def)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the fully resolved path if we were able to resolve it.
|
|
||||||
/// otherwise returns `PerNs::none`
|
|
||||||
pub(crate) fn resolve_path_without_assoc_items(
|
|
||||||
&self,
|
&self,
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
path: &Path,
|
f: &mut dyn FnMut(Name, ScopeDef),
|
||||||
) -> PerNs<Resolution> {
|
) {
|
||||||
// into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise
|
|
||||||
self.resolve_path_segments(db, path).into_fully_resolved()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> {
|
|
||||||
let mut names = FxHashMap::default();
|
|
||||||
for scope in self.scopes.iter().rev() {
|
for scope in self.scopes.iter().rev() {
|
||||||
scope.collect_names(db, &mut |name, res| {
|
scope.process_names(db, f);
|
||||||
let current: &mut PerNs<Resolution> = names.entry(name).or_default();
|
|
||||||
if current.types.is_none() {
|
|
||||||
current.types = res.types;
|
|
||||||
}
|
|
||||||
if current.values.is_none() {
|
|
||||||
current.values = res.values;
|
|
||||||
}
|
|
||||||
if current.macros.is_none() {
|
|
||||||
current.macros = res.macros;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
names
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait> {
|
pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait> {
|
||||||
|
@ -301,41 +375,28 @@ impl Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scope {
|
/// For IDE only
|
||||||
fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
|
pub enum ScopeDef {
|
||||||
match self {
|
ModuleDef(ModuleDef),
|
||||||
Scope::ModuleScope(m) => {
|
MacroDef(MacroDef),
|
||||||
if name == &SELF_PARAM {
|
GenericParam(u32),
|
||||||
PerNs::types(Resolution::Def(m.crate_def_map.mk_module(m.module_id).into()))
|
SelfType(ImplBlock),
|
||||||
} else {
|
LocalBinding(PatId),
|
||||||
m.crate_def_map
|
Unknown,
|
||||||
.resolve_name_in_module(db, m.module_id, name)
|
}
|
||||||
.map(Resolution::Def)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Scope::GenericParams(gp) => match gp.find_by_name(name) {
|
|
||||||
Some(gp) => PerNs::types(Resolution::GenericParam(gp.idx)),
|
|
||||||
None => PerNs::none(),
|
|
||||||
},
|
|
||||||
Scope::ImplBlockScope(i) => {
|
|
||||||
if name == &SELF_TYPE {
|
|
||||||
PerNs::types(Resolution::SelfType(*i))
|
|
||||||
} else {
|
|
||||||
PerNs::none()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Scope::ExprScope(e) => {
|
|
||||||
let entry =
|
|
||||||
e.expr_scopes.entries(e.scope_id).iter().find(|entry| entry.name() == name);
|
|
||||||
match entry {
|
|
||||||
Some(e) => PerNs::values(Resolution::LocalBinding(e.pat())),
|
|
||||||
None => PerNs::none(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, PerNs<Resolution>)) {
|
impl From<PerNs<ModuleDef>> for ScopeDef {
|
||||||
|
fn from(def: PerNs<ModuleDef>) -> Self {
|
||||||
|
def.take_types()
|
||||||
|
.or_else(|| def.take_values())
|
||||||
|
.map(ScopeDef::ModuleDef)
|
||||||
|
.or_else(|| def.get_macros().map(ScopeDef::MacroDef))
|
||||||
|
.unwrap_or(ScopeDef::Unknown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
fn process_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
|
||||||
match self {
|
match self {
|
||||||
Scope::ModuleScope(m) => {
|
Scope::ModuleScope(m) => {
|
||||||
// FIXME: should we provide `self` here?
|
// FIXME: should we provide `self` here?
|
||||||
|
@ -346,32 +407,32 @@ impl Scope {
|
||||||
// }),
|
// }),
|
||||||
// );
|
// );
|
||||||
m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| {
|
m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| {
|
||||||
f(name.clone(), res.def.map(Resolution::Def));
|
f(name.clone(), res.def.into());
|
||||||
});
|
});
|
||||||
m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
|
m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
|
||||||
f(name.clone(), PerNs::macros(macro_));
|
f(name.clone(), ScopeDef::MacroDef(macro_));
|
||||||
});
|
});
|
||||||
m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| {
|
m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| {
|
||||||
f(name.clone(), PerNs::types(Resolution::Def(*def)));
|
f(name.clone(), ScopeDef::ModuleDef(*def));
|
||||||
});
|
});
|
||||||
if let Some(prelude) = m.crate_def_map.prelude() {
|
if let Some(prelude) = m.crate_def_map.prelude() {
|
||||||
let prelude_def_map = db.crate_def_map(prelude.krate);
|
let prelude_def_map = db.crate_def_map(prelude.krate);
|
||||||
prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| {
|
prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| {
|
||||||
f(name.clone(), res.def.map(Resolution::Def));
|
f(name.clone(), res.def.into());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::GenericParams(gp) => {
|
Scope::GenericParams(gp) => {
|
||||||
for param in &gp.params {
|
for param in &gp.params {
|
||||||
f(param.name.clone(), PerNs::types(Resolution::GenericParam(param.idx)))
|
f(param.name.clone(), ScopeDef::GenericParam(param.idx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::ImplBlockScope(i) => {
|
Scope::ImplBlockScope(i) => {
|
||||||
f(SELF_TYPE, PerNs::types(Resolution::SelfType(*i)));
|
f(SELF_TYPE, ScopeDef::SelfType(*i));
|
||||||
}
|
}
|
||||||
Scope::ExprScope(e) => {
|
Scope::ExprScope(e) => {
|
||||||
e.expr_scopes.entries(e.scope_id).iter().for_each(|e| {
|
e.expr_scopes.entries(e.scope_id).iter().for_each(|e| {
|
||||||
f(e.name().clone(), PerNs::values(Resolution::LocalBinding(e.pat())));
|
f(e.name().clone(), ScopeDef::LocalBinding(e.pat()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use ra_syntax::{
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
SyntaxNode, SyntaxNodePtr, TextRange, TextUnit,
|
SyntaxNode, SyntaxNodePtr, TextRange, TextUnit,
|
||||||
};
|
};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
|
@ -27,9 +27,10 @@ use crate::{
|
||||||
ids::LocationCtx,
|
ids::LocationCtx,
|
||||||
name,
|
name,
|
||||||
path::{PathKind, PathSegment},
|
path::{PathKind, PathSegment},
|
||||||
|
resolve::{ScopeDef, TypeNs, ValueNs},
|
||||||
ty::method_resolution::implements_trait,
|
ty::method_resolution::implements_trait,
|
||||||
AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef,
|
AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef,
|
||||||
Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty,
|
Module, Name, Path, Resolver, Static, Struct, Trait, Ty,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Locates the module by `FileId`. Picks topmost module in the file.
|
/// Locates the module by `FileId`. Picks topmost module in the file.
|
||||||
|
@ -301,8 +302,41 @@ impl SourceAnalyzer {
|
||||||
&self,
|
&self,
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
path: &crate::Path,
|
path: &crate::Path,
|
||||||
) -> PerNs<crate::Resolution> {
|
) -> Option<PathResolution> {
|
||||||
self.resolver.resolve_path_without_assoc_items(db, path)
|
let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty {
|
||||||
|
TypeNs::SelfType(it) => PathResolution::SelfType(it),
|
||||||
|
TypeNs::GenericParam(it) => PathResolution::GenericParam(it),
|
||||||
|
TypeNs::Adt(it) => PathResolution::Def(it.into()),
|
||||||
|
TypeNs::EnumVariant(it) => PathResolution::Def(it.into()),
|
||||||
|
TypeNs::TypeAlias(it) => PathResolution::Def(it.into()),
|
||||||
|
TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
|
||||||
|
TypeNs::Trait(it) => PathResolution::Def(it.into()),
|
||||||
|
});
|
||||||
|
let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
|
||||||
|
let res = match val {
|
||||||
|
ValueNs::LocalBinding(it) => {
|
||||||
|
// We get a `PatId` from resolver, but it actually can only
|
||||||
|
// point at `BindPat`, and not at the arbitrary pattern.
|
||||||
|
let pat_ptr = self
|
||||||
|
.body_source_map
|
||||||
|
.as_ref()?
|
||||||
|
.pat_syntax(it)?
|
||||||
|
.ast // FIXME: ignoring file_id here is definitelly wrong
|
||||||
|
.map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap());
|
||||||
|
PathResolution::LocalBinding(pat_ptr)
|
||||||
|
}
|
||||||
|
ValueNs::Function(it) => PathResolution::Def(it.into()),
|
||||||
|
ValueNs::Const(it) => PathResolution::Def(it.into()),
|
||||||
|
ValueNs::Static(it) => PathResolution::Def(it.into()),
|
||||||
|
ValueNs::Struct(it) => PathResolution::Def(it.into()),
|
||||||
|
ValueNs::EnumVariant(it) => PathResolution::Def(it.into()),
|
||||||
|
};
|
||||||
|
Some(res)
|
||||||
|
});
|
||||||
|
|
||||||
|
let items =
|
||||||
|
self.resolver.resolve_module_path(db, &path).take_types().map(PathResolution::Def);
|
||||||
|
types.or(values).or(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> {
|
pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> {
|
||||||
|
@ -319,25 +353,7 @@ impl SourceAnalyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let hir_path = crate::Path::from_ast(path.clone())?;
|
let hir_path = crate::Path::from_ast(path.clone())?;
|
||||||
let res = self.resolver.resolve_path_without_assoc_items(db, &hir_path);
|
self.resolve_hir_path(db, &hir_path)
|
||||||
let res = res.clone().take_types().or_else(|| res.take_values())?;
|
|
||||||
let res = match res {
|
|
||||||
crate::Resolution::Def(it) => PathResolution::Def(it),
|
|
||||||
crate::Resolution::LocalBinding(it) => {
|
|
||||||
// We get a `PatId` from resolver, but it actually can only
|
|
||||||
// point at `BindPat`, and not at the arbitrary pattern.
|
|
||||||
let pat_ptr = self
|
|
||||||
.body_source_map
|
|
||||||
.as_ref()?
|
|
||||||
.pat_syntax(it)?
|
|
||||||
.ast // FIXME: ignoring file_id here is definitelly wrong
|
|
||||||
.map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap());
|
|
||||||
PathResolution::LocalBinding(pat_ptr)
|
|
||||||
}
|
|
||||||
crate::Resolution::GenericParam(it) => PathResolution::GenericParam(it),
|
|
||||||
crate::Resolution::SelfType(it) => PathResolution::SelfType(it),
|
|
||||||
};
|
|
||||||
Some(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> {
|
pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> {
|
||||||
|
@ -360,8 +376,8 @@ impl SourceAnalyzer {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<crate::Resolution>> {
|
pub fn process_all_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
|
||||||
self.resolver.all_names(db)
|
self.resolver.process_all_names(db, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> {
|
pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> {
|
||||||
|
|
|
@ -45,11 +45,10 @@ use crate::{
|
||||||
name,
|
name,
|
||||||
nameres::Namespace,
|
nameres::Namespace,
|
||||||
path::{GenericArg, GenericArgs, PathKind, PathSegment},
|
path::{GenericArg, GenericArgs, PathKind, PathSegment},
|
||||||
resolve::{Resolution, Resolver},
|
resolve::{Resolver, TypeNs, ValueNs, ValueOrPartial},
|
||||||
ty::infer::diagnostics::InferenceDiagnostic,
|
ty::infer::diagnostics::InferenceDiagnostic,
|
||||||
type_ref::{Mutability, TypeRef},
|
type_ref::{Mutability, TypeRef},
|
||||||
Adt, ConstData, DefWithBody, FnData, Function, HasBody, ImplItem, ModuleDef, Name, Path,
|
Adt, ConstData, DefWithBody, FnData, Function, HasBody, ImplItem, Name, Path, StructField,
|
||||||
StructField,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod unify;
|
mod unify;
|
||||||
|
@ -472,141 +471,138 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> {
|
fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> {
|
||||||
let resolved = resolver.resolve_path_segments(self.db, &path);
|
let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
|
||||||
|
|
||||||
let (def, remaining_index) = resolved.into_inner();
|
let (value, self_subst) = match value_or_partial {
|
||||||
|
ValueOrPartial::ValueNs(it) => (it, None),
|
||||||
|
ValueOrPartial::Partial(def, remaining_index) => {
|
||||||
|
self.resolve_assoc_item(def, path, remaining_index, id)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
log::debug!(
|
let typable: TypableDef = match value {
|
||||||
"path {:?} resolved to {:?} with remaining index {:?}",
|
ValueNs::LocalBinding(pat) => {
|
||||||
path,
|
let ty = self.result.type_of_pat.get(pat)?.clone();
|
||||||
def,
|
let ty = self.resolve_ty_as_possible(&mut vec![], ty);
|
||||||
remaining_index
|
return Some(ty);
|
||||||
);
|
}
|
||||||
|
ValueNs::Function(it) => it.into(),
|
||||||
|
ValueNs::Const(it) => it.into(),
|
||||||
|
ValueNs::Static(it) => it.into(),
|
||||||
|
ValueNs::Struct(it) => it.into(),
|
||||||
|
ValueNs::EnumVariant(it) => it.into(),
|
||||||
|
};
|
||||||
|
|
||||||
// if the remaining_index is None, we expect the path
|
let mut ty = self.db.type_for_def(typable, Namespace::Values);
|
||||||
// to be fully resolved, in this case we continue with
|
if let Some(self_subst) = self_subst {
|
||||||
// the default by attempting to `take_values´ from the resolution.
|
ty = ty.subst(&self_subst);
|
||||||
// Otherwise the path was partially resolved, which means
|
}
|
||||||
// we might have resolved into a type for which
|
|
||||||
// we may find some associated item starting at the
|
|
||||||
// path.segment pointed to by `remaining_index´
|
|
||||||
let mut resolved =
|
|
||||||
if remaining_index.is_none() { def.take_values()? } else { def.take_types()? };
|
|
||||||
|
|
||||||
let remaining_index = remaining_index.unwrap_or_else(|| path.segments.len());
|
let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
|
||||||
let mut actual_def_ty: Option<Ty> = None;
|
let ty = ty.subst(&substs);
|
||||||
|
let ty = self.insert_type_vars(ty);
|
||||||
|
let ty = self.normalize_associated_types_in(ty);
|
||||||
|
Some(ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_assoc_item(
|
||||||
|
&mut self,
|
||||||
|
mut def: TypeNs,
|
||||||
|
path: &Path,
|
||||||
|
remaining_index: usize,
|
||||||
|
id: ExprOrPatId,
|
||||||
|
) -> Option<(ValueNs, Option<Substs>)> {
|
||||||
|
assert!(remaining_index < path.segments.len());
|
||||||
|
let krate = self.resolver.krate()?;
|
||||||
|
|
||||||
|
let mut ty = Ty::Unknown;
|
||||||
|
|
||||||
let krate = resolver.krate()?;
|
|
||||||
// resolve intermediate segments
|
// resolve intermediate segments
|
||||||
for (i, segment) in path.segments[remaining_index..].iter().enumerate() {
|
for (i, segment) in path.segments[remaining_index..].iter().enumerate() {
|
||||||
let ty = match resolved {
|
let is_last_segment = i == path.segments[remaining_index..].len() - 1;
|
||||||
Resolution::Def(def) => {
|
ty = {
|
||||||
// FIXME resolve associated items from traits as well
|
let typable: TypableDef = match def {
|
||||||
let typable: Option<TypableDef> = def.into();
|
TypeNs::Adt(it) => it.into(),
|
||||||
let typable = typable?;
|
TypeNs::TypeAlias(it) => it.into(),
|
||||||
|
TypeNs::BuiltinType(it) => it.into(),
|
||||||
|
// FIXME associated item of traits, generics, and Self
|
||||||
|
TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// FIXME: report error here
|
||||||
|
TypeNs::EnumVariant(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
let ty = self.db.type_for_def(typable, Namespace::Types);
|
let ty = self.db.type_for_def(typable, Namespace::Types);
|
||||||
|
|
||||||
// For example, this substs will take `Gen::*<u32>*::make`
|
// For example, this substs will take `Gen::*<u32>*::make`
|
||||||
assert!(remaining_index > 0);
|
assert!(remaining_index > 0);
|
||||||
let substs = Ty::substs_from_path_segment(
|
let substs = Ty::substs_from_path_segment(
|
||||||
self.db,
|
self.db,
|
||||||
&self.resolver,
|
&self.resolver,
|
||||||
&path.segments[remaining_index + i - 1],
|
&path.segments[remaining_index + i - 1],
|
||||||
typable,
|
typable,
|
||||||
);
|
);
|
||||||
|
ty.subst(&substs)
|
||||||
ty.subst(&substs)
|
|
||||||
}
|
|
||||||
Resolution::LocalBinding(_) => {
|
|
||||||
// can't have a local binding in an associated item path
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Resolution::GenericParam(..) => {
|
|
||||||
// FIXME associated item of generic param
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Resolution::SelfType(_) => {
|
|
||||||
// FIXME associated item of self type
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
if is_last_segment {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to find an impl_item for the type which has a name matching
|
// Attempt to find an impl_item for the type which has a name matching
|
||||||
// the current segment
|
// the current segment
|
||||||
log::debug!("looking for path segment: {:?}", segment);
|
log::debug!("looking for path segment: {:?}", segment);
|
||||||
|
|
||||||
actual_def_ty = Some(ty.clone());
|
let ty = mem::replace(&mut ty, Ty::Unknown);
|
||||||
|
def = ty.iterate_impl_items(self.db, krate, |item| {
|
||||||
let item: crate::ModuleDef = ty.iterate_impl_items(self.db, krate, |item| {
|
match item {
|
||||||
let matching_def: Option<crate::ModuleDef> = match item {
|
crate::ImplItem::Method(_) => None,
|
||||||
crate::ImplItem::Method(func) => {
|
crate::ImplItem::Const(_) => None,
|
||||||
if segment.name == func.name(self.db) {
|
|
||||||
Some(func.into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::ImplItem::Const(konst) => {
|
|
||||||
let data = konst.data(self.db);
|
|
||||||
if segment.name == *data.name() {
|
|
||||||
Some(konst.into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Resolve associated types
|
// FIXME: Resolve associated types
|
||||||
crate::ImplItem::TypeAlias(_) => None,
|
crate::ImplItem::TypeAlias(_) => {
|
||||||
};
|
// Some(TypeNs::TypeAlias(..))
|
||||||
match matching_def {
|
None::<TypeNs>
|
||||||
Some(_) => {
|
|
||||||
self.write_assoc_resolution(id, item);
|
|
||||||
matching_def
|
|
||||||
}
|
}
|
||||||
None => None,
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
resolved = Resolution::Def(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match resolved {
|
let segment = path.segments.last().unwrap();
|
||||||
Resolution::Def(def) => {
|
let def = ty.clone().iterate_impl_items(self.db, krate, |item| {
|
||||||
let typable: Option<TypableDef> = def.into();
|
let matching_def: Option<ValueNs> = match item {
|
||||||
let typable = typable?;
|
crate::ImplItem::Method(func) => {
|
||||||
let mut ty = self.db.type_for_def(typable, Namespace::Values);
|
if segment.name == func.name(self.db) {
|
||||||
if let Some(sts) = self.find_self_types(&def, actual_def_ty) {
|
Some(ValueNs::Function(func))
|
||||||
ty = ty.subst(&sts);
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
|
crate::ImplItem::Const(konst) => {
|
||||||
let ty = ty.subst(&substs);
|
let data = konst.data(self.db);
|
||||||
let ty = self.insert_type_vars(ty);
|
if segment.name == *data.name() {
|
||||||
let ty = self.normalize_associated_types_in(ty);
|
Some(ValueNs::Const(konst))
|
||||||
Some(ty)
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crate::ImplItem::TypeAlias(_) => None,
|
||||||
|
};
|
||||||
|
match matching_def {
|
||||||
|
Some(_) => {
|
||||||
|
self.write_assoc_resolution(id, item);
|
||||||
|
matching_def
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
}
|
}
|
||||||
Resolution::LocalBinding(pat) => {
|
})?;
|
||||||
let ty = self.result.type_of_pat.get(pat)?.clone();
|
let self_types = self.find_self_types(&def, ty);
|
||||||
let ty = self.resolve_ty_as_possible(&mut vec![], ty);
|
Some((def, self_types))
|
||||||
Some(ty)
|
|
||||||
}
|
|
||||||
Resolution::GenericParam(..) => {
|
|
||||||
// generic params can't refer to values... yet
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Resolution::SelfType(_) => {
|
|
||||||
log::error!("path expr {:?} resolved to Self type in values ns", path);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_self_types(&self, def: &ModuleDef, actual_def_ty: Option<Ty>) -> Option<Substs> {
|
fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
|
||||||
let actual_def_ty = actual_def_ty?;
|
if let ValueNs::Function(func) = def {
|
||||||
|
|
||||||
if let crate::ModuleDef::Function(func) = def {
|
|
||||||
// We only do the infer if parent has generic params
|
// We only do the infer if parent has generic params
|
||||||
let gen = func.generic_params(self.db);
|
let gen = func.generic_params(self.db);
|
||||||
if gen.count_parent_params() == 0 {
|
if gen.count_parent_params() == 0 {
|
||||||
|
@ -641,30 +637,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
None => return (Ty::Unknown, None),
|
None => return (Ty::Unknown, None),
|
||||||
};
|
};
|
||||||
let resolver = &self.resolver;
|
let resolver = &self.resolver;
|
||||||
let typable: Option<TypableDef> =
|
let def: TypableDef =
|
||||||
// FIXME: this should resolve assoc items as well, see this example:
|
// FIXME: this should resolve assoc items as well, see this example:
|
||||||
// https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
|
// https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
|
||||||
match resolver.resolve_path_without_assoc_items(self.db, &path).take_types() {
|
match resolver.resolve_path_in_type_ns_fully(self.db, &path) {
|
||||||
Some(Resolution::Def(def)) => def.into(),
|
Some(TypeNs::Adt(Adt::Struct(it))) => it.into(),
|
||||||
Some(Resolution::LocalBinding(..)) => {
|
Some(TypeNs::Adt(Adt::Union(it))) => it.into(),
|
||||||
// this cannot happen
|
Some(TypeNs::EnumVariant(it)) => it.into(),
|
||||||
log::error!("path resolved to local binding in type ns");
|
Some(TypeNs::TypeAlias(it)) => it.into(),
|
||||||
return (Ty::Unknown, None);
|
|
||||||
|
Some(TypeNs::SelfType(_)) |
|
||||||
|
Some(TypeNs::GenericParam(_)) |
|
||||||
|
Some(TypeNs::BuiltinType(_)) |
|
||||||
|
Some(TypeNs::Trait(_)) |
|
||||||
|
Some(TypeNs::Adt(Adt::Enum(_))) |
|
||||||
|
None => {
|
||||||
|
return (Ty::Unknown, None)
|
||||||
}
|
}
|
||||||
Some(Resolution::GenericParam(..)) => {
|
|
||||||
// generic params can't be used in struct literals
|
|
||||||
return (Ty::Unknown, None);
|
|
||||||
}
|
|
||||||
Some(Resolution::SelfType(..)) => {
|
|
||||||
// FIXME this is allowed in an impl for a struct, handle this
|
|
||||||
return (Ty::Unknown, None);
|
|
||||||
}
|
|
||||||
None => return (Ty::Unknown, None),
|
|
||||||
};
|
};
|
||||||
let def = match typable {
|
|
||||||
None => return (Ty::Unknown, None),
|
|
||||||
Some(it) => it,
|
|
||||||
};
|
|
||||||
// FIXME remove the duplication between here and `Ty::from_path`?
|
// FIXME remove the duplication between here and `Ty::from_path`?
|
||||||
let substs = Ty::substs_from_path(self.db, resolver, path, def);
|
let substs = Ty::substs_from_path(self.db, resolver, path, def);
|
||||||
match def {
|
match def {
|
||||||
|
|
|
@ -19,7 +19,7 @@ use crate::{
|
||||||
generics::{GenericDef, WherePredicate},
|
generics::{GenericDef, WherePredicate},
|
||||||
nameres::Namespace,
|
nameres::Namespace,
|
||||||
path::{GenericArg, PathSegment},
|
path::{GenericArg, PathSegment},
|
||||||
resolve::{Resolution, Resolver},
|
resolve::{Resolver, TypeNs},
|
||||||
ty::Adt,
|
ty::Adt,
|
||||||
type_ref::{TypeBound, TypeRef},
|
type_ref::{TypeBound, TypeRef},
|
||||||
BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField,
|
BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField,
|
||||||
|
@ -88,16 +88,47 @@ impl Ty {
|
||||||
|
|
||||||
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
|
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
|
||||||
// Resolve the path (in type namespace)
|
// Resolve the path (in type namespace)
|
||||||
let (resolution, remaining_index) = resolver.resolve_path_segments(db, path).into_inner();
|
let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) {
|
||||||
let resolution = resolution.take_types();
|
Some(it) => it,
|
||||||
|
None => return Ty::Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
let def = match resolution {
|
let typable: TypableDef = match resolution {
|
||||||
Some(Resolution::Def(def)) => def,
|
TypeNs::Trait(trait_) => {
|
||||||
Some(Resolution::LocalBinding(..)) => {
|
let segment = match remaining_index {
|
||||||
// this should never happen
|
None => path.segments.last().expect("resolved path has at least one element"),
|
||||||
panic!("path resolved to local binding in type ns");
|
Some(i) => &path.segments[i - 1],
|
||||||
|
};
|
||||||
|
let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None);
|
||||||
|
return if let Some(remaining_index) = remaining_index {
|
||||||
|
if remaining_index == path.segments.len() - 1 {
|
||||||
|
let segment = &path.segments[remaining_index];
|
||||||
|
match trait_ref
|
||||||
|
.trait_
|
||||||
|
.associated_type_by_name_including_super_traits(db, &segment.name)
|
||||||
|
{
|
||||||
|
Some(associated_ty) => {
|
||||||
|
// FIXME handle type parameters on the segment
|
||||||
|
Ty::Projection(ProjectionTy {
|
||||||
|
associated_ty,
|
||||||
|
parameters: trait_ref.substs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// associated type not found
|
||||||
|
Ty::Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FIXME more than one segment remaining, is this possible?
|
||||||
|
Ty::Unknown
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FIXME dyn Trait without the dyn
|
||||||
|
Ty::Unknown
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Some(Resolution::GenericParam(idx)) => {
|
TypeNs::GenericParam(idx) => {
|
||||||
if remaining_index.is_some() {
|
if remaining_index.is_some() {
|
||||||
// e.g. T::Item
|
// e.g. T::Item
|
||||||
return Ty::Unknown;
|
return Ty::Unknown;
|
||||||
|
@ -111,57 +142,24 @@ impl Ty {
|
||||||
.clone(),
|
.clone(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Some(Resolution::SelfType(impl_block)) => {
|
TypeNs::SelfType(impl_block) => {
|
||||||
if remaining_index.is_some() {
|
if remaining_index.is_some() {
|
||||||
// e.g. Self::Item
|
// e.g. Self::Item
|
||||||
return Ty::Unknown;
|
return Ty::Unknown;
|
||||||
}
|
}
|
||||||
return impl_block.target_ty(db);
|
return impl_block.target_ty(db);
|
||||||
}
|
}
|
||||||
None => {
|
|
||||||
// path did not resolve
|
TypeNs::Adt(it) => it.into(),
|
||||||
return Ty::Unknown;
|
TypeNs::BuiltinType(it) => it.into(),
|
||||||
}
|
TypeNs::TypeAlias(it) => it.into(),
|
||||||
|
// FIXME: report error
|
||||||
|
TypeNs::EnumVariant(_) => return Ty::Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let ModuleDef::Trait(trait_) = def {
|
let ty = db.type_for_def(typable, Namespace::Types);
|
||||||
let segment = match remaining_index {
|
let substs = Ty::substs_from_path(db, resolver, path, typable);
|
||||||
None => path.segments.last().expect("resolved path has at least one element"),
|
ty.subst(&substs)
|
||||||
Some(i) => &path.segments[i - 1],
|
|
||||||
};
|
|
||||||
let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None);
|
|
||||||
if let Some(remaining_index) = remaining_index {
|
|
||||||
if remaining_index == path.segments.len() - 1 {
|
|
||||||
let segment = &path.segments[remaining_index];
|
|
||||||
let associated_ty = match trait_ref
|
|
||||||
.trait_
|
|
||||||
.associated_type_by_name_including_super_traits(db, &segment.name)
|
|
||||||
{
|
|
||||||
Some(t) => t,
|
|
||||||
None => {
|
|
||||||
// associated type not found
|
|
||||||
return Ty::Unknown;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// FIXME handle type parameters on the segment
|
|
||||||
Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs })
|
|
||||||
} else {
|
|
||||||
// FIXME more than one segment remaining, is this possible?
|
|
||||||
Ty::Unknown
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// FIXME dyn Trait without the dyn
|
|
||||||
Ty::Unknown
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let typable: TypableDef = match def.into() {
|
|
||||||
None => return Ty::Unknown,
|
|
||||||
Some(it) => it,
|
|
||||||
};
|
|
||||||
let ty = db.type_for_def(typable, Namespace::Types);
|
|
||||||
let substs = Ty::substs_from_path(db, resolver, path, typable);
|
|
||||||
ty.subst(&substs)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn substs_from_path_segment(
|
pub(super) fn substs_from_path_segment(
|
||||||
|
@ -278,8 +276,8 @@ impl TraitRef {
|
||||||
path: &Path,
|
path: &Path,
|
||||||
explicit_self_ty: Option<Ty>,
|
explicit_self_ty: Option<Ty>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let resolved = match resolver.resolve_path_without_assoc_items(db, &path).take_types()? {
|
let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? {
|
||||||
Resolution::Def(ModuleDef::Trait(tr)) => tr,
|
TypeNs::Trait(tr) => tr,
|
||||||
_ => return None,
|
_ => 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");
|
||||||
|
|
|
@ -3,11 +3,11 @@ use crate::completion::{CompletionContext, Completions};
|
||||||
pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
|
pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
// Show only macros in top level.
|
// Show only macros in top level.
|
||||||
if ctx.is_new_item {
|
if ctx.is_new_item {
|
||||||
for (name, res) in ctx.analyzer.all_names(ctx.db) {
|
ctx.analyzer.process_all_names(ctx.db, &mut |name, res| {
|
||||||
if res.get_macros().is_some() {
|
if let hir::ScopeDef::MacroDef(mac) = res {
|
||||||
acc.add_resolution(ctx, name.to_string(), &res.only_macros());
|
acc.add_macro(ctx, Some(name.to_string()), mac);
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use hir::{Adt, Either, Resolution};
|
use hir::{Adt, Either, PathResolution};
|
||||||
use ra_syntax::AstNode;
|
use ra_syntax::AstNode;
|
||||||
use test_utils::tested_by;
|
use test_utils::tested_by;
|
||||||
|
|
||||||
|
@ -9,15 +9,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
Some(path) => path.clone(),
|
Some(path) => path.clone(),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let def = match ctx.analyzer.resolve_hir_path(ctx.db, &path).take_types() {
|
let def = match dbg!(ctx.analyzer.resolve_hir_path(ctx.db, &path)) {
|
||||||
Some(Resolution::Def(def)) => def,
|
Some(PathResolution::Def(def)) => def,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
match def {
|
match def {
|
||||||
hir::ModuleDef::Module(module) => {
|
hir::ModuleDef::Module(module) => {
|
||||||
let module_scope = module.scope(ctx.db);
|
let module_scope = module.scope(ctx.db);
|
||||||
for (name, res) in module_scope.entries() {
|
for (name, res) in module_scope.entries() {
|
||||||
if let Some(hir::ModuleDef::BuiltinType(..)) = res.def.as_ref().take_types() {
|
if let Some(hir::ModuleDef::BuiltinType(..)) = res.def.take_types() {
|
||||||
if ctx.use_item_syntax.is_some() {
|
if ctx.use_item_syntax.is_some() {
|
||||||
tested_by!(dont_complete_primitive_in_use);
|
tested_by!(dont_complete_primitive_in_use);
|
||||||
continue;
|
continue;
|
||||||
|
@ -34,7 +34,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
acc.add_resolution(ctx, name.to_string(), &res.def.map(hir::Resolution::Def));
|
acc.add_resolution(ctx, name.to_string(), &res.def.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => {
|
hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => {
|
||||||
|
|
|
@ -7,22 +7,20 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
}
|
}
|
||||||
// FIXME: ideally, we should look at the type we are matching against and
|
// FIXME: ideally, we should look at the type we are matching against and
|
||||||
// suggest variants + auto-imports
|
// suggest variants + auto-imports
|
||||||
let names = ctx.analyzer.all_names(ctx.db);
|
ctx.analyzer.process_all_names(ctx.db, &mut |name, res| {
|
||||||
for (name, res) in names.into_iter() {
|
let def = match &res {
|
||||||
let r = res.as_ref();
|
hir::ScopeDef::ModuleDef(def) => def,
|
||||||
let def = match r.take_types().or_else(|| r.take_values()) {
|
_ => return,
|
||||||
Some(hir::Resolution::Def(def)) => def,
|
|
||||||
_ => continue,
|
|
||||||
};
|
};
|
||||||
match def {
|
match def {
|
||||||
hir::ModuleDef::Adt(hir::Adt::Enum(..))
|
hir::ModuleDef::Adt(hir::Adt::Enum(..))
|
||||||
| hir::ModuleDef::EnumVariant(..)
|
| hir::ModuleDef::EnumVariant(..)
|
||||||
| hir::ModuleDef::Const(..)
|
| hir::ModuleDef::Const(..)
|
||||||
| hir::ModuleDef::Module(..) => (),
|
| hir::ModuleDef::Module(..) => (),
|
||||||
_ => continue,
|
_ => return,
|
||||||
}
|
}
|
||||||
acc.add_resolution(ctx, name.to_string(), &res)
|
acc.add_resolution(ctx, name.to_string(), &res)
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -10,8 +10,9 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let names = ctx.analyzer.all_names(ctx.db);
|
ctx.analyzer.process_all_names(ctx.db, &mut |name, res| {
|
||||||
names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res));
|
acc.add_resolution(ctx, name.to_string(), &res)
|
||||||
|
});
|
||||||
|
|
||||||
// auto-import
|
// auto-import
|
||||||
// We fetch ident from the original file, because we need to pre-filter auto-imports
|
// We fetch ident from the original file, because we need to pre-filter auto-imports
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! This modules takes care of rendering various defenitions as completion items.
|
//! This modules takes care of rendering various definitions as completion items.
|
||||||
use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty, TypeWalk};
|
use hir::{Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
|
||||||
use join_to_string::join;
|
use join_to_string::join;
|
||||||
use ra_syntax::ast::NameOwner;
|
use ra_syntax::ast::NameOwner;
|
||||||
use test_utils::tested_by;
|
use test_utils::tested_by;
|
||||||
|
@ -39,19 +39,65 @@ impl Completions {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
local_name: String,
|
local_name: String,
|
||||||
resolution: &PerNs<Resolution>,
|
resolution: &ScopeDef,
|
||||||
) {
|
) {
|
||||||
use hir::ModuleDef::*;
|
use hir::ModuleDef::*;
|
||||||
|
|
||||||
if let Some(macro_) = resolution.get_macros() {
|
// if let Some(macro_) = resolution.get_macros() {
|
||||||
self.add_macro(ctx, Some(local_name.clone()), macro_);
|
// self.add_macro(ctx, Some(local_name.clone()), macro_);
|
||||||
}
|
// }
|
||||||
|
|
||||||
let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
|
// let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
|
||||||
let def = match def {
|
// let def = match def {
|
||||||
// Only insert once if it is just a macro name
|
// // Only insert once if it is just a macro name
|
||||||
None if resolution.get_macros().is_some() => return,
|
// None if resolution.get_macros().is_some() => return,
|
||||||
None => {
|
// None => {
|
||||||
|
// self.add(CompletionItem::new(
|
||||||
|
// CompletionKind::Reference,
|
||||||
|
// ctx.source_range(),
|
||||||
|
// local_name,
|
||||||
|
// ));
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// Some(it) => it,
|
||||||
|
// };
|
||||||
|
let mut completion_kind = CompletionKind::Reference;
|
||||||
|
let (kind, docs) = match resolution {
|
||||||
|
ScopeDef::ModuleDef(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
|
||||||
|
ScopeDef::ModuleDef(Function(func)) => {
|
||||||
|
return self.add_function_with_name(ctx, Some(local_name), *func);
|
||||||
|
}
|
||||||
|
ScopeDef::ModuleDef(Adt(hir::Adt::Struct(it))) => {
|
||||||
|
(CompletionItemKind::Struct, it.docs(ctx.db))
|
||||||
|
}
|
||||||
|
ScopeDef::ModuleDef(Adt(hir::Adt::Union(it))) => {
|
||||||
|
(CompletionItemKind::Struct, it.docs(ctx.db))
|
||||||
|
}
|
||||||
|
ScopeDef::ModuleDef(Adt(hir::Adt::Enum(it))) => {
|
||||||
|
(CompletionItemKind::Enum, it.docs(ctx.db))
|
||||||
|
}
|
||||||
|
ScopeDef::ModuleDef(EnumVariant(it)) => {
|
||||||
|
(CompletionItemKind::EnumVariant, it.docs(ctx.db))
|
||||||
|
}
|
||||||
|
ScopeDef::ModuleDef(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
|
||||||
|
ScopeDef::ModuleDef(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
|
||||||
|
ScopeDef::ModuleDef(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
|
||||||
|
ScopeDef::ModuleDef(TypeAlias(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
|
||||||
|
ScopeDef::ModuleDef(BuiltinType(..)) => {
|
||||||
|
completion_kind = CompletionKind::BuiltinType;
|
||||||
|
(CompletionItemKind::BuiltinType, None)
|
||||||
|
}
|
||||||
|
ScopeDef::GenericParam(..) => (CompletionItemKind::TypeParam, None),
|
||||||
|
ScopeDef::LocalBinding(..) => (CompletionItemKind::Binding, None),
|
||||||
|
ScopeDef::SelfType(..) => (
|
||||||
|
CompletionItemKind::TypeParam, // (does this need its own kind?)
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
ScopeDef::MacroDef(mac) => {
|
||||||
|
self.add_macro(ctx, Some(local_name.clone()), *mac);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ScopeDef::Unknown => {
|
||||||
self.add(CompletionItem::new(
|
self.add(CompletionItem::new(
|
||||||
CompletionKind::Reference,
|
CompletionKind::Reference,
|
||||||
ctx.source_range(),
|
ctx.source_range(),
|
||||||
|
@ -59,41 +105,11 @@ impl Completions {
|
||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some(it) => it,
|
|
||||||
};
|
|
||||||
let mut completion_kind = CompletionKind::Reference;
|
|
||||||
let (kind, docs) = match def {
|
|
||||||
Resolution::Def(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
|
|
||||||
Resolution::Def(Function(func)) => {
|
|
||||||
return self.add_function_with_name(ctx, Some(local_name), *func);
|
|
||||||
}
|
|
||||||
Resolution::Def(Adt(hir::Adt::Struct(it))) => {
|
|
||||||
(CompletionItemKind::Struct, it.docs(ctx.db))
|
|
||||||
}
|
|
||||||
Resolution::Def(Adt(hir::Adt::Union(it))) => {
|
|
||||||
(CompletionItemKind::Struct, it.docs(ctx.db))
|
|
||||||
}
|
|
||||||
Resolution::Def(Adt(hir::Adt::Enum(it))) => (CompletionItemKind::Enum, it.docs(ctx.db)),
|
|
||||||
Resolution::Def(EnumVariant(it)) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
|
|
||||||
Resolution::Def(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
|
|
||||||
Resolution::Def(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
|
|
||||||
Resolution::Def(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
|
|
||||||
Resolution::Def(TypeAlias(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
|
|
||||||
Resolution::Def(BuiltinType(..)) => {
|
|
||||||
completion_kind = CompletionKind::BuiltinType;
|
|
||||||
(CompletionItemKind::BuiltinType, None)
|
|
||||||
}
|
|
||||||
Resolution::GenericParam(..) => (CompletionItemKind::TypeParam, None),
|
|
||||||
Resolution::LocalBinding(..) => (CompletionItemKind::Binding, None),
|
|
||||||
Resolution::SelfType(..) => (
|
|
||||||
CompletionItemKind::TypeParam, // (does this need its own kind?)
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut completion_item =
|
let mut completion_item =
|
||||||
CompletionItem::new(completion_kind, ctx.source_range(), local_name);
|
CompletionItem::new(completion_kind, ctx.source_range(), local_name);
|
||||||
if let Resolution::LocalBinding(pat_id) = def {
|
if let ScopeDef::LocalBinding(pat_id) = resolution {
|
||||||
let ty = ctx
|
let ty = ctx
|
||||||
.analyzer
|
.analyzer
|
||||||
.type_of_pat_by_id(ctx.db, pat_id.clone())
|
.type_of_pat_by_id(ctx.db, pat_id.clone())
|
||||||
|
@ -108,7 +124,12 @@ impl Completions {
|
||||||
self.add_function_with_name(ctx, None, func)
|
self.add_function_with_name(ctx, None, func)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_macro(&mut self, ctx: &CompletionContext, name: Option<String>, macro_: hir::MacroDef) {
|
pub(crate) fn add_macro(
|
||||||
|
&mut self,
|
||||||
|
ctx: &CompletionContext,
|
||||||
|
name: Option<String>,
|
||||||
|
macro_: hir::MacroDef,
|
||||||
|
) {
|
||||||
let ast_node = macro_.source(ctx.db).ast;
|
let ast_node = macro_.source(ctx.db).ast;
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
let detail = macro_label(&ast_node);
|
let detail = macro_label(&ast_node);
|
||||||
|
|
Loading…
Reference in a new issue