aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-07-09 08:50:18 +0100
committerbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-07-09 08:50:18 +0100
commitf59cd1a4a0d6c369025a7014e838d25f91d478e4 (patch)
tree2c4b9dc868a87507ed63e9dc46530cc60f38ae64
parent35f28c538a9b9f461bb4db1a78d02e9f02a3d296 (diff)
parent9afbf2dff43dee3227358f10162d4c77d192ce7a (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]>
-rw-r--r--crates/ra_hir/src/db.rs13
-rw-r--r--crates/ra_hir/src/ty.rs2
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs10
-rw-r--r--crates/ra_hir/src/ty/infer.rs69
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs34
-rw-r--r--crates/ra_hir/src/ty/lower.rs12
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs21
-rw-r--r--crates/ra_hir/src/ty/tests.rs79
-rw-r--r--crates/ra_hir/src/ty/traits.rs63
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs99
-rw-r--r--crates/ra_ide_api/src/change.rs3
11 files changed, 286 insertions, 119 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 0e6e3fdb7..b0c027631 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -213,18 +213,11 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
213 #[salsa::invoke(crate::ty::traits::chalk::impl_datum_query)] 213 #[salsa::invoke(crate::ty::traits::chalk::impl_datum_query)]
214 fn impl_datum(&self, krate: Crate, impl_id: chalk_ir::ImplId) -> Arc<chalk_rust_ir::ImplDatum>; 214 fn impl_datum(&self, krate: Crate, impl_id: chalk_ir::ImplId) -> Arc<chalk_rust_ir::ImplDatum>;
215 215
216 #[salsa::invoke(crate::ty::traits::implements_query)] 216 #[salsa::invoke(crate::ty::traits::solve_query)]
217 fn implements( 217 fn solve(
218 &self, 218 &self,
219 krate: Crate, 219 krate: Crate,
220 goal: crate::ty::Canonical<crate::ty::TraitRef>, 220 goal: crate::ty::Canonical<crate::ty::InEnvironment<crate::ty::Obligation>>,
221 ) -> Option<crate::ty::traits::Solution>;
222
223 #[salsa::invoke(crate::ty::traits::normalize_query)]
224 fn normalize(
225 &self,
226 krate: Crate,
227 goal: crate::ty::Canonical<crate::ty::ProjectionPredicate>,
228 ) -> Option<crate::ty::traits::Solution>; 221 ) -> Option<crate::ty::traits::Solution>;
229} 222}
230 223
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index d8c7945e1..9accffcbc 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -26,7 +26,7 @@ pub(crate) use lower::{
26 callable_item_sig, generic_defaults_query, generic_predicates_query, type_for_def, 26 callable_item_sig, generic_defaults_query, generic_predicates_query, type_for_def,
27 type_for_field, TypableDef, 27 type_for_field, TypableDef,
28}; 28};
29pub(crate) use traits::ProjectionPredicate; 29pub(crate) use traits::{Environment, InEnvironment, Obligation, ProjectionPredicate};
30 30
31/// A type constructor or type name: this might be something like the primitive 31/// A type constructor or type name: this might be something like the primitive
32/// type `bool`, a struct like `Vec`, or things like function pointers or 32/// type `bool`, a struct like `Vec`, or things like function pointers or
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;
27use test_utils::tested_by; 27use test_utils::tested_by;
28 28
29use super::{ 29use 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};
34use crate::{ 35use 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
3use super::InferenceContext; 3use super::{InferenceContext, Obligation};
4use crate::db::HirDatabase; 4use crate::db::HirDatabase;
5use crate::ty::{Canonical, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty}; 5use crate::ty::{
6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty,
7};
6 8
7impl<'a, D: HirDatabase> InferenceContext<'a, D> { 9impl<'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
320pub(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.
321pub(crate) fn generic_predicates_query( 333pub(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;
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9 9
10use super::{autoderef, Canonical, TraitRef}; 10use super::{autoderef, lower, Canonical, Environment, InEnvironment, TraitRef};
11use crate::{ 11use 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.
282fn canonical_trait_ref( 284fn 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]
3007fn generic_param_env_1() {
3008 let t = type_at(
3009 r#"
3010//- /main.rs
3011trait Clone {}
3012trait Trait { fn foo(self) -> u128; }
3013struct S;
3014impl Clone for S {}
3015impl<T> Trait for T where T: Clone {}
3016fn test<T: Clone>(t: T) { t.foo()<|>; }
3017"#,
3018 );
3019 assert_eq!(t, "u128");
3020}
3021
3022#[test]
3023fn generic_param_env_1_not_met() {
3024 let t = type_at(
3025 r#"
3026//- /main.rs
3027trait Clone {}
3028trait Trait { fn foo(self) -> u128; }
3029struct S;
3030impl Clone for S {}
3031impl<T> Trait for T where T: Clone {}
3032fn test<T>(t: T) { t.foo()<|>; }
3033"#,
3034 );
3035 assert_eq!(t, "{unknown}");
3036}
3037
3038#[test]
3039fn generic_param_env_2() {
3040 let t = type_at(
3041 r#"
3042//- /main.rs
3043trait Trait { fn foo(self) -> u128; }
3044struct S;
3045impl Trait for S {}
3046fn test<T: Trait>(t: T) { t.foo()<|>; }
3047"#,
3048 );
3049 assert_eq!(t, "u128");
3050}
3051
3052#[test]
3053fn generic_param_env_2_not_met() {
3054 let t = type_at(
3055 r#"
3056//- /main.rs
3057trait Trait { fn foo(self) -> u128; }
3058struct S;
3059impl Trait for S {}
3060fn test<T>(t: T) { t.foo()<|>; }
3061"#,
3062 );
3063 assert_eq!(t, "{unknown}");
3064}
3065
3066#[test]
3067fn generic_param_env_deref() {
3068 let t = type_at(
3069 r#"
3070//- /main.rs
3071#[lang = "deref"]
3072trait Deref {
3073 type Target;
3074}
3075trait Trait {}
3076impl<T> Deref for T where T: Trait {
3077 type Target = i128;
3078}
3079fn test<T: Trait>(t: T) { (*t)<|>; }
3080"#,
3081 );
3082 assert_eq!(t, "i128");
3083}
3084
3006fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 3085fn 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)]
76pub 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)]
82pub struct InEnvironment<T> {
83 pub environment: Arc<Environment>,
84 pub value: T,
85}
86
87impl<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)]
74pub enum Obligation { 97pub 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.
97pub(crate) fn implements_query( 120pub(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
117pub(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};
12use ra_db::salsa::{InternId, InternKey}; 12use ra_db::salsa::{InternId, InternKey};
13use test_utils::tested_by; 13use test_utils::tested_by;
14 14
15use super::ChalkContext; 15use super::{Canonical, ChalkContext, Obligation};
16use crate::{ 16use 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
221impl 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
236impl 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
251impl<T> ToChalk for Canonical<T>
252where
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
269impl 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
297impl<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
221fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 318fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
222 chalk_ir::Binders { 319 chalk_ir::Binders {
223 value, 320 value,
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 2a1af0a0a..efc9a92de 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -295,8 +295,7 @@ impl RootDatabase {
295 hir::db::TraitDatumQuery 295 hir::db::TraitDatumQuery
296 hir::db::StructDatumQuery 296 hir::db::StructDatumQuery
297 hir::db::ImplDatumQuery 297 hir::db::ImplDatumQuery
298 hir::db::ImplementsQuery 298 hir::db::SolveQuery
299 hir::db::NormalizeQuery
300 ]; 299 ];
301 acc.sort_by_key(|it| std::cmp::Reverse(it.1)); 300 acc.sort_by_key(|it| std::cmp::Reverse(it.1));
302 acc 301 acc