From cbe75676b90d93e5b0ac461dce2d916cef4c0476 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 11 May 2019 16:49:55 +0200 Subject: Add support for inline bounds E.g. impl Foo for T. --- crates/ra_hir/src/generics.rs | 43 +++++++++++++++++++++++++++---------------- crates/ra_hir/src/ty/tests.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 16 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 826117ba5..c29b96f50 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -90,8 +90,17 @@ impl GenericParams { fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { for (idx, type_param) in params.type_params().enumerate() { let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); - let param = GenericParam { idx: idx as u32 + start, name }; + let param = GenericParam { idx: idx as u32 + start, name: name.clone() }; self.params.push(param); + + let type_ref = TypeRef::Path(name.into()); + for bound in type_param + .type_bound_list() + .iter() + .flat_map(|type_bound_list| type_bound_list.bounds()) + { + self.add_where_predicate_from_bound(bound, type_ref.clone()); + } } } @@ -101,26 +110,28 @@ impl GenericParams { Some(type_ref) => type_ref, None => continue, }; + let type_ref = TypeRef::from_ast(type_ref); for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { - let path = bound - .type_ref() - .and_then(|tr| match tr.kind() { - ast::TypeRefKind::PathType(path) => path.path(), - _ => None, - }) - .and_then(Path::from_ast); - let path = match path { - Some(p) => p, - None => continue, - }; - self.where_predicates.push(WherePredicate { - type_ref: TypeRef::from_ast(type_ref), - trait_ref: path, - }); + self.add_where_predicate_from_bound(bound, type_ref.clone()); } } } + fn add_where_predicate_from_bound(&mut self, bound: &ast::TypeBound, type_ref: TypeRef) { + let path = bound + .type_ref() + .and_then(|tr| match tr.kind() { + ast::TypeRefKind::PathType(path) => path.path(), + _ => None, + }) + .and_then(Path::from_ast); + let path = match path { + Some(p) => p, + None => return, + }; + self.where_predicates.push(WherePredicate { type_ref, trait_ref: path }); + } + pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { self.params.iter().find(|p| &p.name == name) } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 6f8d8fa49..59c85daed 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -2535,6 +2535,22 @@ fn test() { (&S).foo()<|>; } assert_eq!(t, "{unknown}"); } +#[test] +fn method_resolution_where_clause_inline_not_met() { + // The blanket impl shouldn't apply because we can't prove S: Clone + let t = type_at( + r#" +//- /main.rs +trait Clone {} +trait Trait { fn foo(self) -> u128; } +struct S; +impl Trait for T {} +fn test() { (&S).foo()<|>; } +"#, + ); + assert_eq!(t, "{unknown}"); +} + #[test] fn method_resolution_where_clause_1() { let t = type_at( @@ -2568,6 +2584,23 @@ fn test() { S2.into()<|>; } assert_eq!(t, "S1"); } +#[test] +fn method_resolution_where_clause_inline() { + let t = type_at( + r#" +//- /main.rs +trait Into { fn into(self) -> T; } +trait From { fn from(other: T) -> Self; } +struct S1; +struct S2; +impl From for S1 {}; +impl> Into for T {} +fn test() { S2.into()<|>; } +"#, + ); + assert_eq!(t, "S1"); +} + #[test] fn method_resolution_encountering_fn_type() { covers!(trait_resolution_on_fn_type); -- cgit v1.2.3