diff options
author | Florian Diebold <[email protected]> | 2019-06-29 16:40:00 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-07-08 20:20:17 +0100 |
commit | 638100dc8bea69cc4093d15f1641ed39a8d27a43 (patch) | |
tree | bb7cf46f4095e9e427f7d4277f28693a3bd671a6 /crates/ra_hir/src/ty | |
parent | 32100022010ecfefd1ea06caa71d1a508d2eb75d (diff) |
Refactor a bit & introduce Environment struct
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 56 |
5 files changed, 105 insertions, 19 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 52a49070a..84edd3d46 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -29,7 +29,8 @@ use test_utils::tested_by; | |||
29 | use super::{ | 29 | use super::{ |
30 | autoderef, method_resolution, op, primitive, | 30 | autoderef, 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, InEnvironment, ProjectionTy, Substs, TraitRef, Ty, TypableDef, |
33 | TypeCtor, | ||
33 | }; | 34 | }; |
34 | use crate::{ | 35 | use crate::{ |
35 | adt::VariantDef, | 36 | adt::VariantDef, |
@@ -330,7 +331,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
330 | for obligation in obligations { | 331 | for obligation in obligations { |
331 | match &obligation { | 332 | match &obligation { |
332 | Obligation::Trait(tr) => { | 333 | Obligation::Trait(tr) => { |
333 | let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone()); | 334 | let env = Arc::new(super::Environment); // FIXME add environment |
335 | let in_env = InEnvironment::new(env, tr.clone()); | ||
336 | let canonicalized = self.canonicalizer().canonicalize_trait_ref(in_env); | ||
334 | let solution = self | 337 | let solution = self |
335 | .db | 338 | .db |
336 | .implements(self.resolver.krate().unwrap(), canonicalized.value.clone()); | 339 | .implements(self.resolver.krate().unwrap(), canonicalized.value.clone()); |
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index a24e5eb5c..ad2eefcaf 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs | |||
@@ -2,7 +2,9 @@ | |||
2 | 2 | ||
3 | use super::InferenceContext; | 3 | use super::InferenceContext; |
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,14 +107,24 @@ where | |||
105 | ProjectionPredicate { ty, projection_ty } | 107 | ProjectionPredicate { ty, projection_ty } |
106 | } | 108 | } |
107 | 109 | ||
110 | // FIXME: add some point, we need to introduce a `Fold` trait that abstracts | ||
111 | // over all the things that can be canonicalized (like Chalk and rustc have) | ||
112 | |||
108 | pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | 113 | pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { |
109 | let result = self.do_canonicalize_ty(ty); | 114 | let result = self.do_canonicalize_ty(ty); |
110 | self.into_canonicalized(result) | 115 | self.into_canonicalized(result) |
111 | } | 116 | } |
112 | 117 | ||
113 | pub fn canonicalize_trait_ref(mut self, trait_ref: TraitRef) -> Canonicalized<TraitRef> { | 118 | pub fn canonicalize_trait_ref( |
114 | let result = self.do_canonicalize_trait_ref(trait_ref); | 119 | mut self, |
115 | self.into_canonicalized(result) | 120 | trait_ref_in_env: InEnvironment<TraitRef>, |
121 | ) -> Canonicalized<InEnvironment<TraitRef>> { | ||
122 | let result = self.do_canonicalize_trait_ref(trait_ref_in_env.value); | ||
123 | // FIXME canonicalize env | ||
124 | self.into_canonicalized(InEnvironment { | ||
125 | value: result, | ||
126 | environment: trait_ref_in_env.environment, | ||
127 | }) | ||
116 | } | 128 | } |
117 | 129 | ||
118 | pub fn canonicalize_projection( | 130 | pub fn canonicalize_projection( |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 76ace66ea..770e1964e 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, 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}, |
@@ -209,7 +209,8 @@ fn iterate_trait_method_candidates<T>( | |||
209 | let data = m.data(db); | 209 | let data = m.data(db); |
210 | if name.map_or(true, |name| data.name() == name) && data.has_self_param() { | 210 | if name.map_or(true, |name| data.name() == name) && data.has_self_param() { |
211 | if !known_implemented { | 211 | if !known_implemented { |
212 | let trait_ref = canonical_trait_ref(db, t, ty.clone()); | 212 | let env = Arc::new(super::Environment); // FIXME add environment |
213 | let trait_ref = canonical_trait_ref(db, env, t, ty.clone()); | ||
213 | if db.implements(krate, trait_ref).is_none() { | 214 | if db.implements(krate, trait_ref).is_none() { |
214 | continue 'traits; | 215 | continue 'traits; |
215 | } | 216 | } |
@@ -279,9 +280,10 @@ impl Ty { | |||
279 | /// for all other parameters, to query Chalk with it. | 280 | /// for all other parameters, to query Chalk with it. |
280 | fn canonical_trait_ref( | 281 | fn canonical_trait_ref( |
281 | db: &impl HirDatabase, | 282 | db: &impl HirDatabase, |
283 | env: Arc<Environment>, | ||
282 | trait_: Trait, | 284 | trait_: Trait, |
283 | self_ty: Canonical<Ty>, | 285 | self_ty: Canonical<Ty>, |
284 | ) -> Canonical<TraitRef> { | 286 | ) -> Canonical<InEnvironment<TraitRef>> { |
285 | let mut substs = Vec::new(); | 287 | let mut substs = Vec::new(); |
286 | let generics = trait_.generic_params(db); | 288 | let generics = trait_.generic_params(db); |
287 | let num_vars = self_ty.num_vars; | 289 | let num_vars = self_ty.num_vars; |
@@ -296,6 +298,6 @@ fn canonical_trait_ref( | |||
296 | ); | 298 | ); |
297 | Canonical { | 299 | Canonical { |
298 | num_vars: substs.len() - 1 + self_ty.num_vars, | 300 | num_vars: substs.len() - 1 + self_ty.num_vars, |
299 | value: TraitRef { trait_, substs: substs.into() }, | 301 | value: InEnvironment::new(env, TraitRef { trait_, substs: substs.into() }), |
300 | } | 302 | } |
301 | } | 303 | } |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 3e28852b6..718970553 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -67,6 +67,27 @@ 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, PartialOrd, Ord)] | ||
76 | pub struct Environment; | ||
77 | |||
78 | /// Something (usually a goal), along with an environment. | ||
79 | #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
80 | pub struct InEnvironment<T> { | ||
81 | pub environment: Arc<Environment>, | ||
82 | pub value: T, | ||
83 | } | ||
84 | |||
85 | impl<T> InEnvironment<T> { | ||
86 | pub fn new(environment: Arc<Environment>, value: T) -> InEnvironment<T> { | ||
87 | InEnvironment { environment, value } | ||
88 | } | ||
89 | } | ||
90 | |||
70 | /// Something that needs to be proven (by Chalk) during type checking, e.g. that | 91 | /// 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 | 92 | /// a certain type implements a certain trait. Proving the Obligation might |
72 | /// result in additional information about inference variables. | 93 | /// result in additional information about inference variables. |
@@ -97,16 +118,10 @@ pub struct ProjectionPredicate { | |||
97 | pub(crate) fn implements_query( | 118 | pub(crate) fn implements_query( |
98 | db: &impl HirDatabase, | 119 | db: &impl HirDatabase, |
99 | krate: Crate, | 120 | krate: Crate, |
100 | trait_ref: Canonical<TraitRef>, | 121 | trait_ref: Canonical<InEnvironment<TraitRef>>, |
101 | ) -> Option<Solution> { | 122 | ) -> Option<Solution> { |
102 | let _p = profile("implements_query"); | 123 | let _p = profile("implements_query"); |
103 | let goal: chalk_ir::Goal = trait_ref.value.to_chalk(db).cast(); | 124 | 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 | 125 | // We currently don't deal with universes (I think / hope they're not yet |
111 | // relevant for our use cases?) | 126 | // relevant for our use cases?) |
112 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; | 127 | 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..bee35fa62 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}; |
16 | use crate::{ | 16 | use crate::{ |
17 | db::HirDatabase, | 17 | db::HirDatabase, |
18 | generics::GenericDef, | 18 | generics::GenericDef, |
@@ -218,6 +218,60 @@ impl ToChalk for ProjectionTy { | |||
218 | } | 218 | } |
219 | } | 219 | } |
220 | 220 | ||
221 | impl<T> ToChalk for Canonical<T> | ||
222 | where | ||
223 | T: ToChalk, | ||
224 | { | ||
225 | type Chalk = chalk_ir::Canonical<T::Chalk>; | ||
226 | |||
227 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | ||
228 | let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT); | ||
229 | let value = self.value.to_chalk(db); | ||
230 | let canonical = chalk_ir::Canonical { value, binders: vec![parameter; self.num_vars] }; | ||
231 | canonical | ||
232 | } | ||
233 | |||
234 | fn from_chalk(db: &impl HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | ||
235 | Canonical { num_vars: canonical.binders.len(), value: from_chalk(db, canonical.value) } | ||
236 | } | ||
237 | } | ||
238 | |||
239 | impl ToChalk for Arc<super::Environment> { | ||
240 | type Chalk = Arc<chalk_ir::Environment>; | ||
241 | |||
242 | fn to_chalk(self, _db: &impl HirDatabase) -> Arc<chalk_ir::Environment> { | ||
243 | chalk_ir::Environment::new() | ||
244 | } | ||
245 | |||
246 | fn from_chalk( | ||
247 | _db: &impl HirDatabase, | ||
248 | _env: Arc<chalk_ir::Environment>, | ||
249 | ) -> Arc<super::Environment> { | ||
250 | Arc::new(super::Environment) | ||
251 | } | ||
252 | } | ||
253 | |||
254 | impl<T: ToChalk> ToChalk for super::InEnvironment<T> { | ||
255 | type Chalk = chalk_ir::InEnvironment<T::Chalk>; | ||
256 | |||
257 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { | ||
258 | chalk_ir::InEnvironment { | ||
259 | environment: self.environment.to_chalk(db), | ||
260 | goal: self.value.to_chalk(db), | ||
261 | } | ||
262 | } | ||
263 | |||
264 | fn from_chalk( | ||
265 | db: &impl HirDatabase, | ||
266 | in_env: chalk_ir::InEnvironment<T::Chalk>, | ||
267 | ) -> super::InEnvironment<T> { | ||
268 | super::InEnvironment { | ||
269 | environment: from_chalk(db, in_env.environment), | ||
270 | value: from_chalk(db, in_env.goal), | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
221 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | 275 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { |
222 | chalk_ir::Binders { | 276 | chalk_ir::Binders { |
223 | value, | 277 | value, |