Merge #1862
1862: Assoc item resolution refactoring (again) r=flodiebold a=flodiebold This is #1849, with the associated type selection code removed for now. Handling cycles there will need some more thought. Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
commit
54379ec6f8
@ -1,7 +1,7 @@
|
||||
use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
|
||||
|
||||
use ra_db::SourceDatabase;
|
||||
use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty, TypeWalk};
|
||||
use ra_hir::{AssocItem, Crate, HasBodySource, HasSource, HirDisplay, ModuleDef, Ty, TypeWalk};
|
||||
use ra_syntax::AstNode;
|
||||
|
||||
use crate::{Result, Verbosity};
|
||||
@ -47,7 +47,7 @@ pub fn run(
|
||||
for impl_block in module.impl_blocks(db) {
|
||||
for item in impl_block.items(db) {
|
||||
num_decls += 1;
|
||||
if let ImplItem::Method(f) = item {
|
||||
if let AssocItem::Function(f) = item {
|
||||
funcs.push(f);
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
},
|
||||
nameres::{CrateModuleId, ImportId, ModuleScope, Namespace},
|
||||
resolve::{Resolver, TypeNs},
|
||||
traits::{TraitData, TraitItem},
|
||||
traits::TraitData,
|
||||
ty::{
|
||||
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
|
||||
InferenceResult, TraitRef,
|
||||
@ -269,7 +269,7 @@ pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
|
||||
|
||||
for impl_block in self.impl_blocks(db) {
|
||||
for item in impl_block.items(db) {
|
||||
if let crate::ImplItem::Method(f) = item {
|
||||
if let AssocItem::Function(f) = item {
|
||||
f.diagnostics(db, sink);
|
||||
}
|
||||
}
|
||||
@ -749,6 +749,10 @@ pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> {
|
||||
db.const_data(self)
|
||||
}
|
||||
|
||||
pub fn name(&self, db: &impl HirDatabase) -> Option<Name> {
|
||||
self.data(db).name().cloned()
|
||||
}
|
||||
|
||||
pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
|
||||
db.infer(self.into())
|
||||
}
|
||||
@ -849,7 +853,7 @@ pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
|
||||
self.trait_data(db).name().clone()
|
||||
}
|
||||
|
||||
pub fn items(self, db: &impl DefDatabase) -> Vec<TraitItem> {
|
||||
pub fn items(self, db: &impl DefDatabase) -> Vec<AssocItem> {
|
||||
self.trait_data(db).items().to_vec()
|
||||
}
|
||||
|
||||
@ -902,7 +906,7 @@ pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Opti
|
||||
.items()
|
||||
.iter()
|
||||
.filter_map(|item| match item {
|
||||
TraitItem::TypeAlias(t) => Some(*t),
|
||||
AssocItem::TypeAlias(t) => Some(*t),
|
||||
_ => None,
|
||||
})
|
||||
.find(|t| &t.name(db) == name)
|
||||
@ -1019,3 +1023,15 @@ pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum AssocItem {
|
||||
Function(Function),
|
||||
Const(Const),
|
||||
TypeAlias(TypeAlias),
|
||||
}
|
||||
// FIXME: not every function, ... is actually an assoc item. maybe we should make
|
||||
// sure that you can only turn actual assoc items into AssocItems. This would
|
||||
// require not implementing From, and instead having some checked way of
|
||||
// casting them, and somehow making the constructors private, which would be annoying.
|
||||
impl_froms!(AssocItem: Function, Const, TypeAlias);
|
||||
|
@ -15,7 +15,7 @@
|
||||
resolve::Resolver,
|
||||
ty::Ty,
|
||||
type_ref::TypeRef,
|
||||
Const, Function, HasSource, HirFileId, Source, TraitRef, TypeAlias,
|
||||
AssocItem, Const, Function, HasSource, HirFileId, Source, TraitRef, TypeAlias,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
@ -56,7 +56,7 @@ fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock>
|
||||
impl ImplBlock {
|
||||
pub(crate) fn containing(
|
||||
module_impl_blocks: Arc<ModuleImplBlocks>,
|
||||
item: ImplItem,
|
||||
item: AssocItem,
|
||||
) -> Option<ImplBlock> {
|
||||
let impl_id = *module_impl_blocks.impls_by_def.get(&item)?;
|
||||
Some(ImplBlock { module: module_impl_blocks.module, impl_id })
|
||||
@ -91,7 +91,7 @@ pub fn target_trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> {
|
||||
TraitRef::from_hir(db, &self.resolver(db), &self.target_trait(db)?, Some(target_ty))
|
||||
}
|
||||
|
||||
pub fn items(&self, db: &impl DefDatabase) -> Vec<ImplItem> {
|
||||
pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> {
|
||||
db.impls_in_module(self.module).impls[self.impl_id].items().to_vec()
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver {
|
||||
pub struct ImplData {
|
||||
target_trait: Option<TypeRef>,
|
||||
target_type: TypeRef,
|
||||
items: Vec<ImplItem>,
|
||||
items: Vec<AssocItem>,
|
||||
negative: bool,
|
||||
}
|
||||
|
||||
@ -151,27 +151,11 @@ pub fn target_type(&self) -> &TypeRef {
|
||||
&self.target_type
|
||||
}
|
||||
|
||||
pub fn items(&self) -> &[ImplItem] {
|
||||
pub fn items(&self) -> &[AssocItem] {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
//FIXME: rename to ImplDef?
|
||||
pub enum ImplItem {
|
||||
Method(Function),
|
||||
Const(Const),
|
||||
TypeAlias(TypeAlias),
|
||||
// Existential
|
||||
}
|
||||
impl_froms!(ImplItem: Const, TypeAlias);
|
||||
|
||||
impl From<Function> for ImplItem {
|
||||
fn from(func: Function) -> ImplItem {
|
||||
ImplItem::Method(func)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct ImplId(pub RawId);
|
||||
impl_arena_id!(ImplId);
|
||||
@ -185,7 +169,7 @@ fn from(func: Function) -> ImplItem {
|
||||
pub struct ModuleImplBlocks {
|
||||
pub(crate) module: Module,
|
||||
pub(crate) impls: Arena<ImplId, ImplData>,
|
||||
impls_by_def: FxHashMap<ImplItem, ImplId>,
|
||||
impls_by_def: FxHashMap<AssocItem, ImplId>,
|
||||
}
|
||||
|
||||
impl ModuleImplBlocks {
|
||||
|
@ -69,7 +69,7 @@ fn from(it: $sv) -> $e {
|
||||
expr::ExprScopes,
|
||||
generics::{GenericParam, GenericParams, HasGenericParams},
|
||||
ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile},
|
||||
impl_block::{ImplBlock, ImplItem},
|
||||
impl_block::ImplBlock,
|
||||
name::Name,
|
||||
nameres::{ImportId, Namespace, PerNs},
|
||||
path::{Path, PathKind},
|
||||
@ -85,7 +85,7 @@ fn from(it: $sv) -> $e {
|
||||
pub use self::code_model::{
|
||||
docs::{DocDef, Docs, Documentation},
|
||||
src::{HasBodySource, HasSource, Source},
|
||||
Adt, BuiltinType, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
|
||||
EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, ModuleSource,
|
||||
Static, Struct, StructField, Trait, TypeAlias, Union,
|
||||
Adt, AssocItem, BuiltinType, Const, ConstData, Container, Crate, CrateDependency, DefWithBody,
|
||||
Enum, EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef,
|
||||
ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
|
||||
};
|
||||
|
@ -190,6 +190,13 @@ pub fn as_ident(&self) -> Option<&Name> {
|
||||
pub fn expand_macro_expr(&self) -> Option<Name> {
|
||||
self.as_ident().and_then(|name| Some(name.clone()))
|
||||
}
|
||||
|
||||
pub fn is_type_relative(&self) -> bool {
|
||||
match self.kind {
|
||||
PathKind::Type(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericArgs {
|
||||
|
@ -15,7 +15,6 @@
|
||||
name::{Name, SELF_PARAM, SELF_TYPE},
|
||||
nameres::{CrateDefMap, CrateModuleId, PerNs},
|
||||
path::{Path, PathKind},
|
||||
type_ref::TypeRef,
|
||||
Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct,
|
||||
Trait, TypeAlias,
|
||||
};
|
||||
@ -50,7 +49,7 @@ pub(crate) enum Scope {
|
||||
ExprScope(ExprScope),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum TypeNs {
|
||||
SelfType(ImplBlock),
|
||||
GenericParam(u32),
|
||||
@ -59,19 +58,18 @@ pub enum TypeNs {
|
||||
TypeAlias(TypeAlias),
|
||||
BuiltinType(BuiltinType),
|
||||
Trait(Trait),
|
||||
// Module belong to type ns, but the resovler is used when all module paths
|
||||
// Module belong to type ns, but the resolver is used when all module paths
|
||||
// are fully resolved.
|
||||
// Module(Module)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ResolveValueResult<'a> {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ResolveValueResult {
|
||||
ValueNs(ValueNs),
|
||||
Partial(TypeNs, usize),
|
||||
TypeRef(&'a TypeRef),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ValueNs {
|
||||
LocalBinding(PatId),
|
||||
Function(Function),
|
||||
@ -131,6 +129,9 @@ pub(crate) fn resolve_path_in_type_ns(
|
||||
db: &impl HirDatabase,
|
||||
path: &Path,
|
||||
) -> Option<(TypeNs, Option<usize>)> {
|
||||
if path.is_type_relative() {
|
||||
return None;
|
||||
}
|
||||
let first_name = &path.segments.first()?.name;
|
||||
let skip_to_mod = path.kind != PathKind::Plain;
|
||||
for scope in self.scopes.iter().rev() {
|
||||
@ -189,11 +190,10 @@ pub(crate) fn resolve_path_in_value_ns<'p>(
|
||||
&self,
|
||||
db: &impl HirDatabase,
|
||||
path: &'p Path,
|
||||
) -> Option<ResolveValueResult<'p>> {
|
||||
if let PathKind::Type(type_ref) = &path.kind {
|
||||
return Some(ResolveValueResult::TypeRef(type_ref));
|
||||
) -> Option<ResolveValueResult> {
|
||||
if path.is_type_relative() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let n_segments = path.segments.len();
|
||||
let tmp = SELF_PARAM;
|
||||
let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name };
|
||||
@ -284,7 +284,7 @@ pub(crate) fn resolve_path_in_value_ns_fully(
|
||||
) -> Option<ValueNs> {
|
||||
match self.resolve_path_in_value_ns(db, path)? {
|
||||
ResolveValueResult::ValueNs(it) => Some(it),
|
||||
ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None,
|
||||
ResolveValueResult::Partial(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ pub enum PathResolution {
|
||||
GenericParam(u32),
|
||||
SelfType(crate::ImplBlock),
|
||||
Macro(MacroDef),
|
||||
AssocItem(crate::ImplItem),
|
||||
AssocItem(crate::AssocItem),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -9,13 +9,13 @@
|
||||
db::{AstDatabase, DefDatabase},
|
||||
ids::LocationCtx,
|
||||
name::AsName,
|
||||
Const, Function, HasSource, Module, Name, Trait, TypeAlias,
|
||||
AssocItem, Const, Function, HasSource, Module, Name, Trait, TypeAlias,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TraitData {
|
||||
name: Option<Name>,
|
||||
items: Vec<TraitItem>,
|
||||
items: Vec<AssocItem>,
|
||||
auto: bool,
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ pub(crate) fn name(&self) -> &Option<Name> {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub(crate) fn items(&self) -> &[TraitItem] {
|
||||
pub(crate) fn items(&self) -> &[AssocItem] {
|
||||
&self.items
|
||||
}
|
||||
|
||||
@ -57,22 +57,9 @@ pub(crate) fn is_auto(&self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum TraitItem {
|
||||
Function(Function),
|
||||
Const(Const),
|
||||
TypeAlias(TypeAlias),
|
||||
// Existential
|
||||
}
|
||||
// FIXME: not every function, ... is actually a trait item. maybe we should make
|
||||
// sure that you can only turn actual trait items into TraitItems. This would
|
||||
// require not implementing From, and instead having some checked way of
|
||||
// casting them.
|
||||
impl_froms!(TraitItem: Function, Const, TypeAlias);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TraitItemsIndex {
|
||||
traits_by_def: FxHashMap<TraitItem, Trait>,
|
||||
traits_by_def: FxHashMap<AssocItem, Trait>,
|
||||
}
|
||||
|
||||
impl TraitItemsIndex {
|
||||
@ -88,7 +75,7 @@ pub(crate) fn trait_items_index(db: &impl DefDatabase, module: Module) -> TraitI
|
||||
index
|
||||
}
|
||||
|
||||
pub(crate) fn get_parent_trait(&self, item: TraitItem) -> Option<Trait> {
|
||||
pub(crate) fn get_parent_trait(&self, item: AssocItem) -> Option<Trait> {
|
||||
self.traits_by_def.get(&item).cloned()
|
||||
}
|
||||
}
|
||||
|
@ -48,8 +48,7 @@
|
||||
resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||
ty::infer::diagnostics::InferenceDiagnostic,
|
||||
type_ref::{Mutability, TypeRef},
|
||||
Adt, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path,
|
||||
StructField,
|
||||
Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField,
|
||||
};
|
||||
|
||||
mod unify;
|
||||
@ -121,7 +120,7 @@ pub struct InferenceResult {
|
||||
/// For each struct literal, records the variant it resolves to.
|
||||
variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>,
|
||||
/// For each associated item record what it resolves to
|
||||
assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>,
|
||||
assoc_resolutions: FxHashMap<ExprOrPatId, AssocItem>,
|
||||
diagnostics: Vec<InferenceDiagnostic>,
|
||||
pub(super) type_of_expr: ArenaMap<ExprId, Ty>,
|
||||
pub(super) type_of_pat: ArenaMap<PatId, Ty>,
|
||||
@ -141,10 +140,10 @@ pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantDef> {
|
||||
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantDef> {
|
||||
self.variant_resolutions.get(&id.into()).copied()
|
||||
}
|
||||
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<ImplItem> {
|
||||
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItem> {
|
||||
self.assoc_resolutions.get(&id.into()).copied()
|
||||
}
|
||||
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> {
|
||||
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItem> {
|
||||
self.assoc_resolutions.get(&id.into()).copied()
|
||||
}
|
||||
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
|
||||
@ -235,7 +234,7 @@ fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantDef) {
|
||||
self.result.variant_resolutions.insert(id, variant);
|
||||
}
|
||||
|
||||
fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: ImplItem) {
|
||||
fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItem) {
|
||||
self.result.assoc_resolutions.insert(id, item);
|
||||
}
|
||||
|
||||
@ -468,16 +467,27 @@ fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty
|
||||
}
|
||||
|
||||
fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> {
|
||||
let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
|
||||
|
||||
let (value, self_subst) = match value_or_partial {
|
||||
ResolveValueResult::ValueNs(it) => (it, None),
|
||||
ResolveValueResult::Partial(def, remaining_index) => {
|
||||
self.resolve_assoc_item(Either::A(def), path, remaining_index, id)?
|
||||
let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind {
|
||||
if path.segments.is_empty() {
|
||||
// This can't actually happen syntax-wise
|
||||
return None;
|
||||
}
|
||||
ResolveValueResult::TypeRef(type_ref) => {
|
||||
let ty = self.make_ty(type_ref);
|
||||
self.resolve_assoc_item(Either::B(ty), path, 0, id)?
|
||||
let ty = self.make_ty(type_ref);
|
||||
let remaining_segments_for_ty = &path.segments[..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"),
|
||||
id,
|
||||
)?
|
||||
} else {
|
||||
let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
|
||||
|
||||
match value_or_partial {
|
||||
ResolveValueResult::ValueNs(it) => (it, None),
|
||||
ResolveValueResult::Partial(def, remaining_index) => {
|
||||
self.resolve_assoc_item(def, path, remaining_index, id)?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -508,101 +518,91 @@ fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId)
|
||||
|
||||
fn resolve_assoc_item(
|
||||
&mut self,
|
||||
mut def_or_ty: Either<TypeNs, Ty>,
|
||||
def: TypeNs,
|
||||
path: &Path,
|
||||
remaining_index: usize,
|
||||
id: ExprOrPatId,
|
||||
) -> Option<(ValueNs, Option<Substs>)> {
|
||||
assert!(remaining_index < path.segments.len());
|
||||
let krate = self.resolver.krate()?;
|
||||
// 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 mut ty = Ty::Unknown;
|
||||
let resolved_segment = &path.segments[remaining_index - 1];
|
||||
let remaining_segments = &path.segments[remaining_index..];
|
||||
let is_before_last = remaining_segments.len() == 1;
|
||||
|
||||
// resolve intermediate segments
|
||||
for (i, segment) in path.segments[remaining_index..].iter().enumerate() {
|
||||
let is_last_segment = i == path.segments[remaining_index..].len() - 1;
|
||||
ty = match def_or_ty {
|
||||
Either::A(def) => {
|
||||
let typable: TypableDef = match def {
|
||||
TypeNs::Adt(it) => it.into(),
|
||||
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);
|
||||
|
||||
// For example, this substs will take `Gen::*<u32>*::make`
|
||||
assert!(remaining_index > 0);
|
||||
let substs = Ty::substs_from_path_segment(
|
||||
self.db,
|
||||
&self.resolver,
|
||||
&path.segments[remaining_index + i - 1],
|
||||
typable,
|
||||
);
|
||||
ty.subst(&substs)
|
||||
}
|
||||
Either::B(ty) => ty,
|
||||
};
|
||||
if is_last_segment {
|
||||
break;
|
||||
match (def, is_before_last) {
|
||||
(TypeNs::Trait(_trait), true) => {
|
||||
// FIXME Associated item of trait, e.g. `Default::default`
|
||||
None
|
||||
}
|
||||
|
||||
// Attempt to find an impl_item for the type which has a name matching
|
||||
// the current segment
|
||||
log::debug!("looking for path segment: {:?}", segment);
|
||||
|
||||
let ty = mem::replace(&mut ty, Ty::Unknown);
|
||||
def_or_ty = ty.iterate_impl_items(self.db, krate, |item| {
|
||||
match item {
|
||||
crate::ImplItem::Method(_) => None,
|
||||
crate::ImplItem::Const(_) => None,
|
||||
|
||||
// FIXME: Resolve associated types
|
||||
crate::ImplItem::TypeAlias(_) => {
|
||||
// Some(Either::A(TypeNs::TypeAlias(..)))
|
||||
None
|
||||
}
|
||||
(def, _) => {
|
||||
// Either we already have a type (e.g. `Vec::new`), or we have a
|
||||
// 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 ty = Ty::from_partly_resolved_hir_path(
|
||||
self.db,
|
||||
&self.resolver,
|
||||
def,
|
||||
resolved_segment,
|
||||
remaining_segments_for_ty,
|
||||
);
|
||||
if let Ty::Unknown = ty {
|
||||
return None;
|
||||
}
|
||||
})?;
|
||||
|
||||
let segment =
|
||||
remaining_segments.last().expect("there should be at least one segment here");
|
||||
|
||||
self.resolve_ty_assoc_item(ty, segment, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_ty_assoc_item(
|
||||
&mut self,
|
||||
ty: Ty,
|
||||
segment: &crate::path::PathSegment,
|
||||
id: ExprOrPatId,
|
||||
) -> Option<(ValueNs, Option<Substs>)> {
|
||||
if let Ty::Unknown = ty {
|
||||
return None;
|
||||
}
|
||||
|
||||
let segment = path.segments.last().unwrap();
|
||||
let def = ty.clone().iterate_impl_items(self.db, krate, |item| {
|
||||
let matching_def: Option<ValueNs> = match item {
|
||||
crate::ImplItem::Method(func) => {
|
||||
if segment.name == func.name(self.db) {
|
||||
Some(ValueNs::Function(func))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
let krate = self.resolver.krate()?;
|
||||
|
||||
crate::ImplItem::Const(konst) => {
|
||||
let data = konst.data(self.db);
|
||||
if Some(&segment.name) == data.name() {
|
||||
Some(ValueNs::Const(konst))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
// Find impl
|
||||
// FIXME: consider trait candidates
|
||||
let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
|
||||
AssocItem::Function(func) => {
|
||||
if segment.name == func.name(self.db) {
|
||||
Some(AssocItem::Function(func))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
crate::ImplItem::TypeAlias(_) => None,
|
||||
};
|
||||
match matching_def {
|
||||
Some(_) => {
|
||||
self.write_assoc_resolution(id, item);
|
||||
matching_def
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
|
||||
AssocItem::Const(konst) => {
|
||||
if konst.name(self.db).map_or(false, |n| n == segment.name) {
|
||||
Some(AssocItem::Const(konst))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
AssocItem::TypeAlias(_) => None,
|
||||
})?;
|
||||
let self_types = self.find_self_types(&def, ty);
|
||||
Some((def, self_types))
|
||||
let def = match item {
|
||||
AssocItem::Function(f) => ValueNs::Function(f),
|
||||
AssocItem::Const(c) => ValueNs::Const(c),
|
||||
AssocItem::TypeAlias(_) => unreachable!(),
|
||||
};
|
||||
let substs = self.find_self_types(&def, ty);
|
||||
|
||||
self.write_assoc_resolution(id, item);
|
||||
Some((def, substs))
|
||||
}
|
||||
|
||||
fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
|
||||
|
@ -86,78 +86,125 @@ pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &Ty
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
|
||||
// Resolve the path (in type namespace)
|
||||
let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) {
|
||||
Some(it) => it,
|
||||
None => return Ty::Unknown,
|
||||
};
|
||||
pub(crate) fn from_type_relative_path(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
ty: Ty,
|
||||
remaining_segments: &[PathSegment],
|
||||
) -> Ty {
|
||||
if remaining_segments.len() == 1 {
|
||||
// resolve unselected assoc types
|
||||
let segment = &remaining_segments[0];
|
||||
Ty::select_associated_type(db, resolver, ty, segment)
|
||||
} else if remaining_segments.len() > 1 {
|
||||
// FIXME report error (ambiguous associated type)
|
||||
Ty::Unknown
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
|
||||
let typable: TypableDef = match resolution {
|
||||
pub(crate) fn from_partly_resolved_hir_path(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolution: TypeNs,
|
||||
resolved_segment: &PathSegment,
|
||||
remaining_segments: &[PathSegment],
|
||||
) -> Ty {
|
||||
let ty = match resolution {
|
||||
TypeNs::Trait(trait_) => {
|
||||
let segment = match remaining_index {
|
||||
None => path.segments.last().expect("resolved path has at least one element"),
|
||||
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
|
||||
}
|
||||
let trait_ref =
|
||||
TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None);
|
||||
return if remaining_segments.len() == 1 {
|
||||
let segment = &remaining_segments[0];
|
||||
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 => {
|
||||
// FIXME: report error (associated type not found)
|
||||
Ty::Unknown
|
||||
}
|
||||
} else {
|
||||
// FIXME more than one segment remaining, is this possible?
|
||||
Ty::Unknown
|
||||
}
|
||||
} else if remaining_segments.len() > 1 {
|
||||
// FIXME report error (ambiguous associated type)
|
||||
Ty::Unknown
|
||||
} else {
|
||||
Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)]))
|
||||
};
|
||||
}
|
||||
TypeNs::GenericParam(idx) => {
|
||||
if remaining_index.is_some() {
|
||||
// e.g. T::Item
|
||||
return Ty::Unknown;
|
||||
}
|
||||
return Ty::Param {
|
||||
idx,
|
||||
// FIXME: maybe return name in resolution?
|
||||
name: path
|
||||
.as_ident()
|
||||
.expect("generic param should be single-segment path")
|
||||
.clone(),
|
||||
};
|
||||
}
|
||||
TypeNs::SelfType(impl_block) => {
|
||||
if remaining_index.is_some() {
|
||||
// e.g. Self::Item
|
||||
return Ty::Unknown;
|
||||
}
|
||||
return impl_block.target_ty(db);
|
||||
// FIXME: maybe return name in resolution?
|
||||
let name = resolved_segment.name.clone();
|
||||
Ty::Param { idx, name }
|
||||
}
|
||||
TypeNs::SelfType(impl_block) => impl_block.target_ty(db),
|
||||
|
||||
TypeNs::Adt(it) => it.into(),
|
||||
TypeNs::BuiltinType(it) => it.into(),
|
||||
TypeNs::TypeAlias(it) => it.into(),
|
||||
TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()),
|
||||
TypeNs::BuiltinType(it) => {
|
||||
Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into())
|
||||
}
|
||||
TypeNs::TypeAlias(it) => {
|
||||
Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into())
|
||||
}
|
||||
// FIXME: report error
|
||||
TypeNs::EnumVariant(_) => return Ty::Unknown,
|
||||
};
|
||||
|
||||
Ty::from_type_relative_path(db, resolver, ty, remaining_segments)
|
||||
}
|
||||
|
||||
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
|
||||
// Resolve the path (in type namespace)
|
||||
if let crate::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);
|
||||
}
|
||||
let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, 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],
|
||||
),
|
||||
Some(i) => (&path.segments[i - 1], &path.segments[i..]),
|
||||
};
|
||||
Ty::from_partly_resolved_hir_path(
|
||||
db,
|
||||
resolver,
|
||||
resolution,
|
||||
resolved_segment,
|
||||
remaining_segments,
|
||||
)
|
||||
}
|
||||
|
||||
fn select_associated_type(
|
||||
_db: &impl HirDatabase,
|
||||
_resolver: &Resolver,
|
||||
_self_ty: Ty,
|
||||
_segment: &PathSegment,
|
||||
) -> Ty {
|
||||
Ty::Unknown
|
||||
}
|
||||
|
||||
fn from_hir_path_inner(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
segment: &PathSegment,
|
||||
typable: TypableDef,
|
||||
) -> Ty {
|
||||
let ty = db.type_for_def(typable, Namespace::Types);
|
||||
let substs = Ty::substs_from_path(db, resolver, path, typable);
|
||||
let substs = Ty::substs_from_path_segment(db, resolver, segment, typable);
|
||||
ty.subst(&substs)
|
||||
}
|
||||
|
||||
|
@ -11,13 +11,12 @@
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
generics::HasGenericParams,
|
||||
impl_block::{ImplBlock, ImplId, ImplItem},
|
||||
impl_block::{ImplBlock, ImplId},
|
||||
nameres::CrateModuleId,
|
||||
resolve::Resolver,
|
||||
traits::TraitItem,
|
||||
ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy},
|
||||
ty::{Ty, TypeCtor},
|
||||
Crate, Function, Module, Name, Trait,
|
||||
AssocItem, Crate, Function, Module, Name, Trait,
|
||||
};
|
||||
|
||||
/// This is used as a key for indexing impls.
|
||||
@ -232,7 +231,7 @@ fn iterate_trait_method_candidates<T>(
|
||||
// iteration
|
||||
let mut known_implemented = inherently_implemented;
|
||||
for item in data.items() {
|
||||
if let TraitItem::Function(m) = *item {
|
||||
if let AssocItem::Function(m) = *item {
|
||||
let data = m.data(db);
|
||||
if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
|
||||
if !known_implemented {
|
||||
@ -264,7 +263,7 @@ fn iterate_inherent_methods<T>(
|
||||
|
||||
for impl_block in impls.lookup_impl_blocks(&ty.value) {
|
||||
for item in impl_block.items(db) {
|
||||
if let ImplItem::Method(f) = item {
|
||||
if let AssocItem::Function(f) = item {
|
||||
let data = f.data(db);
|
||||
if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
|
||||
if let Some(result) = callback(&ty.value, f) {
|
||||
@ -304,7 +303,7 @@ pub fn iterate_impl_items<T>(
|
||||
self,
|
||||
db: &impl HirDatabase,
|
||||
krate: Crate,
|
||||
mut callback: impl FnMut(ImplItem) -> Option<T>,
|
||||
mut callback: impl FnMut(AssocItem) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
for krate in def_crates(db, krate, &self)? {
|
||||
let impls = db.impls_in_crate(krate);
|
||||
|
@ -2613,18 +2613,18 @@ fn infer_call_trait_method_on_generic_param_1() {
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
trait Trait {
|
||||
fn method() -> u32;
|
||||
fn method(&self) -> u32;
|
||||
}
|
||||
fn test<T: Trait>(t: T) {
|
||||
t.method();
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
|
||||
[59; 60) 't': T
|
||||
[65; 84) '{ ...d(); }': ()
|
||||
[71; 72) 't': T
|
||||
[71; 81) 't.method()': {unknown}
|
||||
[30; 34) 'self': &Self
|
||||
[64; 65) 't': T
|
||||
[70; 89) '{ ...d(); }': ()
|
||||
[76; 77) 't': T
|
||||
[76; 86) 't.method()': u32
|
||||
"###
|
||||
);
|
||||
}
|
||||
@ -2634,18 +2634,18 @@ fn infer_call_trait_method_on_generic_param_2() {
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
trait Trait<T> {
|
||||
fn method() -> T;
|
||||
fn method(&self) -> T;
|
||||
}
|
||||
fn test<U, T: Trait<U>>(t: T) {
|
||||
t.method();
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
|
||||
[66; 67) 't': T
|
||||
[72; 91) '{ ...d(); }': ()
|
||||
[78; 79) 't': T
|
||||
[78; 88) 't.method()': {unknown}
|
||||
[33; 37) 'self': &Self
|
||||
[71; 72) 't': T
|
||||
[77; 96) '{ ...d(); }': ()
|
||||
[83; 84) 't': T
|
||||
[83; 93) 't.method()': [missing name]
|
||||
"###
|
||||
);
|
||||
}
|
||||
@ -2685,6 +2685,7 @@ fn test() {
|
||||
|
||||
#[test]
|
||||
fn infer_project_associated_type() {
|
||||
// y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
trait Iterable {
|
||||
@ -2696,16 +2697,19 @@ fn test<T: Iterable>() {
|
||||
let x: <S as Iterable>::Item = 1;
|
||||
let y: <T as Iterable>::Item = no_matter;
|
||||
let z: T::Item = no_matter;
|
||||
let a: <T>::Item = no_matter;
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[108; 227) '{ ...ter; }': ()
|
||||
[108; 261) '{ ...ter; }': ()
|
||||
[118; 119) 'x': u32
|
||||
[145; 146) '1': u32
|
||||
[156; 157) 'y': {unknown}
|
||||
[183; 192) 'no_matter': {unknown}
|
||||
[202; 203) 'z': {unknown}
|
||||
[215; 224) 'no_matter': {unknown}
|
||||
[234; 235) 'a': {unknown}
|
||||
[249; 258) 'no_matter': {unknown}
|
||||
"###
|
||||
);
|
||||
}
|
||||
@ -2721,9 +2725,11 @@ trait Iterable {
|
||||
impl Iterable for S { type Item = u32; }
|
||||
fn foo1<T: Iterable>(t: T) -> T::Item {}
|
||||
fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
|
||||
fn foo3<T: Iterable>(t: T) -> <T>::Item {}
|
||||
fn test() {
|
||||
let x = foo1(S);
|
||||
let y = foo2(S);
|
||||
let z = foo3(S);
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
@ -2731,15 +2737,21 @@ fn test() {
|
||||
[123; 125) '{}': ()
|
||||
[147; 148) 't': T
|
||||
[178; 180) '{}': ()
|
||||
[191; 236) '{ ...(S); }': ()
|
||||
[201; 202) 'x': {unknown}
|
||||
[205; 209) 'foo1': fn foo1<S>(T) -> {unknown}
|
||||
[205; 212) 'foo1(S)': {unknown}
|
||||
[210; 211) 'S': S
|
||||
[222; 223) 'y': u32
|
||||
[226; 230) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
|
||||
[226; 233) 'foo2(S)': u32
|
||||
[231; 232) 'S': S
|
||||
[202; 203) 't': T
|
||||
[221; 223) '{}': ()
|
||||
[234; 300) '{ ...(S); }': ()
|
||||
[244; 245) 'x': {unknown}
|
||||
[248; 252) 'foo1': fn foo1<S>(T) -> {unknown}
|
||||
[248; 255) 'foo1(S)': {unknown}
|
||||
[253; 254) 'S': S
|
||||
[265; 266) 'y': u32
|
||||
[269; 273) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
|
||||
[269; 276) 'foo2(S)': u32
|
||||
[274; 275) 'S': S
|
||||
[286; 287) 'z': {unknown}
|
||||
[290; 294) 'foo3': fn foo3<S>(T) -> {unknown}
|
||||
[290; 297) 'foo3(S)': {unknown}
|
||||
[295; 296) 'S': S
|
||||
"###
|
||||
);
|
||||
}
|
||||
@ -4050,6 +4062,48 @@ fn test<F: FnOnce(u32) -> u64>(f: F) {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unselected_projection_in_trait_env() {
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
trait Trait {
|
||||
type Item;
|
||||
}
|
||||
|
||||
trait Trait2 {
|
||||
fn foo(&self) -> u32;
|
||||
}
|
||||
|
||||
fn test<T: Trait>() where T::Item: Trait2 {
|
||||
let x: T::Item = no_matter;
|
||||
x.foo()<|>;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_eq!(t, "u32");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unselected_projection_in_trait_env_cycle() {
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
trait Trait {
|
||||
type Item;
|
||||
}
|
||||
|
||||
trait Trait2<T> {}
|
||||
|
||||
fn test<T: Trait>() where T: Trait2<T::Item> {
|
||||
let x: T::Item = no_matter<|>;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
// this is a legitimate cycle
|
||||
assert_eq!(t, "{unknown}");
|
||||
}
|
||||
|
||||
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
||||
let file = db.parse(pos.file_id).ok().unwrap();
|
||||
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
||||
|
@ -21,7 +21,7 @@
|
||||
ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
|
||||
TypeWalk,
|
||||
},
|
||||
Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias,
|
||||
AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias,
|
||||
};
|
||||
|
||||
/// This represents a trait whose name we could not resolve.
|
||||
@ -496,7 +496,7 @@ pub(crate) fn trait_datum_query(
|
||||
.items(db)
|
||||
.into_iter()
|
||||
.filter_map(|trait_item| match trait_item {
|
||||
crate::traits::TraitItem::TypeAlias(type_alias) => Some(type_alias),
|
||||
crate::AssocItem::TypeAlias(type_alias) => Some(type_alias),
|
||||
_ => None,
|
||||
})
|
||||
.map(|type_alias| type_alias.to_chalk(db))
|
||||
@ -616,7 +616,7 @@ pub(crate) fn impl_datum_query(
|
||||
.items(db)
|
||||
.into_iter()
|
||||
.filter_map(|item| match item {
|
||||
ImplItem::TypeAlias(t) => Some(t),
|
||||
AssocItem::TypeAlias(t) => Some(t),
|
||||
_ => None,
|
||||
})
|
||||
.filter_map(|t| {
|
||||
|
@ -52,14 +52,14 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
if let Some(krate) = krate {
|
||||
ty.iterate_impl_items(ctx.db, krate, |item| {
|
||||
match item {
|
||||
hir::ImplItem::Method(func) => {
|
||||
hir::AssocItem::Function(func) => {
|
||||
let data = func.data(ctx.db);
|
||||
if !data.has_self_param() {
|
||||
acc.add_function(ctx, func);
|
||||
}
|
||||
}
|
||||
hir::ImplItem::Const(ct) => acc.add_const(ctx, ct),
|
||||
hir::ImplItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
||||
hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
|
||||
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
||||
}
|
||||
None::<()>
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
use hir::{FieldSource, HasSource, ImplItem, ModuleSource};
|
||||
use hir::{AssocItem, FieldSource, HasSource, ModuleSource};
|
||||
use ra_db::{FileId, SourceDatabase};
|
||||
use ra_syntax::{
|
||||
algo::visit::{visitor, Visitor},
|
||||
@ -221,11 +221,14 @@ pub(crate) fn from_impl_block(
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn from_impl_item(db: &RootDatabase, impl_item: hir::ImplItem) -> NavigationTarget {
|
||||
match impl_item {
|
||||
ImplItem::Method(it) => NavigationTarget::from_def_source(db, it),
|
||||
ImplItem::Const(it) => NavigationTarget::from_def_source(db, it),
|
||||
ImplItem::TypeAlias(it) => NavigationTarget::from_def_source(db, it),
|
||||
pub(crate) fn from_assoc_item(
|
||||
db: &RootDatabase,
|
||||
assoc_item: hir::AssocItem,
|
||||
) -> NavigationTarget {
|
||||
match assoc_item {
|
||||
AssocItem::Function(it) => NavigationTarget::from_def_source(db, it),
|
||||
AssocItem::Const(it) => NavigationTarget::from_def_source(db, it),
|
||||
AssocItem::TypeAlias(it) => NavigationTarget::from_def_source(db, it),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ pub(crate) fn reference_definition(
|
||||
match classify_name_ref(db, &analyzer, name_ref) {
|
||||
Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)),
|
||||
Some(FieldAccess(field)) => return Exact(NavigationTarget::from_field(db, field)),
|
||||
Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_impl_item(db, assoc)),
|
||||
Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)),
|
||||
Some(Method(func)) => return Exact(NavigationTarget::from_def_source(db, func)),
|
||||
Some(Def(def)) => match NavigationTarget::from_def(db, def) {
|
||||
Some(nav) => return Exact(nav),
|
||||
|
@ -117,9 +117,9 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
|
||||
}
|
||||
}
|
||||
Some(AssocItem(it)) => res.extend(match it {
|
||||
hir::ImplItem::Method(it) => from_def_source(db, it),
|
||||
hir::ImplItem::Const(it) => from_def_source(db, it),
|
||||
hir::ImplItem::TypeAlias(it) => from_def_source(db, it),
|
||||
hir::AssocItem::Function(it) => from_def_source(db, it),
|
||||
hir::AssocItem::Const(it) => from_def_source(db, it),
|
||||
hir::AssocItem::TypeAlias(it) => from_def_source(db, it),
|
||||
}),
|
||||
Some(Def(it)) => {
|
||||
match it {
|
||||
|
@ -8,7 +8,7 @@ pub enum NameRefKind {
|
||||
Method(hir::Function),
|
||||
Macro(hir::MacroDef),
|
||||
FieldAccess(hir::StructField),
|
||||
AssocItem(hir::ImplItem),
|
||||
AssocItem(hir::AssocItem),
|
||||
Def(hir::ModuleDef),
|
||||
SelfType(hir::Ty),
|
||||
Pat(AstPtr<ast::BindPat>),
|
||||
|
@ -102,9 +102,9 @@ fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
|
||||
Some(Method(_)) => "function",
|
||||
Some(Macro(_)) => "macro",
|
||||
Some(FieldAccess(_)) => "field",
|
||||
Some(AssocItem(hir::ImplItem::Method(_))) => "function",
|
||||
Some(AssocItem(hir::ImplItem::Const(_))) => "constant",
|
||||
Some(AssocItem(hir::ImplItem::TypeAlias(_))) => "type",
|
||||
Some(AssocItem(hir::AssocItem::Function(_))) => "function",
|
||||
Some(AssocItem(hir::AssocItem::Const(_))) => "constant",
|
||||
Some(AssocItem(hir::AssocItem::TypeAlias(_))) => "type",
|
||||
Some(Def(hir::ModuleDef::Module(_))) => "module",
|
||||
Some(Def(hir::ModuleDef::Function(_))) => "function",
|
||||
Some(Def(hir::ModuleDef::Adt(_))) => "type",
|
||||
|
Loading…
Reference in New Issue
Block a user