diff options
-rw-r--r-- | crates/ra_hir/src/generics.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 9 |
3 files changed, 63 insertions, 5 deletions
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 5625c2459..1c71e21ea 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -5,11 +5,11 @@ | |||
5 | 5 | ||
6 | use std::sync::Arc; | 6 | use std::sync::Arc; |
7 | 7 | ||
8 | use ra_syntax::ast::{self, NameOwner, TypeParamsOwner}; | 8 | use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::DefDatabase, | 11 | db::DefDatabase, |
12 | Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container | 12 | Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container, path::Path, type_ref::TypeRef |
13 | }; | 13 | }; |
14 | 14 | ||
15 | /// Data about a generic parameter (to a function, struct, impl, ...). | 15 | /// Data about a generic parameter (to a function, struct, impl, ...). |
@@ -25,6 +25,15 @@ pub struct GenericParam { | |||
25 | pub struct GenericParams { | 25 | pub struct GenericParams { |
26 | pub(crate) parent_params: Option<Arc<GenericParams>>, | 26 | pub(crate) parent_params: Option<Arc<GenericParams>>, |
27 | pub(crate) params: Vec<GenericParam>, | 27 | pub(crate) params: Vec<GenericParam>, |
28 | pub(crate) where_predicates: Vec<WherePredicate>, | ||
29 | } | ||
30 | |||
31 | /// A single predicate from a where clause, i.e. `where Type: Trait`. Combined | ||
32 | /// where clauses like `where T: Foo + Bar` are turned into multiple of these. | ||
33 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
34 | pub struct WherePredicate { | ||
35 | type_ref: TypeRef, | ||
36 | trait_ref: Path, | ||
28 | } | 37 | } |
29 | 38 | ||
30 | // FIXME: consts can have type parameters from their parents (i.e. associated consts of traits) | 39 | // FIXME: consts can have type parameters from their parents (i.e. associated consts of traits) |
@@ -73,6 +82,9 @@ impl GenericParams { | |||
73 | if let Some(params) = node.type_param_list() { | 82 | if let Some(params) = node.type_param_list() { |
74 | self.fill_params(params, start) | 83 | self.fill_params(params, start) |
75 | } | 84 | } |
85 | if let Some(where_clause) = node.where_clause() { | ||
86 | self.fill_where_predicates(where_clause); | ||
87 | } | ||
76 | } | 88 | } |
77 | 89 | ||
78 | fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { | 90 | fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { |
@@ -83,6 +95,32 @@ impl GenericParams { | |||
83 | } | 95 | } |
84 | } | 96 | } |
85 | 97 | ||
98 | fn fill_where_predicates(&mut self, where_clause: &ast::WhereClause) { | ||
99 | for pred in where_clause.predicates() { | ||
100 | let type_ref = match pred.type_ref() { | ||
101 | Some(type_ref) => type_ref, | ||
102 | None => continue, | ||
103 | }; | ||
104 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | ||
105 | let path = bound | ||
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 | } | ||
121 | } | ||
122 | } | ||
123 | |||
86 | pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { | 124 | pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { |
87 | self.params.iter().find(|p| &p.name == name) | 125 | self.params.iter().find(|p| &p.name == name) |
88 | } | 126 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 86f18b487..a4c99528d 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2477,6 +2477,23 @@ fn test() { (&S).foo()<|>; } | |||
2477 | assert_eq!(t, "u128"); | 2477 | assert_eq!(t, "u128"); |
2478 | } | 2478 | } |
2479 | 2479 | ||
2480 | #[test] | ||
2481 | fn method_resolution_where_clause_not_met() { | ||
2482 | // The blanket impl shouldn't apply because we can't prove S: Clone | ||
2483 | let t = type_at( | ||
2484 | r#" | ||
2485 | //- /main.rs | ||
2486 | trait Clone {} | ||
2487 | trait Trait { fn foo(self) -> u128; } | ||
2488 | struct S; | ||
2489 | impl S { fn foo(self) -> i8 { 0 } } | ||
2490 | impl<T> Trait for T where T: Clone { fn foo(self) -> u128 { 0 } } | ||
2491 | fn test() { (&S).foo()<|>; } | ||
2492 | "#, | ||
2493 | ); | ||
2494 | assert_eq!(t, "i8"); | ||
2495 | } | ||
2496 | |||
2480 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 2497 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
2481 | let file = db.parse(pos.file_id); | 2498 | let file = db.parse(pos.file_id); |
2482 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 2499 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index f8c3958bd..06f483899 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | //! Stuff that will probably mostly replaced by Chalk. | 1 | //! Stuff that will probably mostly replaced by Chalk. |
2 | use std::collections::HashMap; | 2 | use std::collections::HashMap; |
3 | 3 | ||
4 | use crate::db::HirDatabase; | 4 | use crate::{db::HirDatabase, generics::HasGenericParams}; |
5 | use super::{ TraitRef, Substs, infer::{ TypeVarId, InferTy}, Ty}; | 5 | use super::{TraitRef, Substs, infer::{TypeVarId, InferTy}, Ty}; |
6 | 6 | ||
7 | // Copied (and simplified) from Chalk | 7 | // Copied (and simplified) from Chalk |
8 | 8 | ||
@@ -59,7 +59,10 @@ pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> Option<S | |||
59 | None => return None, | 59 | None => return None, |
60 | }; | 60 | }; |
61 | let crate_impl_blocks = db.impls_in_crate(krate); | 61 | let crate_impl_blocks = db.impls_in_crate(krate); |
62 | let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_); | 62 | let mut impl_blocks = crate_impl_blocks |
63 | .lookup_impl_blocks_for_trait(&trait_ref.trait_) | ||
64 | // we don't handle where clauses at all, waiting for Chalk for that | ||
65 | .filter(|impl_block| impl_block.generic_params(db).where_predicates.is_empty()); | ||
63 | impl_blocks | 66 | impl_blocks |
64 | .find_map(|impl_block| unify_trait_refs(&trait_ref, &impl_block.target_trait_ref(db)?)) | 67 | .find_map(|impl_block| unify_trait_refs(&trait_ref, &impl_block.target_trait_ref(db)?)) |
65 | } | 68 | } |