aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-07-06 17:28:42 +0100
committerbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-07-06 17:28:42 +0100
commit9dc9a7a3e2fa858125f9b3c6170c0b259da06fb6 (patch)
treecce758eabcbcfbb1bc1673601477a9c86580cb2b /crates/ra_hir/src
parent219e0e8c8d6672feaab2f19b7c3280d5967360e4 (diff)
parentf854a29c9adcfeaa7164928ff91daab9ca9a063c (diff)
Merge #1496
1496: Add trait obligations for where clauses when calling functions/methods r=matklad a=flodiebold E.g. if we call `foo<T: Into<u32>>(x)`, that adds an obligation that `x: Into<u32>`, etc., which sometimes allows type inference to make further progress. Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/db.rs4
-rw-r--r--crates/ra_hir/src/generics.rs12
-rw-r--r--crates/ra_hir/src/resolve.rs12
-rw-r--r--crates/ra_hir/src/ty.rs4
-rw-r--r--crates/ra_hir/src/ty/infer.rs10
-rw-r--r--crates/ra_hir/src/ty/lower.rs20
-rw-r--r--crates/ra_hir/src/ty/tests.rs134
-rw-r--r--crates/ra_hir/src/ty/traits.rs11
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs6
9 files changed, 171 insertions, 42 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index a9c6c52d9..0e6e3fdb7 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -163,10 +163,10 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
163 #[salsa::invoke(crate::ty::callable_item_sig)] 163 #[salsa::invoke(crate::ty::callable_item_sig)]
164 fn callable_item_signature(&self, def: CallableDef) -> FnSig; 164 fn callable_item_signature(&self, def: CallableDef) -> FnSig;
165 165
166 #[salsa::invoke(crate::ty::generic_predicates)] 166 #[salsa::invoke(crate::ty::generic_predicates_query)]
167 fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>; 167 fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>;
168 168
169 #[salsa::invoke(crate::ty::generic_defaults)] 169 #[salsa::invoke(crate::ty::generic_defaults_query)]
170 fn generic_defaults(&self, def: GenericDef) -> Substs; 170 fn generic_defaults(&self, def: GenericDef) -> Substs;
171 171
172 #[salsa::invoke(crate::expr::body_with_source_map_query)] 172 #[salsa::invoke(crate::expr::body_with_source_map_query)]
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 9929331d3..521e47090 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -11,8 +11,8 @@ use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
12 path::Path, 12 path::Path,
13 type_ref::TypeRef, 13 type_ref::TypeRef,
14 AdtDef, AsName, Container, Enum, Function, HasSource, ImplBlock, Name, Struct, Trait, 14 AdtDef, AsName, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct,
15 TypeAlias, Union, 15 Trait, TypeAlias, Union,
16}; 16};
17 17
18/// Data about a generic parameter (to a function, struct, impl, ...). 18/// Data about a generic parameter (to a function, struct, impl, ...).
@@ -50,8 +50,11 @@ pub enum GenericDef {
50 Trait(Trait), 50 Trait(Trait),
51 TypeAlias(TypeAlias), 51 TypeAlias(TypeAlias),
52 ImplBlock(ImplBlock), 52 ImplBlock(ImplBlock),
53 // enum variants cannot have generics themselves, but their parent enums
54 // can, and this makes some code easier to write
55 EnumVariant(EnumVariant),
53} 56}
54impl_froms!(GenericDef: Function, Struct, Union, Enum, Trait, TypeAlias, ImplBlock); 57impl_froms!(GenericDef: Function, Struct, Union, Enum, Trait, TypeAlias, ImplBlock, EnumVariant);
55 58
56impl GenericParams { 59impl GenericParams {
57 pub(crate) fn generic_params_query( 60 pub(crate) fn generic_params_query(
@@ -62,6 +65,7 @@ impl GenericParams {
62 let parent = match def { 65 let parent = match def {
63 GenericDef::Function(it) => it.container(db).map(GenericDef::from), 66 GenericDef::Function(it) => it.container(db).map(GenericDef::from),
64 GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from), 67 GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
68 GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()),
65 GenericDef::Struct(_) 69 GenericDef::Struct(_)
66 | GenericDef::Union(_) 70 | GenericDef::Union(_)
67 | GenericDef::Enum(_) 71 | GenericDef::Enum(_)
@@ -86,6 +90,7 @@ impl GenericParams {
86 } 90 }
87 GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).ast, start), 91 GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).ast, start),
88 GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).ast, start), 92 GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).ast, start),
93 GenericDef::EnumVariant(_) => {}
89 } 94 }
90 95
91 Arc::new(generics) 96 Arc::new(generics)
@@ -184,6 +189,7 @@ impl GenericDef {
184 GenericDef::Trait(inner) => inner.resolver(db), 189 GenericDef::Trait(inner) => inner.resolver(db),
185 GenericDef::TypeAlias(inner) => inner.resolver(db), 190 GenericDef::TypeAlias(inner) => inner.resolver(db),
186 GenericDef::ImplBlock(inner) => inner.resolver(db), 191 GenericDef::ImplBlock(inner) => inner.resolver(db),
192 GenericDef::EnumVariant(inner) => inner.parent_enum(db).resolver(db),
187 } 193 }
188 } 194 }
189} 195}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index c8be27e54..e2a7639b0 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -221,6 +221,18 @@ impl Resolver {
221 pub(crate) fn krate(&self) -> Option<Crate> { 221 pub(crate) fn krate(&self) -> Option<Crate> {
222 self.module().map(|t| t.0.krate()) 222 self.module().map(|t| t.0.krate())
223 } 223 }
224
225 pub(crate) fn where_predicates_in_scope<'a>(
226 &'a self,
227 ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a {
228 self.scopes
229 .iter()
230 .filter_map(|scope| match scope {
231 Scope::GenericParams(params) => Some(params),
232 _ => None,
233 })
234 .flat_map(|params| params.where_predicates.iter())
235 }
224} 236}
225 237
226impl Resolver { 238impl Resolver {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 11afdc0f3..d8c7945e1 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -23,8 +23,8 @@ pub(crate) use autoderef::autoderef;
23pub(crate) use infer::{infer_query, InferTy, InferenceResult}; 23pub(crate) use infer::{infer_query, InferTy, InferenceResult};
24pub use lower::CallableDef; 24pub use lower::CallableDef;
25pub(crate) use lower::{ 25pub(crate) use lower::{
26 callable_item_sig, generic_defaults, generic_predicates, type_for_def, type_for_field, 26 callable_item_sig, generic_defaults_query, generic_predicates_query, type_for_def,
27 TypableDef, 27 type_for_field, TypableDef,
28}; 28};
29pub(crate) use traits::ProjectionPredicate; 29pub(crate) use traits::ProjectionPredicate;
30 30
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index a23daabc2..e79e5e223 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -849,8 +849,14 @@ 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(def.into());
853 for predicate in generic_predicates.iter() {
854 let predicate = predicate.clone().subst(&a_ty.parameters);
855 if let Some(obligation) = Obligation::from_predicate(predicate) {
856 self.obligations.push(obligation);
857 }
858 }
852 // add obligation for trait implementation, if this is a trait method 859 // 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 { 860 match def {
855 CallableDef::Function(f) => { 861 CallableDef::Function(f) => {
856 if let Some(trait_) = f.parent_trait(self.db) { 862 if let Some(trait_) = f.parent_trait(self.db) {
@@ -992,7 +998,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
992 (Vec::new(), Ty::Unknown) 998 (Vec::new(), Ty::Unknown)
993 } 999 }
994 }; 1000 };
995 // FIXME register obligations from where clauses from the function 1001 self.register_obligations_for_call(&callee_ty);
996 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); 1002 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
997 for (arg, param) in args.iter().zip(param_iter) { 1003 for (arg, param) in args.iter().zip(param_iter) {
998 self.infer_expr(*arg, &Expectation::has_type(param)); 1004 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..b48ada760 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
@@ -511,3 +509,13 @@ pub enum CallableDef {
511 EnumVariant(EnumVariant), 509 EnumVariant(EnumVariant),
512} 510}
513impl_froms!(CallableDef: Function, Struct, EnumVariant); 511impl_froms!(CallableDef: Function, Struct, EnumVariant);
512
513impl From<CallableDef> for GenericDef {
514 fn from(def: CallableDef) -> GenericDef {
515 match def {
516 CallableDef::Function(f) => f.into(),
517 CallableDef::Struct(s) => s.into(),
518 CallableDef::EnumVariant(e) => e.into(),
519 }
520 }
521}
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,
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 2a0537bc3..4c3744b44 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -428,11 +428,7 @@ pub(crate) fn struct_datum_query(
428 CallableDef::Struct(s) => s.module(db).krate(db), 428 CallableDef::Struct(s) => s.module(db).krate(db),
429 CallableDef::EnumVariant(v) => v.parent_enum(db).module(db).krate(db), 429 CallableDef::EnumVariant(v) => v.parent_enum(db).module(db).krate(db),
430 } != Some(krate); 430 } != Some(krate);
431 let generic_def: GenericDef = match callable { 431 let generic_def: GenericDef = callable.into();
432 CallableDef::Function(f) => f.into(),
433 CallableDef::Struct(s) => s.into(),
434 CallableDef::EnumVariant(v) => v.parent_enum(db).into(),
435 };
436 let generic_params = generic_def.generic_params(db); 432 let generic_params = generic_def.generic_params(db);
437 let bound_vars = Substs::bound_vars(&generic_params); 433 let bound_vars = Substs::bound_vars(&generic_params);
438 let where_clauses = convert_where_clauses(db, generic_def, &bound_vars); 434 let where_clauses = convert_where_clauses(db, generic_def, &bound_vars);