diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-07-09 08:50:18 +0100 |
---|---|---|
committer | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-07-09 08:50:18 +0100 |
commit | f59cd1a4a0d6c369025a7014e838d25f91d478e4 (patch) | |
tree | 2c4b9dc868a87507ed63e9dc46530cc60f38ae64 /crates/ra_hir/src/ty | |
parent | 35f28c538a9b9f461bb4db1a78d02e9f02a3d296 (diff) | |
parent | 9afbf2dff43dee3227358f10162d4c77d192ce7a (diff) |
Merge #1515
1515: Trait environment r=matklad a=flodiebold
This adds the environment, i.e. the set of `where` clauses in scope, when solving trait goals. That means that e.g. in
```rust
fn foo<T: SomeTrait>(t: T) {}
```
, we are able to complete methods of `SomeTrait` on the `t`. This affects the trait APIs quite a bit (since every method that needs to be able to solve for some trait needs to get this environment somehow), so I thought I'd do it rather sooner than later ;)
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 69 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 34 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 79 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 63 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 99 |
8 files changed, 281 insertions, 106 deletions
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 90c1ae630..c26513871 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs | |||
@@ -52,6 +52,8 @@ fn deref_by_trait( | |||
52 | 52 | ||
53 | // FIXME make the Canonical handling nicer | 53 | // FIXME make the Canonical handling nicer |
54 | 54 | ||
55 | let env = super::lower::trait_env(db, resolver); | ||
56 | |||
55 | let projection = super::traits::ProjectionPredicate { | 57 | let projection = super::traits::ProjectionPredicate { |
56 | ty: Ty::Bound(0), | 58 | ty: Ty::Bound(0), |
57 | projection_ty: super::ProjectionTy { | 59 | projection_ty: super::ProjectionTy { |
@@ -60,9 +62,13 @@ fn deref_by_trait( | |||
60 | }, | 62 | }, |
61 | }; | 63 | }; |
62 | 64 | ||
63 | let canonical = super::Canonical { num_vars: 1 + ty.num_vars, value: projection }; | 65 | let obligation = super::Obligation::Projection(projection); |
66 | |||
67 | let in_env = super::traits::InEnvironment { value: obligation, environment: env }; | ||
68 | |||
69 | let canonical = super::Canonical { num_vars: 1 + ty.num_vars, value: in_env }; | ||
64 | 70 | ||
65 | let solution = db.normalize(krate, canonical)?; | 71 | let solution = db.solve(krate, canonical)?; |
66 | 72 | ||
67 | match &solution { | 73 | match &solution { |
68 | Solution::Unique(vars) => { | 74 | Solution::Unique(vars) => { |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 827addddd..26ddf0317 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -27,9 +27,10 @@ use ra_prof::profile; | |||
27 | use test_utils::tested_by; | 27 | use test_utils::tested_by; |
28 | 28 | ||
29 | use super::{ | 29 | use super::{ |
30 | autoderef, method_resolution, op, primitive, | 30 | autoderef, lower, method_resolution, op, primitive, |
31 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 31 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
32 | ApplicationTy, CallableDef, ProjectionTy, Substs, TraitRef, Ty, TypableDef, TypeCtor, | 32 | ApplicationTy, CallableDef, Environment, InEnvironment, ProjectionTy, Substs, TraitRef, Ty, |
33 | TypableDef, TypeCtor, | ||
33 | }; | 34 | }; |
34 | use crate::{ | 35 | use crate::{ |
35 | adt::VariantDef, | 36 | adt::VariantDef, |
@@ -165,6 +166,7 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
165 | body: Arc<Body>, | 166 | body: Arc<Body>, |
166 | resolver: Resolver, | 167 | resolver: Resolver, |
167 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 168 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
169 | trait_env: Arc<Environment>, | ||
168 | obligations: Vec<Obligation>, | 170 | obligations: Vec<Obligation>, |
169 | method_resolutions: FxHashMap<ExprId, Function>, | 171 | method_resolutions: FxHashMap<ExprId, Function>, |
170 | field_resolutions: FxHashMap<ExprId, StructField>, | 172 | field_resolutions: FxHashMap<ExprId, StructField>, |
@@ -188,6 +190,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
188 | var_unification_table: InPlaceUnificationTable::new(), | 190 | var_unification_table: InPlaceUnificationTable::new(), |
189 | obligations: Vec::default(), | 191 | obligations: Vec::default(), |
190 | return_ty: Ty::Unknown, // set in collect_fn_signature | 192 | return_ty: Ty::Unknown, // set in collect_fn_signature |
193 | trait_env: lower::trait_env(db, &resolver), | ||
191 | db, | 194 | db, |
192 | body, | 195 | body, |
193 | resolver, | 196 | resolver, |
@@ -328,51 +331,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
328 | fn resolve_obligations_as_possible(&mut self) { | 331 | fn resolve_obligations_as_possible(&mut self) { |
329 | let obligations = mem::replace(&mut self.obligations, Vec::new()); | 332 | let obligations = mem::replace(&mut self.obligations, Vec::new()); |
330 | for obligation in obligations { | 333 | for obligation in obligations { |
331 | match &obligation { | 334 | let in_env = InEnvironment::new(self.trait_env.clone(), obligation.clone()); |
332 | Obligation::Trait(tr) => { | 335 | let canonicalized = self.canonicalizer().canonicalize_obligation(in_env); |
333 | let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone()); | 336 | let solution = |
334 | let solution = self | 337 | self.db.solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); |
335 | .db | 338 | |
336 | .implements(self.resolver.krate().unwrap(), canonicalized.value.clone()); | 339 | match solution { |
337 | match solution { | 340 | Some(Solution::Unique(substs)) => { |
338 | Some(Solution::Unique(substs)) => { | 341 | canonicalized.apply_solution(self, substs.0); |
339 | canonicalized.apply_solution(self, substs.0); | ||
340 | } | ||
341 | Some(Solution::Ambig(Guidance::Definite(substs))) => { | ||
342 | canonicalized.apply_solution(self, substs.0); | ||
343 | self.obligations.push(obligation); | ||
344 | } | ||
345 | Some(_) => { | ||
346 | // FIXME use this when trying to resolve everything at the end | ||
347 | self.obligations.push(obligation); | ||
348 | } | ||
349 | None => { | ||
350 | // FIXME obligation cannot be fulfilled => diagnostic | ||
351 | } | ||
352 | }; | ||
353 | } | 342 | } |
354 | Obligation::Projection(pr) => { | 343 | Some(Solution::Ambig(Guidance::Definite(substs))) => { |
355 | let canonicalized = self.canonicalizer().canonicalize_projection(pr.clone()); | 344 | canonicalized.apply_solution(self, substs.0); |
356 | let solution = self | 345 | self.obligations.push(obligation); |
357 | .db | 346 | } |
358 | .normalize(self.resolver.krate().unwrap(), canonicalized.value.clone()); | 347 | Some(_) => { |
359 | 348 | // FIXME use this when trying to resolve everything at the end | |
360 | match solution { | 349 | self.obligations.push(obligation); |
361 | Some(Solution::Unique(substs)) => { | 350 | } |
362 | canonicalized.apply_solution(self, substs.0); | 351 | None => { |
363 | } | 352 | // FIXME obligation cannot be fulfilled => diagnostic |
364 | Some(Solution::Ambig(Guidance::Definite(substs))) => { | ||
365 | canonicalized.apply_solution(self, substs.0); | ||
366 | self.obligations.push(obligation); | ||
367 | } | ||
368 | Some(_) => { | ||
369 | // FIXME use this when trying to resolve everything at the end | ||
370 | self.obligations.push(obligation); | ||
371 | } | ||
372 | None => { | ||
373 | // FIXME obligation cannot be fulfilled => diagnostic | ||
374 | } | ||
375 | }; | ||
376 | } | 353 | } |
377 | }; | 354 | }; |
378 | } | 355 | } |
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index a24e5eb5c..e7e8825d1 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs | |||
@@ -1,8 +1,10 @@ | |||
1 | //! Unification and canonicalization logic. | 1 | //! Unification and canonicalization logic. |
2 | 2 | ||
3 | use super::InferenceContext; | 3 | use super::{InferenceContext, Obligation}; |
4 | use crate::db::HirDatabase; | 4 | use crate::db::HirDatabase; |
5 | use crate::ty::{Canonical, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty}; | 5 | use crate::ty::{ |
6 | Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, | ||
7 | }; | ||
6 | 8 | ||
7 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 9 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
8 | pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> | 10 | pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> |
@@ -105,22 +107,28 @@ where | |||
105 | ProjectionPredicate { ty, projection_ty } | 107 | ProjectionPredicate { ty, projection_ty } |
106 | } | 108 | } |
107 | 109 | ||
108 | pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | 110 | // FIXME: add some point, we need to introduce a `Fold` trait that abstracts |
109 | let result = self.do_canonicalize_ty(ty); | 111 | // over all the things that can be canonicalized (like Chalk and rustc have) |
110 | self.into_canonicalized(result) | ||
111 | } | ||
112 | 112 | ||
113 | pub fn canonicalize_trait_ref(mut self, trait_ref: TraitRef) -> Canonicalized<TraitRef> { | 113 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { |
114 | let result = self.do_canonicalize_trait_ref(trait_ref); | 114 | let result = self.do_canonicalize_ty(ty); |
115 | self.into_canonicalized(result) | 115 | self.into_canonicalized(result) |
116 | } | 116 | } |
117 | 117 | ||
118 | pub fn canonicalize_projection( | 118 | pub(crate) fn canonicalize_obligation( |
119 | mut self, | 119 | mut self, |
120 | projection: ProjectionPredicate, | 120 | obligation: InEnvironment<Obligation>, |
121 | ) -> Canonicalized<ProjectionPredicate> { | 121 | ) -> Canonicalized<InEnvironment<Obligation>> { |
122 | let result = self.do_canonicalize_projection_predicate(projection); | 122 | let result = match obligation.value { |
123 | self.into_canonicalized(result) | 123 | Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize_trait_ref(tr)), |
124 | Obligation::Projection(pr) => { | ||
125 | Obligation::Projection(self.do_canonicalize_projection_predicate(pr)) | ||
126 | } | ||
127 | }; | ||
128 | self.into_canonicalized(InEnvironment { | ||
129 | value: result, | ||
130 | environment: obligation.environment, | ||
131 | }) | ||
124 | } | 132 | } |
125 | } | 133 | } |
126 | 134 | ||
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index b48ada760..ca47d6e96 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -317,6 +317,18 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { | |||
317 | Ty::from_hir(db, &resolver, type_ref) | 317 | Ty::from_hir(db, &resolver, type_ref) |
318 | } | 318 | } |
319 | 319 | ||
320 | pub(crate) fn trait_env(db: &impl HirDatabase, resolver: &Resolver) -> Arc<super::Environment> { | ||
321 | let predicates = resolver | ||
322 | .where_predicates_in_scope() | ||
323 | .map(|pred| { | ||
324 | TraitRef::for_where_predicate(db, &resolver, pred) | ||
325 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | ||
326 | }) | ||
327 | .collect::<Vec<_>>(); | ||
328 | |||
329 | Arc::new(super::Environment { predicates }) | ||
330 | } | ||
331 | |||
320 | /// Resolve the where clause(s) of an item with generics. | 332 | /// Resolve the where clause(s) of an item with generics. |
321 | pub(crate) fn generic_predicates_query( | 333 | pub(crate) fn generic_predicates_query( |
322 | db: &impl HirDatabase, | 334 | db: &impl HirDatabase, |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index f65ad08a8..353820436 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -7,7 +7,7 @@ use std::sync::Arc; | |||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use rustc_hash::FxHashMap; | 8 | use rustc_hash::FxHashMap; |
9 | 9 | ||
10 | use super::{autoderef, Canonical, TraitRef}; | 10 | use super::{autoderef, lower, Canonical, Environment, InEnvironment, TraitRef}; |
11 | use crate::{ | 11 | use crate::{ |
12 | generics::HasGenericParams, | 12 | generics::HasGenericParams, |
13 | impl_block::{ImplBlock, ImplId, ImplItem}, | 13 | impl_block::{ImplBlock, ImplId, ImplItem}, |
@@ -200,6 +200,8 @@ fn iterate_trait_method_candidates<T>( | |||
200 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 200 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
201 | ) -> Option<T> { | 201 | ) -> Option<T> { |
202 | let krate = resolver.krate()?; | 202 | let krate = resolver.krate()?; |
203 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) | ||
204 | let env = lower::trait_env(db, resolver); | ||
203 | 'traits: for t in resolver.traits_in_scope(db) { | 205 | 'traits: for t in resolver.traits_in_scope(db) { |
204 | let data = t.trait_data(db); | 206 | let data = t.trait_data(db); |
205 | // we'll be lazy about checking whether the type implements the | 207 | // we'll be lazy about checking whether the type implements the |
@@ -211,8 +213,8 @@ fn iterate_trait_method_candidates<T>( | |||
211 | let data = m.data(db); | 213 | let data = m.data(db); |
212 | if name.map_or(true, |name| data.name() == name) && data.has_self_param() { | 214 | if name.map_or(true, |name| data.name() == name) && data.has_self_param() { |
213 | if !known_implemented { | 215 | if !known_implemented { |
214 | let trait_ref = canonical_trait_ref(db, t, ty.clone()); | 216 | let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); |
215 | if db.implements(krate, trait_ref).is_none() { | 217 | if db.solve(krate, goal).is_none() { |
216 | continue 'traits; | 218 | continue 'traits; |
217 | } | 219 | } |
218 | } | 220 | } |
@@ -279,11 +281,12 @@ impl Ty { | |||
279 | 281 | ||
280 | /// This creates Substs for a trait with the given Self type and type variables | 282 | /// This creates Substs for a trait with the given Self type and type variables |
281 | /// for all other parameters, to query Chalk with it. | 283 | /// for all other parameters, to query Chalk with it. |
282 | fn canonical_trait_ref( | 284 | fn generic_implements_goal( |
283 | db: &impl HirDatabase, | 285 | db: &impl HirDatabase, |
286 | env: Arc<Environment>, | ||
284 | trait_: Trait, | 287 | trait_: Trait, |
285 | self_ty: Canonical<Ty>, | 288 | self_ty: Canonical<Ty>, |
286 | ) -> Canonical<TraitRef> { | 289 | ) -> Canonical<InEnvironment<super::Obligation>> { |
287 | let mut substs = Vec::new(); | 290 | let mut substs = Vec::new(); |
288 | let generics = trait_.generic_params(db); | 291 | let generics = trait_.generic_params(db); |
289 | let num_vars = self_ty.num_vars; | 292 | let num_vars = self_ty.num_vars; |
@@ -296,8 +299,8 @@ fn canonical_trait_ref( | |||
296 | .enumerate() | 299 | .enumerate() |
297 | .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)), | 300 | .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)), |
298 | ); | 301 | ); |
299 | Canonical { | 302 | let num_vars = substs.len() - 1 + self_ty.num_vars; |
300 | num_vars: substs.len() - 1 + self_ty.num_vars, | 303 | let trait_ref = TraitRef { trait_, substs: substs.into() }; |
301 | value: TraitRef { trait_, substs: substs.into() }, | 304 | let obligation = super::Obligation::Trait(trait_ref); |
302 | } | 305 | Canonical { num_vars, value: InEnvironment::new(env, obligation) } |
303 | } | 306 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 6aea1fb4a..2410602a6 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3003,6 +3003,85 @@ fn test(o: O<S>) { | |||
3003 | assert_eq!(t, "&str"); | 3003 | assert_eq!(t, "&str"); |
3004 | } | 3004 | } |
3005 | 3005 | ||
3006 | #[test] | ||
3007 | fn generic_param_env_1() { | ||
3008 | let t = type_at( | ||
3009 | r#" | ||
3010 | //- /main.rs | ||
3011 | trait Clone {} | ||
3012 | trait Trait { fn foo(self) -> u128; } | ||
3013 | struct S; | ||
3014 | impl Clone for S {} | ||
3015 | impl<T> Trait for T where T: Clone {} | ||
3016 | fn test<T: Clone>(t: T) { t.foo()<|>; } | ||
3017 | "#, | ||
3018 | ); | ||
3019 | assert_eq!(t, "u128"); | ||
3020 | } | ||
3021 | |||
3022 | #[test] | ||
3023 | fn generic_param_env_1_not_met() { | ||
3024 | let t = type_at( | ||
3025 | r#" | ||
3026 | //- /main.rs | ||
3027 | trait Clone {} | ||
3028 | trait Trait { fn foo(self) -> u128; } | ||
3029 | struct S; | ||
3030 | impl Clone for S {} | ||
3031 | impl<T> Trait for T where T: Clone {} | ||
3032 | fn test<T>(t: T) { t.foo()<|>; } | ||
3033 | "#, | ||
3034 | ); | ||
3035 | assert_eq!(t, "{unknown}"); | ||
3036 | } | ||
3037 | |||
3038 | #[test] | ||
3039 | fn generic_param_env_2() { | ||
3040 | let t = type_at( | ||
3041 | r#" | ||
3042 | //- /main.rs | ||
3043 | trait Trait { fn foo(self) -> u128; } | ||
3044 | struct S; | ||
3045 | impl Trait for S {} | ||
3046 | fn test<T: Trait>(t: T) { t.foo()<|>; } | ||
3047 | "#, | ||
3048 | ); | ||
3049 | assert_eq!(t, "u128"); | ||
3050 | } | ||
3051 | |||
3052 | #[test] | ||
3053 | fn generic_param_env_2_not_met() { | ||
3054 | let t = type_at( | ||
3055 | r#" | ||
3056 | //- /main.rs | ||
3057 | trait Trait { fn foo(self) -> u128; } | ||
3058 | struct S; | ||
3059 | impl Trait for S {} | ||
3060 | fn test<T>(t: T) { t.foo()<|>; } | ||
3061 | "#, | ||
3062 | ); | ||
3063 | assert_eq!(t, "{unknown}"); | ||
3064 | } | ||
3065 | |||
3066 | #[test] | ||
3067 | fn generic_param_env_deref() { | ||
3068 | let t = type_at( | ||
3069 | r#" | ||
3070 | //- /main.rs | ||
3071 | #[lang = "deref"] | ||
3072 | trait Deref { | ||
3073 | type Target; | ||
3074 | } | ||
3075 | trait Trait {} | ||
3076 | impl<T> Deref for T where T: Trait { | ||
3077 | type Target = i128; | ||
3078 | } | ||
3079 | fn test<T: Trait>(t: T) { (*t)<|>; } | ||
3080 | "#, | ||
3081 | ); | ||
3082 | assert_eq!(t, "i128"); | ||
3083 | } | ||
3084 | |||
3006 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3085 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
3007 | let file = db.parse(pos.file_id).ok().unwrap(); | 3086 | let file = db.parse(pos.file_id).ok().unwrap(); |
3008 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 3087 | 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 3e28852b6..d99843319 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -67,10 +67,33 @@ fn solve( | |||
67 | solution | 67 | solution |
68 | } | 68 | } |
69 | 69 | ||
70 | /// A set of clauses that we assume to be true. E.g. if we are inside this function: | ||
71 | /// ```rust | ||
72 | /// fn foo<T: Default>(t: T) {} | ||
73 | /// ``` | ||
74 | /// we assume that `T: Default`. | ||
75 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
76 | pub struct Environment { | ||
77 | pub predicates: Vec<GenericPredicate>, | ||
78 | } | ||
79 | |||
80 | /// Something (usually a goal), along with an environment. | ||
81 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
82 | pub struct InEnvironment<T> { | ||
83 | pub environment: Arc<Environment>, | ||
84 | pub value: T, | ||
85 | } | ||
86 | |||
87 | impl<T> InEnvironment<T> { | ||
88 | pub fn new(environment: Arc<Environment>, value: T) -> InEnvironment<T> { | ||
89 | InEnvironment { environment, value } | ||
90 | } | ||
91 | } | ||
92 | |||
70 | /// Something that needs to be proven (by Chalk) during type checking, e.g. that | 93 | /// Something that needs to be proven (by Chalk) during type checking, e.g. that |
71 | /// a certain type implements a certain trait. Proving the Obligation might | 94 | /// a certain type implements a certain trait. Proving the Obligation might |
72 | /// result in additional information about inference variables. | 95 | /// result in additional information about inference variables. |
73 | #[derive(Clone, Debug, PartialEq, Eq)] | 96 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
74 | pub enum Obligation { | 97 | pub enum Obligation { |
75 | /// Prove that a certain type implements a trait (the type is the `Self` type | 98 | /// Prove that a certain type implements a trait (the type is the `Self` type |
76 | /// parameter to the `TraitRef`). | 99 | /// parameter to the `TraitRef`). |
@@ -93,44 +116,14 @@ pub struct ProjectionPredicate { | |||
93 | pub ty: Ty, | 116 | pub ty: Ty, |
94 | } | 117 | } |
95 | 118 | ||
96 | /// Check using Chalk whether trait is implemented for given parameters including `Self` type. | 119 | /// Solve a trait goal using Chalk. |
97 | pub(crate) fn implements_query( | 120 | pub(crate) fn solve_query( |
98 | db: &impl HirDatabase, | 121 | db: &impl HirDatabase, |
99 | krate: Crate, | 122 | krate: Crate, |
100 | trait_ref: Canonical<TraitRef>, | 123 | trait_ref: Canonical<InEnvironment<Obligation>>, |
101 | ) -> Option<Solution> { | 124 | ) -> Option<Solution> { |
102 | let _p = profile("implements_query"); | 125 | let _p = profile("implements_query"); |
103 | let goal: chalk_ir::Goal = trait_ref.value.to_chalk(db).cast(); | 126 | let canonical = trait_ref.to_chalk(db).cast(); |
104 | debug!("goal: {:?}", goal); | ||
105 | let env = chalk_ir::Environment::new(); | ||
106 | let in_env = chalk_ir::InEnvironment::new(&env, goal); | ||
107 | let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT); | ||
108 | let canonical = | ||
109 | chalk_ir::Canonical { value: in_env, binders: vec![parameter; trait_ref.num_vars] }; | ||
110 | // We currently don't deal with universes (I think / hope they're not yet | ||
111 | // relevant for our use cases?) | ||
112 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; | ||
113 | let solution = solve(db, krate, &u_canonical); | ||
114 | solution.map(|solution| solution_from_chalk(db, solution)) | ||
115 | } | ||
116 | |||
117 | pub(crate) fn normalize_query( | ||
118 | db: &impl HirDatabase, | ||
119 | krate: Crate, | ||
120 | projection: Canonical<ProjectionPredicate>, | ||
121 | ) -> Option<Solution> { | ||
122 | let goal: chalk_ir::Goal = chalk_ir::Normalize { | ||
123 | projection: projection.value.projection_ty.to_chalk(db), | ||
124 | ty: projection.value.ty.to_chalk(db), | ||
125 | } | ||
126 | .cast(); | ||
127 | debug!("goal: {:?}", goal); | ||
128 | // FIXME unify with `implements` | ||
129 | let env = chalk_ir::Environment::new(); | ||
130 | let in_env = chalk_ir::InEnvironment::new(&env, goal); | ||
131 | let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT); | ||
132 | let canonical = | ||
133 | chalk_ir::Canonical { value: in_env, binders: vec![parameter; projection.num_vars] }; | ||
134 | // We currently don't deal with universes (I think / hope they're not yet | 127 | // We currently don't deal with universes (I think / hope they're not yet |
135 | // relevant for our use cases?) | 128 | // relevant for our use cases?) |
136 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; | 129 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 4c3744b44..2df4dd13f 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -12,7 +12,7 @@ use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; | |||
12 | use ra_db::salsa::{InternId, InternKey}; | 12 | use ra_db::salsa::{InternId, InternKey}; |
13 | use test_utils::tested_by; | 13 | use test_utils::tested_by; |
14 | 14 | ||
15 | use super::ChalkContext; | 15 | use super::{Canonical, ChalkContext, Obligation}; |
16 | use crate::{ | 16 | use crate::{ |
17 | db::HirDatabase, | 17 | db::HirDatabase, |
18 | generics::GenericDef, | 18 | generics::GenericDef, |
@@ -218,6 +218,103 @@ impl ToChalk for ProjectionTy { | |||
218 | } | 218 | } |
219 | } | 219 | } |
220 | 220 | ||
221 | impl ToChalk for super::ProjectionPredicate { | ||
222 | type Chalk = chalk_ir::Normalize; | ||
223 | |||
224 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize { | ||
225 | chalk_ir::Normalize { | ||
226 | projection: self.projection_ty.to_chalk(db), | ||
227 | ty: self.ty.to_chalk(db), | ||
228 | } | ||
229 | } | ||
230 | |||
231 | fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self { | ||
232 | unimplemented!() | ||
233 | } | ||
234 | } | ||
235 | |||
236 | impl ToChalk for Obligation { | ||
237 | type Chalk = chalk_ir::DomainGoal; | ||
238 | |||
239 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal { | ||
240 | match self { | ||
241 | Obligation::Trait(tr) => tr.to_chalk(db).cast(), | ||
242 | Obligation::Projection(pr) => pr.to_chalk(db).cast(), | ||
243 | } | ||
244 | } | ||
245 | |||
246 | fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self { | ||
247 | unimplemented!() | ||
248 | } | ||
249 | } | ||
250 | |||
251 | impl<T> ToChalk for Canonical<T> | ||
252 | where | ||
253 | T: ToChalk, | ||
254 | { | ||
255 | type Chalk = chalk_ir::Canonical<T::Chalk>; | ||
256 | |||
257 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | ||
258 | let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT); | ||
259 | let value = self.value.to_chalk(db); | ||
260 | let canonical = chalk_ir::Canonical { value, binders: vec![parameter; self.num_vars] }; | ||
261 | canonical | ||
262 | } | ||
263 | |||
264 | fn from_chalk(db: &impl HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | ||
265 | Canonical { num_vars: canonical.binders.len(), value: from_chalk(db, canonical.value) } | ||
266 | } | ||
267 | } | ||
268 | |||
269 | impl ToChalk for Arc<super::Environment> { | ||
270 | type Chalk = Arc<chalk_ir::Environment>; | ||
271 | |||
272 | fn to_chalk(self, db: &impl HirDatabase) -> Arc<chalk_ir::Environment> { | ||
273 | let mut clauses = Vec::new(); | ||
274 | for pred in &self.predicates { | ||
275 | if pred.is_error() { | ||
276 | // for env, we just ignore errors | ||
277 | continue; | ||
278 | } | ||
279 | if let GenericPredicate::Implemented(trait_ref) = pred { | ||
280 | if blacklisted_trait(db, trait_ref.trait_) { | ||
281 | continue; | ||
282 | } | ||
283 | } | ||
284 | clauses.push(pred.clone().to_chalk(db).cast()); | ||
285 | } | ||
286 | chalk_ir::Environment::new().add_clauses(clauses) | ||
287 | } | ||
288 | |||
289 | fn from_chalk( | ||
290 | _db: &impl HirDatabase, | ||
291 | _env: Arc<chalk_ir::Environment>, | ||
292 | ) -> Arc<super::Environment> { | ||
293 | unimplemented!() | ||
294 | } | ||
295 | } | ||
296 | |||
297 | impl<T: ToChalk> ToChalk for super::InEnvironment<T> { | ||
298 | type Chalk = chalk_ir::InEnvironment<T::Chalk>; | ||
299 | |||
300 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { | ||
301 | chalk_ir::InEnvironment { | ||
302 | environment: self.environment.to_chalk(db), | ||
303 | goal: self.value.to_chalk(db), | ||
304 | } | ||
305 | } | ||
306 | |||
307 | fn from_chalk( | ||
308 | db: &impl HirDatabase, | ||
309 | in_env: chalk_ir::InEnvironment<T::Chalk>, | ||
310 | ) -> super::InEnvironment<T> { | ||
311 | super::InEnvironment { | ||
312 | environment: from_chalk(db, in_env.environment), | ||
313 | value: from_chalk(db, in_env.goal), | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | |||
221 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | 318 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { |
222 | chalk_ir::Binders { | 319 | chalk_ir::Binders { |
223 | value, | 320 | value, |