aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-04-21 14:01:48 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-04-21 14:01:48 +0100
commit5e1c29543cd49ab9f0833acbffd572d6b9f50da8 (patch)
tree1fdbd68757a878026c560cc133ddd3cc2672295e /crates
parent7f94119171658523bc854e8c8b4b6da28378b468 (diff)
parent787fb3e5ec56494f3856bb1ce33cbe296265d199 (diff)
Merge #1182
1182: Add HIR for where clauses & ignore impls with where clauses in trait resolution r=matklad a=flodiebold This prevents any `impl<T> Trait for T where ...` from being treated as a blanket impl while we don't handle where clauses yet. Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/generics.rs42
-rw-r--r--crates/ra_hir/src/ty/tests.rs17
-rw-r--r--crates/ra_hir/src/ty/traits.rs9
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
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use ra_syntax::ast::{self, NameOwner, TypeParamsOwner}; 8use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner};
9 9
10use crate::{ 10use 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 {
25pub struct GenericParams { 25pub 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)]
34pub 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]
2481fn 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
2486trait Clone {}
2487trait Trait { fn foo(self) -> u128; }
2488struct S;
2489impl S { fn foo(self) -> i8 { 0 } }
2490impl<T> Trait for T where T: Clone { fn foo(self) -> u128 { 0 } }
2491fn test() { (&S).foo()<|>; }
2492"#,
2493 );
2494 assert_eq!(t, "i8");
2495}
2496
2480fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 2497fn 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.
2use std::collections::HashMap; 2use std::collections::HashMap;
3 3
4use crate::db::HirDatabase; 4use crate::{db::HirDatabase, generics::HasGenericParams};
5use super::{ TraitRef, Substs, infer::{ TypeVarId, InferTy}, Ty}; 5use 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}