From 4926bed42680d329f906be93450bec6b2ba0e99b Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Thu, 12 Sep 2019 02:01:07 +0800 Subject: Support path starting with a type --- crates/ra_hir/src/ty/infer.rs | 120 +++++++++++++++++++----------------------- crates/ra_hir/src/ty/tests.rs | 58 ++++++++++++++++++++ 2 files changed, 113 insertions(+), 65 deletions(-) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index bf57bb3b7..3981de829 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -44,11 +44,12 @@ use crate::{ generics::{GenericParams, HasGenericParams}, name, nameres::Namespace, - path::{GenericArg, GenericArgs, PathKind, PathSegment}, - resolve::{Resolver, TypeNs, ValueNs, ValueOrPartial}, + path::{GenericArg, GenericArgs, PathKind}, + resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, ty::infer::diagnostics::InferenceDiagnostic, type_ref::{Mutability, TypeRef}, - Adt, ConstData, DefWithBody, FnData, Function, HasBody, ImplItem, Name, Path, StructField, + Adt, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path, + StructField, }; mod unify; @@ -470,9 +471,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; let (value, self_subst) = match value_or_partial { - ValueOrPartial::ValueNs(it) => (it, None), - ValueOrPartial::Partial(def, remaining_index) => { - self.resolve_assoc_item(def, path, remaining_index, id)? + ResolveValueResult::ValueNs(it) => (it, None), + ResolveValueResult::Partial(def, remaining_index) => { + self.resolve_assoc_item(Either::A(def), path, remaining_index, id)? + } + ResolveValueResult::TypeRef(type_ref) => { + let ty = self.make_ty(type_ref); + self.resolve_assoc_item(Either::B(ty), path, 0, id)? } }; @@ -503,7 +508,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_assoc_item( &mut self, - mut def: TypeNs, + mut def_or_ty: Either, path: &Path, remaining_index: usize, id: ExprOrPatId, @@ -516,30 +521,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // 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 = { - 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); + 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, + }; - // 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) + 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; @@ -550,15 +558,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { log::debug!("looking for path segment: {:?}", segment); let ty = mem::replace(&mut ty, Ty::Unknown); - def = ty.iterate_impl_items(self.db, krate, |item| { + 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(TypeNs::TypeAlias(..)) - None:: + // Some(Either::A(TypeNs::TypeAlias(..))) + None } } })?; @@ -1434,56 +1442,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn resolve_into_iter_item(&self) -> Option { - let into_iter_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::ITER, args_and_bindings: None }, - PathSegment { name: name::INTO_ITERATOR, args_and_bindings: None }, - ], - }; + let into_iter_path = Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::ITER, name::INTO_ITERATOR], + ); let trait_ = self.resolver.resolve_known_trait(self.db, &into_iter_path)?; trait_.associated_type_by_name(self.db, &name::ITEM) } fn resolve_ops_try_ok(&self) -> Option { - let ops_try_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::OPS, args_and_bindings: None }, - PathSegment { name: name::TRY, args_and_bindings: None }, - ], - }; + let ops_try_path = + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY]); let trait_ = self.resolver.resolve_known_trait(self.db, &ops_try_path)?; trait_.associated_type_by_name(self.db, &name::OK) } fn resolve_future_future_output(&self) -> Option { - let future_future_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, - PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, - ], - }; + let future_future_path = Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::FUTURE_MOD, name::FUTURE_TYPE], + ); let trait_ = self.resolver.resolve_known_trait(self.db, &future_future_path)?; trait_.associated_type_by_name(self.db, &name::OUTPUT) } fn resolve_boxed_box(&self) -> Option { - let boxed_box_path = Path { - kind: PathKind::Abs, - segments: vec![ - PathSegment { name: name::STD, args_and_bindings: None }, - PathSegment { name: name::BOXED_MOD, args_and_bindings: None }, - PathSegment { name: name::BOX_TYPE, args_and_bindings: None }, - ], - }; + let boxed_box_path = Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::BOXED_MOD, name::BOX_TYPE], + ); let struct_ = self.resolver.resolve_known_struct(self.db, &boxed_box_path)?; Some(Adt::Struct(struct_)) } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f6a2a658f..1bd677cab 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -281,6 +281,64 @@ fn test() { ); } +#[test] +fn infer_path_type() { + assert_snapshot!( + infer(r#" +struct S; + +impl S { + fn foo() -> i32 { 1 } +} + +fn test() { + S::foo(); + ::foo(); +} +"#), + @r###" + [41; 46) '{ 1 }': i32 + [43; 44) '1': i32 + [60; 93) '{ ...o(); }': () + [66; 72) 'S::foo': fn foo() -> i32 + [66; 74) 'S::foo()': i32 + [80; 88) '::foo': fn foo() -> i32 + [80; 90) '::foo()': i32 +"### + ); +} + +#[test] +fn infer_slice_method() { + assert_snapshot!( + infer(r#" +#[lang = "slice"] +impl [T] { + fn foo(&self) -> T { + loop {} + } +} + +#[lang = "slice_alloc"] +impl [T] {} + +fn test() { + <[_]>::foo(b"foo"); +} +"#), + @r###" + [45; 49) 'self': &[T] + [56; 79) '{ ... }': ! + [66; 73) 'loop {}': ! + [71; 73) '{}': () + [133; 160) '{ ...o"); }': () + [139; 149) '<[_]>::foo': fn foo(&[T]) -> T + [139; 157) '<[_]>:..."foo")': u8 + [150; 156) 'b"foo"': &[u8] +"### + ); +} + #[test] fn infer_struct() { assert_snapshot!( -- cgit v1.2.3