aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-07-06 15:41:04 +0100
committerFlorian Diebold <[email protected]>2019-07-06 16:34:05 +0100
commit065d3987012b138b123f0544de193f8bb560b1b5 (patch)
tree029ff3c3a9beb816c3056cd38595e15f3c541998 /crates/ra_hir/src/ty
parent219e0e8c8d6672feaab2f19b7c3280d5967360e4 (diff)
Add trait obligations for where clauses when calling functions/methods
E.g. if we call `foo<T: Into<u32>>(x)`, that adds an obligation that `x: Into<u32>`, etc.
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/infer.rs15
-rw-r--r--crates/ra_hir/src/ty/lower.rs10
-rw-r--r--crates/ra_hir/src/ty/tests.rs134
-rw-r--r--crates/ra_hir/src/ty/traits.rs11
4 files changed, 140 insertions, 30 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index a23daabc2..f5d8cd4b1 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -849,8 +849,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
849 fn register_obligations_for_call(&mut self, callable_ty: &Ty) { 849 fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
850 if let Ty::Apply(a_ty) = callable_ty { 850 if let Ty::Apply(a_ty) = callable_ty {
851 if let TypeCtor::FnDef(def) = a_ty.ctor { 851 if let TypeCtor::FnDef(def) = a_ty.ctor {
852 let generic_predicates = self.db.generic_predicates(match def {
853 // TODO add helper function
854 CallableDef::Function(f) => f.into(),
855 CallableDef::Struct(s) => s.into(),
856 CallableDef::EnumVariant(_e) => unimplemented!(),
857 });
858 for predicate in generic_predicates.iter() {
859 let predicate = predicate.clone().subst(&a_ty.parameters);
860 if let Some(obligation) = Obligation::from_predicate(predicate) {
861 self.obligations.push(obligation);
862 }
863 }
852 // add obligation for trait implementation, if this is a trait method 864 // add obligation for trait implementation, if this is a trait method
853 // FIXME also register obligations from where clauses from the trait or impl and method
854 match def { 865 match def {
855 CallableDef::Function(f) => { 866 CallableDef::Function(f) => {
856 if let Some(trait_) = f.parent_trait(self.db) { 867 if let Some(trait_) = f.parent_trait(self.db) {
@@ -992,7 +1003,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
992 (Vec::new(), Ty::Unknown) 1003 (Vec::new(), Ty::Unknown)
993 } 1004 }
994 }; 1005 };
995 // FIXME register obligations from where clauses from the function 1006 self.register_obligations_for_call(&callee_ty);
996 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); 1007 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
997 for (arg, param) in args.iter().zip(param_iter) { 1008 for (arg, param) in args.iter().zip(param_iter) {
998 self.infer_expr(*arg, &Expectation::has_type(param)); 1009 self.infer_expr(*arg, &Expectation::has_type(param));
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 8b1b2a7f9..24755c6aa 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -318,15 +318,13 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
318} 318}
319 319
320/// Resolve the where clause(s) of an item with generics. 320/// Resolve the where clause(s) of an item with generics.
321pub(crate) fn generic_predicates( 321pub(crate) fn generic_predicates_query(
322 db: &impl HirDatabase, 322 db: &impl HirDatabase,
323 def: GenericDef, 323 def: GenericDef,
324) -> Arc<[GenericPredicate]> { 324) -> Arc<[GenericPredicate]> {
325 let resolver = def.resolver(db); 325 let resolver = def.resolver(db);
326 let generic_params = def.generic_params(db); 326 let predicates = resolver
327 let predicates = generic_params 327 .where_predicates_in_scope()
328 .where_predicates
329 .iter()
330 .map(|pred| { 328 .map(|pred| {
331 TraitRef::for_where_predicate(db, &resolver, pred) 329 TraitRef::for_where_predicate(db, &resolver, pred)
332 .map_or(GenericPredicate::Error, GenericPredicate::Implemented) 330 .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
@@ -336,7 +334,7 @@ pub(crate) fn generic_predicates(
336} 334}
337 335
338/// Resolve the default type params from generics 336/// Resolve the default type params from generics
339pub(crate) fn generic_defaults(db: &impl HirDatabase, def: GenericDef) -> Substs { 337pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDef) -> Substs {
340 let resolver = def.resolver(db); 338 let resolver = def.resolver(db);
341 let generic_params = def.generic_params(db); 339 let generic_params = def.generic_params(db);
342 340
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 20fa74fb4..aacd94a26 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2232,16 +2232,18 @@ fn test() {
2232} 2232}
2233"#), 2233"#),
2234 @r###" 2234 @r###"
2235[86; 87) 't': T 2235
2236[92; 94) '{}': () 2236 ⋮[86; 87) 't': T
2237[105; 144) '{ ...(s); }': () 2237 ⋮[92; 94) '{}': ()
2238[115; 116) 's': S<{unknown}> 2238 ⋮[105; 144) '{ ...(s); }': ()
2239[119; 120) 'S': S<{unknown}>(T) -> S<T> 2239 ⋮[115; 116) 's': S<u32>
2240[119; 129) 'S(unknown)': S<{unknown}> 2240 ⋮[119; 120) 'S': S<u32>(T) -> S<T>
2241[121; 128) 'unknown': {unknown} 2241 ⋮[119; 129) 'S(unknown)': S<u32>
2242[135; 138) 'foo': fn foo<S<{unknown}>>(T) -> () 2242 ⋮[121; 128) 'unknown': u32
2243[135; 141) 'foo(s)': () 2243 ⋮[135; 138) 'foo': fn foo<S<u32>>(T) -> ()
2244[139; 140) 's': S<{unknown}>"### 2244 ⋮[135; 141) 'foo(s)': ()
2245 ⋮[139; 140) 's': S<u32>
2246 "###
2245 ); 2247 );
2246} 2248}
2247 2249
@@ -2259,17 +2261,19 @@ fn test() {
2259} 2261}
2260"#), 2262"#),
2261 @r###" 2263 @r###"
2262[87; 88) 't': T 2264
2263[98; 100) '{}': () 2265 ⋮[87; 88) 't': T
2264[111; 163) '{ ...(s); }': () 2266 ⋮[98; 100) '{}': ()
2265[121; 122) 's': S<{unknown}> 2267 ⋮[111; 163) '{ ...(s); }': ()
2266[125; 126) 'S': S<{unknown}>(T) -> S<T> 2268 ⋮[121; 122) 's': S<u32>
2267[125; 135) 'S(unknown)': S<{unknown}> 2269 ⋮[125; 126) 'S': S<u32>(T) -> S<T>
2268[127; 134) 'unknown': {unknown} 2270 ⋮[125; 135) 'S(unknown)': S<u32>
2269[145; 146) 'x': u32 2271 ⋮[127; 134) 'unknown': u32
2270[154; 157) 'foo': fn foo<u32, S<{unknown}>>(T) -> U 2272 ⋮[145; 146) 'x': u32
2271[154; 160) 'foo(s)': u32 2273 ⋮[154; 157) 'foo': fn foo<u32, S<u32>>(T) -> U
2272[158; 159) 's': S<{unknown}>"### 2274 ⋮[154; 160) 'foo(s)': u32
2275 ⋮[158; 159) 's': S<u32>
2276 "###
2273 ); 2277 );
2274} 2278}
2275 2279
@@ -2822,6 +2826,94 @@ fn test(s: S) {
2822 assert_eq!(t, "{unknown}"); 2826 assert_eq!(t, "{unknown}");
2823} 2827}
2824 2828
2829#[test]
2830fn obligation_from_function_clause() {
2831 let t = type_at(
2832 r#"
2833//- /main.rs
2834struct S;
2835
2836trait Trait<T> {}
2837impl Trait<u32> for S {}
2838
2839fn foo<T: Trait<U>, U>(t: T) -> U {}
2840
2841fn test(s: S) {
2842 foo(s)<|>;
2843}
2844"#,
2845 );
2846 assert_eq!(t, "u32");
2847}
2848
2849#[test]
2850fn obligation_from_method_clause() {
2851 let t = type_at(
2852 r#"
2853//- /main.rs
2854struct S;
2855
2856trait Trait<T> {}
2857impl Trait<isize> for S {}
2858
2859struct O;
2860impl O {
2861 fn foo<T: Trait<U>, U>(&self, t: T) -> U {}
2862}
2863
2864fn test() {
2865 O.foo(S)<|>;
2866}
2867"#,
2868 );
2869 assert_eq!(t, "isize");
2870}
2871
2872#[test]
2873fn obligation_from_self_method_clause() {
2874 let t = type_at(
2875 r#"
2876//- /main.rs
2877struct S;
2878
2879trait Trait<T> {}
2880impl Trait<i64> for S {}
2881
2882impl S {
2883 fn foo<U>(&self) -> U where Self: Trait<U> {}
2884}
2885
2886fn test() {
2887 S.foo()<|>;
2888}
2889"#,
2890 );
2891 assert_eq!(t, "i64");
2892}
2893
2894#[test]
2895fn obligation_from_impl_clause() {
2896 let t = type_at(
2897 r#"
2898//- /main.rs
2899struct S;
2900
2901trait Trait<T> {}
2902impl Trait<&str> for S {}
2903
2904struct O<T>;
2905impl<U, T: Trait<U>> O<T> {
2906 fn foo(&self) -> U {}
2907}
2908
2909fn test(o: O<S>) {
2910 o.foo()<|>;
2911}
2912"#,
2913 );
2914 assert_eq!(t, "&str");
2915}
2916
2825fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 2917fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
2826 let file = db.parse(pos.file_id).ok().unwrap(); 2918 let file = db.parse(pos.file_id).ok().unwrap();
2827 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 2919 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 cff4de316..23a26a971 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -7,7 +7,7 @@ use parking_lot::Mutex;
7use ra_prof::profile; 7use ra_prof::profile;
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
9 9
10use super::{Canonical, ProjectionTy, TraitRef, Ty}; 10use super::{Canonical, GenericPredicate, ProjectionTy, TraitRef, Ty};
11use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; 11use crate::{db::HirDatabase, Crate, ImplBlock, Trait};
12 12
13use self::chalk::{from_chalk, ToChalk}; 13use self::chalk::{from_chalk, ToChalk};
@@ -78,6 +78,15 @@ pub enum Obligation {
78 // Projection(ProjectionPredicate), 78 // Projection(ProjectionPredicate),
79} 79}
80 80
81impl Obligation {
82 pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> {
83 match predicate {
84 GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)),
85 GenericPredicate::Error => None,
86 }
87 }
88}
89
81#[derive(Clone, Debug, PartialEq, Eq, Hash)] 90#[derive(Clone, Debug, PartialEq, Eq, Hash)]
82pub struct ProjectionPredicate { 91pub struct ProjectionPredicate {
83 pub projection_ty: ProjectionTy, 92 pub projection_ty: ProjectionTy,