From 16ee779483a1d96ccd2258b43c8477744773b314 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 14 Sep 2019 12:28:35 +0200 Subject: Adapt some tests --- crates/ra_hir/src/ty/tests.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 1bd677cab..b5d3c0180 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -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: 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 { - fn method() -> T; + fn method(&self) -> T; } fn test>(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] "### ); } -- cgit v1.2.3 From 913ab1ec0ad10873134ca429c1496806a9261206 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 14 Sep 2019 13:25:05 +0200 Subject: Resolve assoc types on type parameters E.g. `fn foo() -> T::Item`. It seems that rustc does this only for type parameters and only based on their bounds, so we also only consider traits from bounds. --- crates/ra_hir/src/ty/lower.rs | 79 +++++++++++++++++++++++++++++++------------ crates/ra_hir/src/ty/tests.rs | 6 ++-- 2 files changed, 61 insertions(+), 24 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 6ead3846a..62e4ed0f4 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -93,7 +93,7 @@ impl Ty { None => return Ty::Unknown, }; - let typable: TypableDef = match resolution { + let ty = match resolution { TypeNs::Trait(trait_) => { let segment = match remaining_index { None => path.segments.last().expect("resolved path has at least one element"), @@ -115,12 +115,12 @@ impl Ty { }) } None => { - // associated type not found + // associated type not found (FIXME: report error) Ty::Unknown } } } else { - // FIXME more than one segment remaining, is this possible? + // FIXME report error (ambiguous associated type) Ty::Unknown } } else { @@ -128,34 +128,71 @@ impl Ty { }; } 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 + // FIXME: maybe return name in resolution? + let name = match remaining_index { + None => path .as_ident() .expect("generic param should be single-segment path") .clone(), + Some(idx) => path.segments[idx - 1].name.clone(), }; + Ty::Param { idx, name } } - TypeNs::SelfType(impl_block) => { - if remaining_index.is_some() { - // e.g. Self::Item - return Ty::Unknown; - } - return impl_block.target_ty(db); - } + 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, path, it.into()), + TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), + TypeNs::TypeAlias(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), // FIXME: report error TypeNs::EnumVariant(_) => return Ty::Unknown, }; + if let Some(remaining_index) = remaining_index { + // resolve unselected assoc types + if remaining_index == path.segments.len() - 1 { + let segment = &path.segments[remaining_index]; + Ty::select_associated_type(db, resolver, ty, segment) + } else { + // FIXME report error (ambiguous associated type) + Ty::Unknown + } + } else { + ty + } + } + + fn select_associated_type( + db: &impl HirDatabase, + resolver: &Resolver, + self_ty: Ty, + segment: &PathSegment, + ) -> Ty { + let env = trait_env(db, resolver); + let traits_from_env = env.trait_predicates_for_self_ty(&self_ty).map(|tr| tr.trait_); + let traits = traits_from_env.flat_map(|t| t.all_super_traits(db)); + let mut result = Ty::Unknown; + for t in traits { + if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) { + let generics = t.generic_params(db); + let mut substs = Vec::new(); + substs.push(self_ty.clone()); + substs.extend( + iter::repeat(Ty::Unknown).take(generics.count_params_including_parent() - 1), + ); + // FIXME handle type parameters on the segment + result = Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() }); + break; + } + } + result + } + + fn from_hir_path_inner( + db: &impl HirDatabase, + resolver: &Resolver, + path: &Path, + typable: TypableDef, + ) -> Ty { let ty = db.type_for_def(typable, Namespace::Types); let substs = Ty::substs_from_path(db, resolver, path, typable); ty.subst(&substs) diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index b5d3c0180..dc4e8683d 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -2732,9 +2732,9 @@ fn test() { [147; 148) 't': T [178; 180) '{}': () [191; 236) '{ ...(S); }': () - [201; 202) 'x': {unknown} - [205; 209) 'foo1': fn foo1(T) -> {unknown} - [205; 212) 'foo1(S)': {unknown} + [201; 202) 'x': u32 + [205; 209) 'foo1': fn foo1(T) -> ::Item + [205; 212) 'foo1(S)': u32 [210; 211) 'S': S [222; 223) 'y': u32 [226; 230) 'foo2': fn foo2(T) -> ::Item -- cgit v1.2.3 From 828d60574f8ecbc33fe4987913c6f713e41af1ae Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 14 Sep 2019 16:26:03 +0200 Subject: Refactor a bit to prepare for resolving trait assoc items --- crates/ra_hir/src/code_model.rs | 31 ++++++++++++ crates/ra_hir/src/lib.rs | 6 +-- crates/ra_hir/src/resolve.rs | 8 +-- crates/ra_hir/src/source_binder.rs | 2 +- crates/ra_hir/src/ty/infer.rs | 57 ++++++++++------------ crates/ra_ide_api/src/display/navigation_target.rs | 15 +++--- crates/ra_ide_api/src/goto_definition.rs | 2 +- crates/ra_ide_api/src/hover.rs | 6 +-- crates/ra_ide_api/src/name_ref_kind.rs | 2 +- crates/ra_ide_api/src/syntax_highlighting.rs | 6 +-- 10 files changed, 83 insertions(+), 52 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 84e15385c..892208c1a 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -749,6 +749,10 @@ impl Const { db.const_data(self) } + pub fn name(&self, db: &impl HirDatabase) -> Option { + self.data(db).name().cloned() + } + pub fn infer(self, db: &impl HirDatabase) -> Arc { db.infer(self.into()) } @@ -1019,3 +1023,30 @@ impl Container { } } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum AssocItem { + Function(Function), + Const(Const), + TypeAlias(TypeAlias), +} + +impl From for AssocItem { + fn from(t: TraitItem) -> Self { + match t { + TraitItem::Function(f) => AssocItem::Function(f), + TraitItem::Const(c) => AssocItem::Const(c), + TraitItem::TypeAlias(t) => AssocItem::TypeAlias(t), + } + } +} + +impl From for AssocItem { + fn from(i: crate::ImplItem) -> Self { + match i { + crate::ImplItem::Method(f) => AssocItem::Function(f), + crate::ImplItem::Const(c) => AssocItem::Const(c), + crate::ImplItem::TypeAlias(t) => AssocItem::TypeAlias(t), + } + } +} diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 80cf8d9c0..db82a463c 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -85,7 +85,7 @@ pub use self::{ 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, }; diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index bb6915901..7f4c78859 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -50,7 +50,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 +59,19 @@ 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)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ResolveValueResult<'a> { ValueNs(ValueNs), Partial(TypeNs, usize), TypeRef(&'a TypeRef), } -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ValueNs { LocalBinding(PatId), Function(Function), diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 2a907c9f1..4d895f0a1 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -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)] diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index bf9609d8c..6aaf61c0e 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -48,7 +48,7 @@ use crate::{ resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, ty::infer::diagnostics::InferenceDiagnostic, type_ref::{Mutability, TypeRef}, - Adt, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path, + Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path, StructField, }; @@ -121,7 +121,7 @@ pub struct InferenceResult { /// For each struct literal, records the variant it resolves to. variant_resolutions: FxHashMap, /// For each associated item record what it resolves to - assoc_resolutions: FxHashMap, + assoc_resolutions: FxHashMap, diagnostics: Vec, pub(super) type_of_expr: ArenaMap, pub(super) type_of_pat: ArenaMap, @@ -141,10 +141,10 @@ impl InferenceResult { pub fn variant_resolution_for_pat(&self, id: PatId) -> Option { self.variant_resolutions.get(&id.into()).copied() } - pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option { + pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option { self.assoc_resolutions.get(&id.into()).copied() } - pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option { + pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option { self.assoc_resolutions.get(&id.into()).copied() } pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { @@ -235,7 +235,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { 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); } @@ -560,8 +560,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { 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, + crate::ImplItem::Method(_) | crate::ImplItem::Const(_) => None, // FIXME: Resolve associated types crate::ImplItem::TypeAlias(_) => { @@ -573,34 +572,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } let segment = path.segments.last().unwrap(); - let def = ty.clone().iterate_impl_items(self.db, krate, |item| { - let matching_def: Option = match item { - crate::ImplItem::Method(func) => { - if segment.name == func.name(self.db) { - Some(ValueNs::Function(func)) - } else { - None - } + let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { + crate::ImplItem::Method(func) => { + if segment.name == func.name(self.db) { + Some(ValueNs::Function(func)) + } else { + None } + } - crate::ImplItem::Const(konst) => { - let data = konst.data(self.db); - if Some(&segment.name) == data.name() { - Some(ValueNs::Const(konst)) - } else { - None - } - } - crate::ImplItem::TypeAlias(_) => None, - }; - match matching_def { - Some(_) => { - self.write_assoc_resolution(id, item); - matching_def + crate::ImplItem::Const(konst) => { + if konst.name(self.db).map_or(false, |n| n == segment.name) { + Some(ValueNs::Const(konst)) + } else { + None } - None => None, } + crate::ImplItem::TypeAlias(_) => None, })?; + self.write_assoc_resolution( + id, + match def { + ValueNs::Function(f) => AssocItem::Function(f), + ValueNs::Const(c) => AssocItem::Const(c), + _ => unreachable!(), + }, + ); let self_types = self.find_self_types(&def, ty); Some((def, self_types)) } diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index 03382ab3c..11f73ccfd 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs @@ -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 @@ impl NavigationTarget { ) } - 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), } } diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 28529a2de..503dcacff 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -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), diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 28a6bef12..655bcdb16 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -117,9 +117,9 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option 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 { diff --git a/crates/ra_ide_api/src/name_ref_kind.rs b/crates/ra_ide_api/src/name_ref_kind.rs index 6c2a7b260..aff03464a 100644 --- a/crates/ra_ide_api/src/name_ref_kind.rs +++ b/crates/ra_ide_api/src/name_ref_kind.rs @@ -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), diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 86ab3a260..3d7f91c1d 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -102,9 +102,9 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec "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", -- cgit v1.2.3 From 406280e52f20e25af609d947efbed8b352ca1249 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 15 Sep 2019 12:50:57 +0200 Subject: Refactor associated item resolution more When resolving an associated item in value namespace, use the `Ty` lowering code for the segments before the last instead of replicating it. --- crates/ra_hir/src/ty/infer.rs | 125 ++++++++++++++++++------------------------ crates/ra_hir/src/ty/lower.rs | 119 ++++++++++++++++++++++------------------ 2 files changed, 120 insertions(+), 124 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 6aaf61c0e..f33479dc4 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -48,7 +48,7 @@ use crate::{ resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, ty::infer::diagnostics::InferenceDiagnostic, type_ref::{Mutability, TypeRef}, - Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path, + Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, Name, Path, StructField, }; @@ -508,7 +508,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_assoc_item( &mut self, - mut def_or_ty: Either, + // mut def_or_ty: Either, + def: TypeNs, path: &Path, remaining_index: usize, id: ExprOrPatId, @@ -516,80 +517,63 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { assert!(remaining_index < path.segments.len()); let krate = self.resolver.krate()?; - let mut ty = Ty::Unknown; - - // 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::**::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; - } + // 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. - // 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 resolved_segment = &path.segments[remaining_index - 1]; + let remaining_segments = &path.segments[remaining_index..]; + let is_before_last = remaining_segments.len() == 1; - let ty = mem::replace(&mut ty, Ty::Unknown); - def_or_ty = ty.iterate_impl_items(self.db, krate, |item| { - match item { - crate::ImplItem::Method(_) | crate::ImplItem::Const(_) => None, + let (def, substs) = match (def, is_before_last) { + (TypeNs::Trait(_trait), true) => { + // Associated item of trait, e.g. `Default::default` + // FIXME + return 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. `::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; + } - // FIXME: Resolve associated types - crate::ImplItem::TypeAlias(_) => { - // Some(Either::A(TypeNs::TypeAlias(..))) - None + let segment = + remaining_segments.last().expect("there should be at least one segment here"); + // Find impl + let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { + crate::ImplItem::Method(func) => { + if segment.name == func.name(self.db) { + Some(ValueNs::Function(func)) + } else { + None + } } - } - })?; - } - let segment = path.segments.last().unwrap(); - let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { - crate::ImplItem::Method(func) => { - if segment.name == func.name(self.db) { - Some(ValueNs::Function(func)) - } else { - None - } + crate::ImplItem::Const(konst) => { + if segment.name == konst.name(self.db) { + Some(ValueNs::Const(konst)) + } else { + None + } + } + crate::ImplItem::TypeAlias(_) => None, + })?; + let self_types = self.find_self_types(&def, ty); + (def, self_types) } + }; - crate::ImplItem::Const(konst) => { - if konst.name(self.db).map_or(false, |n| n == segment.name) { - Some(ValueNs::Const(konst)) - } else { - None - } - } - crate::ImplItem::TypeAlias(_) => None, - })?; self.write_assoc_resolution( id, match def { @@ -598,8 +582,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { _ => unreachable!(), }, ); - let self_types = self.find_self_types(&def, ty); - Some((def, self_types)) + Some((def, substs)) } fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option { diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 62e4ed0f4..e29b68f1a 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -86,81 +86,94 @@ impl 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_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 (FIXME: report error) - 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 => { + // associated type not found (FIXME: report error) + Ty::Unknown } - } else { - // FIXME report error (ambiguous associated type) - 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) => { // FIXME: maybe return name in resolution? - let name = match remaining_index { - None => path - .as_ident() - .expect("generic param should be single-segment path") - .clone(), - Some(idx) => path.segments[idx - 1].name.clone(), - }; + let name = resolved_segment.name.clone(); Ty::Param { idx, name } } TypeNs::SelfType(impl_block) => impl_block.target_ty(db), - TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), - TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), - TypeNs::TypeAlias(it) => Ty::from_hir_path_inner(db, resolver, path, 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, }; - if let Some(remaining_index) = remaining_index { + if remaining_segments.len() == 1 { // resolve unselected assoc types - if remaining_index == path.segments.len() - 1 { - let segment = &path.segments[remaining_index]; - Ty::select_associated_type(db, resolver, ty, segment) - } else { - // FIXME report error (ambiguous associated type) - Ty::Unknown - } + 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 } } + 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, + }; + 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, @@ -190,11 +203,11 @@ impl Ty { fn from_hir_path_inner( db: &impl HirDatabase, resolver: &Resolver, - path: &Path, + 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) } -- cgit v1.2.3 From fe1dfd2b20b256b99f40f6f6421f7c7e12c23e41 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 16 Sep 2019 21:38:27 +0200 Subject: Refactor some more Type-relative paths (`::foo`) also need to work in type context, for example `::Item` is legal. So rather than returning the type ref from the resolver function, just check it before. --- crates/ra_hir/src/path.rs | 7 +++ crates/ra_hir/src/resolve.rs | 16 +++---- crates/ra_hir/src/ty/infer.rs | 100 ++++++++++++++++++++++++++---------------- crates/ra_hir/src/ty/lower.rs | 34 +++++++++----- 4 files changed, 100 insertions(+), 57 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index a61161b63..39d1b7e46 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -190,6 +190,13 @@ impl Path { pub fn expand_macro_expr(&self) -> Option { 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 { diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 7f4c78859..a23c8792a 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -15,7 +15,6 @@ use crate::{ 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, }; @@ -65,10 +64,9 @@ pub enum TypeNs { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ResolveValueResult<'a> { +pub enum ResolveValueResult { ValueNs(ValueNs), Partial(TypeNs, usize), - TypeRef(&'a TypeRef), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -131,6 +129,9 @@ impl Resolver { db: &impl HirDatabase, path: &Path, ) -> Option<(TypeNs, Option)> { + 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 @@ impl Resolver { &self, db: &impl HirDatabase, path: &'p Path, - ) -> Option> { - if let PathKind::Type(type_ref) = &path.kind { - return Some(ResolveValueResult::TypeRef(type_ref)); + ) -> Option { + 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 @@ impl Resolver { ) -> Option { match self.resolve_path_in_value_ns(db, path)? { ResolveValueResult::ValueNs(it) => Some(it), - ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None, + ResolveValueResult::Partial(..) => None, } } diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index f33479dc4..181be0fcc 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -48,8 +48,7 @@ use crate::{ resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, ty::infer::diagnostics::InferenceDiagnostic, type_ref::{Mutability, TypeRef}, - Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, Name, Path, - StructField, + Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField, }; mod unify; @@ -468,16 +467,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option { - 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,15 +518,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_assoc_item( &mut self, - // mut def_or_ty: Either, def: TypeNs, path: &Path, remaining_index: usize, id: ExprOrPatId, ) -> Option<(ValueNs, Option)> { 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. @@ -525,11 +532,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let remaining_segments = &path.segments[remaining_index..]; let is_before_last = remaining_segments.len() == 1; - let (def, substs) = match (def, is_before_last) { + match (def, is_before_last) { (TypeNs::Trait(_trait), true) => { - // Associated item of trait, e.g. `Default::default` - // FIXME - return None; + // FIXME Associated item of trait, e.g. `Default::default` + None } (def, _) => { // Either we already have a type (e.g. `Vec::new`), or we have a @@ -550,29 +556,45 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let segment = remaining_segments.last().expect("there should be at least one segment here"); - // Find impl - let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { - crate::ImplItem::Method(func) => { - if segment.name == func.name(self.db) { - Some(ValueNs::Function(func)) - } else { - None - } - } - crate::ImplItem::Const(konst) => { - if segment.name == konst.name(self.db) { - Some(ValueNs::Const(konst)) - } else { - None - } - } - crate::ImplItem::TypeAlias(_) => None, - })?; - let self_types = self.find_self_types(&def, ty); - (def, self_types) + 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)> { + if let Ty::Unknown = ty { + return None; + } + + let krate = self.resolver.krate()?; + + // Find impl + // FIXME: consider trait candidates + let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { + crate::ImplItem::Method(func) => { + if segment.name == func.name(self.db) { + Some(ValueNs::Function(func)) + } else { + None + } + } + + crate::ImplItem::Const(konst) => { + if konst.name(self.db).map_or(false, |n| n == segment.name) { + Some(ValueNs::Const(konst)) + } else { + None + } + } + crate::ImplItem::TypeAlias(_) => None, + })?; + let substs = self.find_self_types(&def, ty); self.write_assoc_resolution( id, diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index e29b68f1a..e6cd5d0be 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -86,6 +86,24 @@ impl Ty { } } + 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 + } + } + pub(crate) fn from_partly_resolved_hir_path( db: &impl HirDatabase, resolver: &Resolver, @@ -140,20 +158,16 @@ impl Ty { TypeNs::EnumVariant(_) => return Ty::Unknown, }; - 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 - } + 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, -- cgit v1.2.3 From 35d1c038967b9d69f2e501e24fec8351f3948779 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 16 Sep 2019 21:46:51 +0200 Subject: Add test for `::Item` --- crates/ra_hir/src/ty/tests.rs | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index dc4e8683d..fdcb3c37f 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -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() { let x: ::Item = 1; let y: ::Item = no_matter; let z: T::Item = no_matter; + let a: ::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 @@ struct S; impl Iterable for S { type Item = u32; } fn foo1(t: T) -> T::Item {} fn foo2(t: T) -> ::Item {} +fn foo3(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': u32 - [205; 209) 'foo1': fn foo1(T) -> ::Item - [205; 212) 'foo1(S)': u32 - [210; 211) 'S': S - [222; 223) 'y': u32 - [226; 230) 'foo2': fn foo2(T) -> ::Item - [226; 233) 'foo2(S)': u32 - [231; 232) 'S': S + [202; 203) 't': T + [221; 223) '{}': () + [234; 300) '{ ...(S); }': () + [244; 245) 'x': u32 + [248; 252) 'foo1': fn foo1(T) -> ::Item + [248; 255) 'foo1(S)': u32 + [253; 254) 'S': S + [265; 266) 'y': u32 + [269; 273) 'foo2': fn foo2(T) -> ::Item + [269; 276) 'foo2(S)': u32 + [274; 275) 'S': S + [286; 287) 'z': u32 + [290; 294) 'foo3': fn foo3(T) -> ::Item + [290; 297) 'foo3(S)': u32 + [295; 296) 'S': S "### ); } -- cgit v1.2.3 From 53a932509dbb9dfdaabb27a0d7fc3fe87e44ec55 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 16 Sep 2019 21:48:46 +0200 Subject: Small review improvements --- crates/ra_hir/src/ty/lower.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index e6cd5d0be..35fdd4a37 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -129,7 +129,7 @@ impl Ty { }) } None => { - // associated type not found (FIXME: report error) + // FIXME: report error (associated type not found) Ty::Unknown } } @@ -197,7 +197,6 @@ impl Ty { let env = trait_env(db, resolver); let traits_from_env = env.trait_predicates_for_self_ty(&self_ty).map(|tr| tr.trait_); let traits = traits_from_env.flat_map(|t| t.all_super_traits(db)); - let mut result = Ty::Unknown; for t in traits { if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) { let generics = t.generic_params(db); @@ -207,11 +206,10 @@ impl Ty { iter::repeat(Ty::Unknown).take(generics.count_params_including_parent() - 1), ); // FIXME handle type parameters on the segment - result = Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() }); - break; + return Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() }); } } - result + Ty::Unknown } fn from_hir_path_inner( -- cgit v1.2.3 From a040fde3ae5e339199237f24a7461812e74475bf Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 16 Sep 2019 22:01:13 +0200 Subject: Remove TraitItem and ImplItem in favor of AssocItem --- crates/ra_cli/src/analysis_stats.rs | 4 +-- crates/ra_hir/src/code_model.rs | 33 +++++++---------------- crates/ra_hir/src/impl_block.rs | 28 +++++-------------- crates/ra_hir/src/lib.rs | 2 +- crates/ra_hir/src/traits.rs | 23 ++++------------ crates/ra_hir/src/ty/infer.rs | 26 +++++++++--------- crates/ra_hir/src/ty/method_resolution.rs | 11 ++++---- crates/ra_hir/src/ty/traits/chalk.rs | 6 ++--- crates/ra_ide_api/src/completion/complete_path.rs | 6 ++--- 9 files changed, 46 insertions(+), 93 deletions(-) (limited to 'crates') diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs index 8f4ce42da..6b1e44a2c 100644 --- a/crates/ra_cli/src/analysis_stats.rs +++ b/crates/ra_cli/src/analysis_stats.rs @@ -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); } } diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 892208c1a..706d24c32 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -23,7 +23,7 @@ use crate::{ }, 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 @@ impl Module { 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); } } @@ -853,7 +853,7 @@ impl Trait { self.trait_data(db).name().clone() } - pub fn items(self, db: &impl DefDatabase) -> Vec { + pub fn items(self, db: &impl DefDatabase) -> Vec { self.trait_data(db).items().to_vec() } @@ -906,7 +906,7 @@ impl Trait { .items() .iter() .filter_map(|item| match item { - TraitItem::TypeAlias(t) => Some(*t), + AssocItem::TypeAlias(t) => Some(*t), _ => None, }) .find(|t| &t.name(db) == name) @@ -1030,23 +1030,8 @@ pub enum AssocItem { Const(Const), TypeAlias(TypeAlias), } - -impl From for AssocItem { - fn from(t: TraitItem) -> Self { - match t { - TraitItem::Function(f) => AssocItem::Function(f), - TraitItem::Const(c) => AssocItem::Const(c), - TraitItem::TypeAlias(t) => AssocItem::TypeAlias(t), - } - } -} - -impl From for AssocItem { - fn from(i: crate::ImplItem) -> Self { - match i { - crate::ImplItem::Method(f) => AssocItem::Function(f), - crate::ImplItem::Const(c) => AssocItem::Const(c), - crate::ImplItem::TypeAlias(t) => AssocItem::TypeAlias(t), - } - } -} +// 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); diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index d26a024ed..c463d351c 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -15,7 +15,7 @@ use crate::{ 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 @@ impl HasSource for ImplBlock { impl ImplBlock { pub(crate) fn containing( module_impl_blocks: Arc, - item: ImplItem, + item: AssocItem, ) -> Option { let impl_id = *module_impl_blocks.impls_by_def.get(&item)?; Some(ImplBlock { module: module_impl_blocks.module, impl_id }) @@ -91,7 +91,7 @@ impl ImplBlock { TraitRef::from_hir(db, &self.resolver(db), &self.target_trait(db)?, Some(target_ty)) } - pub fn items(&self, db: &impl DefDatabase) -> Vec { + pub fn items(&self, db: &impl DefDatabase) -> Vec { db.impls_in_module(self.module).impls[self.impl_id].items().to_vec() } @@ -113,7 +113,7 @@ impl ImplBlock { pub struct ImplData { target_trait: Option, target_type: TypeRef, - items: Vec, + items: Vec, negative: bool, } @@ -151,27 +151,11 @@ impl ImplData { &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 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 @@ impl_arena_id!(ImplId); pub struct ModuleImplBlocks { pub(crate) module: Module, pub(crate) impls: Arena, - impls_by_def: FxHashMap, + impls_by_def: FxHashMap, } impl ModuleImplBlocks { diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index db82a463c..e7a576aa0 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -69,7 +69,7 @@ pub use self::{ 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}, diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs index 4c2f7980d..e39511518 100644 --- a/crates/ra_hir/src/traits.rs +++ b/crates/ra_hir/src/traits.rs @@ -9,13 +9,13 @@ use crate::{ 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, - items: Vec, + items: Vec, auto: bool, } @@ -48,7 +48,7 @@ impl TraitData { &self.name } - pub(crate) fn items(&self) -> &[TraitItem] { + pub(crate) fn items(&self) -> &[AssocItem] { &self.items } @@ -57,22 +57,9 @@ impl TraitData { } } -#[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, + traits_by_def: FxHashMap, } impl TraitItemsIndex { @@ -88,7 +75,7 @@ impl TraitItemsIndex { index } - pub(crate) fn get_parent_trait(&self, item: TraitItem) -> Option { + pub(crate) fn get_parent_trait(&self, item: AssocItem) -> Option { self.traits_by_def.get(&item).cloned() } } diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 181be0fcc..70da7f311 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -576,34 +576,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // Find impl // FIXME: consider trait candidates - let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { - crate::ImplItem::Method(func) => { + let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item { + AssocItem::Function(func) => { if segment.name == func.name(self.db) { - Some(ValueNs::Function(func)) + Some(AssocItem::Function(func)) } else { None } } - crate::ImplItem::Const(konst) => { + AssocItem::Const(konst) => { if konst.name(self.db).map_or(false, |n| n == segment.name) { - Some(ValueNs::Const(konst)) + Some(AssocItem::Const(konst)) } else { None } } - crate::ImplItem::TypeAlias(_) => None, + AssocItem::TypeAlias(_) => None, })?; + 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, - match def { - ValueNs::Function(f) => AssocItem::Function(f), - ValueNs::Const(c) => AssocItem::Const(c), - _ => unreachable!(), - }, - ); + self.write_assoc_resolution(id, item); Some((def, substs)) } diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index be63806d4..8b46b11a9 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -11,13 +11,12 @@ use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitR 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( // 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( 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 @@ impl Ty { self, db: &impl HirDatabase, krate: Crate, - mut callback: impl FnMut(ImplItem) -> Option, + mut callback: impl FnMut(AssocItem) -> Option, ) -> Option { for krate in def_crates(db, krate, &self)? { let impls = db.impls_in_crate(krate); diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index c748e9d84..693d9b28f 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -21,7 +21,7 @@ use crate::{ 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| { diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index e1c8d6ab0..e9fec54d8 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -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::<()> }); -- cgit v1.2.3 From 69c8cfc4c17e9f4533437c757e754a140c0a9ebc Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 17 Sep 2019 23:06:05 +0200 Subject: Add test for `T::Item` cycles --- crates/ra_hir/src/ty/tests.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index fdcb3c37f..9a3faa9ab 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -4062,6 +4062,48 @@ fn test 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() 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 {} + +fn test() where T: Trait2 { + 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::(file.syntax(), pos.offset).unwrap(); -- cgit v1.2.3 From c2f9558e1af8dbf73ff86eeffcb9ea6940947dd6 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 17 Sep 2019 23:11:20 +0200 Subject: Remove assoc type selection code for now to fix crashes --- crates/ra_hir/src/ty/lower.rs | 23 ++++------------------- crates/ra_hir/src/ty/tests.rs | 12 ++++++------ 2 files changed, 10 insertions(+), 25 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 35fdd4a37..a83842b0f 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -189,26 +189,11 @@ impl Ty { } fn select_associated_type( - db: &impl HirDatabase, - resolver: &Resolver, - self_ty: Ty, - segment: &PathSegment, + _db: &impl HirDatabase, + _resolver: &Resolver, + _self_ty: Ty, + _segment: &PathSegment, ) -> Ty { - let env = trait_env(db, resolver); - let traits_from_env = env.trait_predicates_for_self_ty(&self_ty).map(|tr| tr.trait_); - let traits = traits_from_env.flat_map(|t| t.all_super_traits(db)); - for t in traits { - if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) { - let generics = t.generic_params(db); - let mut substs = Vec::new(); - substs.push(self_ty.clone()); - substs.extend( - iter::repeat(Ty::Unknown).take(generics.count_params_including_parent() - 1), - ); - // FIXME handle type parameters on the segment - return Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() }); - } - } Ty::Unknown } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 9a3faa9ab..09c17fdf4 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -2740,17 +2740,17 @@ fn test() { [202; 203) 't': T [221; 223) '{}': () [234; 300) '{ ...(S); }': () - [244; 245) 'x': u32 - [248; 252) 'foo1': fn foo1(T) -> ::Item - [248; 255) 'foo1(S)': u32 + [244; 245) 'x': {unknown} + [248; 252) 'foo1': fn foo1(T) -> {unknown} + [248; 255) 'foo1(S)': {unknown} [253; 254) 'S': S [265; 266) 'y': u32 [269; 273) 'foo2': fn foo2(T) -> ::Item [269; 276) 'foo2(S)': u32 [274; 275) 'S': S - [286; 287) 'z': u32 - [290; 294) 'foo3': fn foo3(T) -> ::Item - [290; 297) 'foo3(S)': u32 + [286; 287) 'z': {unknown} + [290; 294) 'foo3': fn foo3(T) -> {unknown} + [290; 297) 'foo3(S)': {unknown} [295; 296) 'S': S "### ); -- cgit v1.2.3