diff options
author | Florian Diebold <[email protected]> | 2019-05-11 15:49:55 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-05-11 15:56:36 +0100 |
commit | cbe75676b90d93e5b0ac461dce2d916cef4c0476 (patch) | |
tree | 50999df2191aa13204ca05f255ebe2b2105a1832 /crates/ra_hir | |
parent | d6dc75f9f22b73faf8c526be69ca43e52d6db1bf (diff) |
Add support for inline bounds
E.g. impl<T: Clone> Foo for T.
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/generics.rs | 43 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 33 |
2 files changed, 60 insertions, 16 deletions
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 { | |||
90 | fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { | 90 | fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { |
91 | for (idx, type_param) in params.type_params().enumerate() { | 91 | for (idx, type_param) in params.type_params().enumerate() { |
92 | let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); | 92 | let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); |
93 | let param = GenericParam { idx: idx as u32 + start, name }; | 93 | let param = GenericParam { idx: idx as u32 + start, name: name.clone() }; |
94 | self.params.push(param); | 94 | self.params.push(param); |
95 | |||
96 | let type_ref = TypeRef::Path(name.into()); | ||
97 | for bound in type_param | ||
98 | .type_bound_list() | ||
99 | .iter() | ||
100 | .flat_map(|type_bound_list| type_bound_list.bounds()) | ||
101 | { | ||
102 | self.add_where_predicate_from_bound(bound, type_ref.clone()); | ||
103 | } | ||
95 | } | 104 | } |
96 | } | 105 | } |
97 | 106 | ||
@@ -101,26 +110,28 @@ impl GenericParams { | |||
101 | Some(type_ref) => type_ref, | 110 | Some(type_ref) => type_ref, |
102 | None => continue, | 111 | None => continue, |
103 | }; | 112 | }; |
113 | let type_ref = TypeRef::from_ast(type_ref); | ||
104 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | 114 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { |
105 | let path = bound | 115 | self.add_where_predicate_from_bound(bound, type_ref.clone()); |
106 | .type_ref() | ||
107 | .and_then(|tr| match tr.kind() { | ||
108 | ast::TypeRefKind::PathType(path) => path.path(), | ||
109 | _ => None, | ||
110 | }) | ||
111 | .and_then(Path::from_ast); | ||
112 | let path = match path { | ||
113 | Some(p) => p, | ||
114 | None => continue, | ||
115 | }; | ||
116 | self.where_predicates.push(WherePredicate { | ||
117 | type_ref: TypeRef::from_ast(type_ref), | ||
118 | trait_ref: path, | ||
119 | }); | ||
120 | } | 116 | } |
121 | } | 117 | } |
122 | } | 118 | } |
123 | 119 | ||
120 | fn add_where_predicate_from_bound(&mut self, bound: &ast::TypeBound, type_ref: TypeRef) { | ||
121 | let path = bound | ||
122 | .type_ref() | ||
123 | .and_then(|tr| match tr.kind() { | ||
124 | ast::TypeRefKind::PathType(path) => path.path(), | ||
125 | _ => None, | ||
126 | }) | ||
127 | .and_then(Path::from_ast); | ||
128 | let path = match path { | ||
129 | Some(p) => p, | ||
130 | None => return, | ||
131 | }; | ||
132 | self.where_predicates.push(WherePredicate { type_ref, trait_ref: path }); | ||
133 | } | ||
134 | |||
124 | pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { | 135 | pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { |
125 | self.params.iter().find(|p| &p.name == name) | 136 | self.params.iter().find(|p| &p.name == name) |
126 | } | 137 | } |
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 | |||
@@ -2536,6 +2536,22 @@ fn test() { (&S).foo()<|>; } | |||
2536 | } | 2536 | } |
2537 | 2537 | ||
2538 | #[test] | 2538 | #[test] |
2539 | fn method_resolution_where_clause_inline_not_met() { | ||
2540 | // The blanket impl shouldn't apply because we can't prove S: Clone | ||
2541 | let t = type_at( | ||
2542 | r#" | ||
2543 | //- /main.rs | ||
2544 | trait Clone {} | ||
2545 | trait Trait { fn foo(self) -> u128; } | ||
2546 | struct S; | ||
2547 | impl<T: Clone> Trait for T {} | ||
2548 | fn test() { (&S).foo()<|>; } | ||
2549 | "#, | ||
2550 | ); | ||
2551 | assert_eq!(t, "{unknown}"); | ||
2552 | } | ||
2553 | |||
2554 | #[test] | ||
2539 | fn method_resolution_where_clause_1() { | 2555 | fn method_resolution_where_clause_1() { |
2540 | let t = type_at( | 2556 | let t = type_at( |
2541 | r#" | 2557 | r#" |
@@ -2569,6 +2585,23 @@ fn test() { S2.into()<|>; } | |||
2569 | } | 2585 | } |
2570 | 2586 | ||
2571 | #[test] | 2587 | #[test] |
2588 | fn method_resolution_where_clause_inline() { | ||
2589 | let t = type_at( | ||
2590 | r#" | ||
2591 | //- /main.rs | ||
2592 | trait Into<T> { fn into(self) -> T; } | ||
2593 | trait From<T> { fn from(other: T) -> Self; } | ||
2594 | struct S1; | ||
2595 | struct S2; | ||
2596 | impl From<S2> for S1 {}; | ||
2597 | impl<T, U: From<T>> Into<U> for T {} | ||
2598 | fn test() { S2.into()<|>; } | ||
2599 | "#, | ||
2600 | ); | ||
2601 | assert_eq!(t, "S1"); | ||
2602 | } | ||
2603 | |||
2604 | #[test] | ||
2572 | fn method_resolution_encountering_fn_type() { | 2605 | fn method_resolution_encountering_fn_type() { |
2573 | covers!(trait_resolution_on_fn_type); | 2606 | covers!(trait_resolution_on_fn_type); |
2574 | type_at( | 2607 | type_at( |