diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-01 19:41:06 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-01 19:41:06 +0100 |
commit | a33eefa3b26000b3018e6bb873f18dbe15ab4ab7 (patch) | |
tree | da55aac24be34db6750e6675673317f52e7db4dc | |
parent | ec1d1a1b709a6eafff07077cdf75291d01cda3b6 (diff) | |
parent | d5d485ef9289589332893f2c0ad96cb366afe9d6 (diff) |
Merge #5149
5149: Implement Chalk variable kinds r=flodiebold a=flodiebold
This means we need to keep track of the kinds (general/int/float) of variables in `Canonical`, which requires some more ceremony. (It also exposes some places where we're not really dealing with canonicalization correctly -- another thing to be cleaned up when we switch to using Chalk's types directly.)
Should fix the last remaining issue of #2534.
Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/autoderef.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 55 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 32 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk/mapping.rs | 43 |
8 files changed, 140 insertions, 71 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index cc72964ff..1b3525011 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -1189,7 +1189,7 @@ impl Type { | |||
1189 | None => return false, | 1189 | None => return false, |
1190 | }; | 1190 | }; |
1191 | 1191 | ||
1192 | let canonical_ty = Canonical { value: self.ty.value.clone(), num_vars: 0 }; | 1192 | let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; |
1193 | method_resolution::implements_trait( | 1193 | method_resolution::implements_trait( |
1194 | &canonical_ty, | 1194 | &canonical_ty, |
1195 | db, | 1195 | db, |
@@ -1213,7 +1213,7 @@ impl Type { | |||
1213 | self.ty.environment.clone(), | 1213 | self.ty.environment.clone(), |
1214 | hir_ty::Obligation::Trait(trait_ref), | 1214 | hir_ty::Obligation::Trait(trait_ref), |
1215 | ), | 1215 | ), |
1216 | num_vars: 0, | 1216 | kinds: Arc::new([]), |
1217 | }; | 1217 | }; |
1218 | 1218 | ||
1219 | db.trait_solve(self.krate, goal).is_some() | 1219 | db.trait_solve(self.krate, goal).is_some() |
@@ -1288,7 +1288,7 @@ impl Type { | |||
1288 | pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { | 1288 | pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { |
1289 | // There should be no inference vars in types passed here | 1289 | // There should be no inference vars in types passed here |
1290 | // FIXME check that? | 1290 | // FIXME check that? |
1291 | let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; | 1291 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; |
1292 | let environment = self.ty.environment.clone(); | 1292 | let environment = self.ty.environment.clone(); |
1293 | let ty = InEnvironment { value: canonical, environment }; | 1293 | let ty = InEnvironment { value: canonical, environment }; |
1294 | autoderef(db, Some(self.krate), ty) | 1294 | autoderef(db, Some(self.krate), ty) |
@@ -1329,7 +1329,7 @@ impl Type { | |||
1329 | // There should be no inference vars in types passed here | 1329 | // There should be no inference vars in types passed here |
1330 | // FIXME check that? | 1330 | // FIXME check that? |
1331 | // FIXME replace Unknown by bound vars here | 1331 | // FIXME replace Unknown by bound vars here |
1332 | let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; | 1332 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; |
1333 | 1333 | ||
1334 | let env = self.ty.environment.clone(); | 1334 | let env = self.ty.environment.clone(); |
1335 | let krate = krate.id; | 1335 | let krate = krate.id; |
@@ -1360,7 +1360,7 @@ impl Type { | |||
1360 | // There should be no inference vars in types passed here | 1360 | // There should be no inference vars in types passed here |
1361 | // FIXME check that? | 1361 | // FIXME check that? |
1362 | // FIXME replace Unknown by bound vars here | 1362 | // FIXME replace Unknown by bound vars here |
1363 | let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; | 1363 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; |
1364 | 1364 | ||
1365 | let env = self.ty.environment.clone(); | 1365 | let env = self.ty.environment.clone(); |
1366 | let krate = krate.id; | 1366 | let krate = krate.id; |
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs index 1b0f84c5c..c727012c6 100644 --- a/crates/ra_hir_ty/src/autoderef.rs +++ b/crates/ra_hir_ty/src/autoderef.rs | |||
@@ -37,7 +37,7 @@ pub(crate) fn deref( | |||
37 | ty: InEnvironment<&Canonical<Ty>>, | 37 | ty: InEnvironment<&Canonical<Ty>>, |
38 | ) -> Option<Canonical<Ty>> { | 38 | ) -> Option<Canonical<Ty>> { |
39 | if let Some(derefed) = ty.value.value.builtin_deref() { | 39 | if let Some(derefed) = ty.value.value.builtin_deref() { |
40 | Some(Canonical { value: derefed, num_vars: ty.value.num_vars }) | 40 | Some(Canonical { value: derefed, kinds: ty.value.kinds.clone() }) |
41 | } else { | 41 | } else { |
42 | deref_by_trait(db, krate, ty) | 42 | deref_by_trait(db, krate, ty) |
43 | } | 43 | } |
@@ -68,8 +68,8 @@ fn deref_by_trait( | |||
68 | 68 | ||
69 | // Check that the type implements Deref at all | 69 | // Check that the type implements Deref at all |
70 | let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; | 70 | let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; |
71 | let implements_goal = super::Canonical { | 71 | let implements_goal = Canonical { |
72 | num_vars: ty.value.num_vars, | 72 | kinds: ty.value.kinds.clone(), |
73 | value: InEnvironment { | 73 | value: InEnvironment { |
74 | value: Obligation::Trait(trait_ref), | 74 | value: Obligation::Trait(trait_ref), |
75 | environment: ty.environment.clone(), | 75 | environment: ty.environment.clone(), |
@@ -81,7 +81,7 @@ fn deref_by_trait( | |||
81 | 81 | ||
82 | // Now do the assoc type projection | 82 | // Now do the assoc type projection |
83 | let projection = super::traits::ProjectionPredicate { | 83 | let projection = super::traits::ProjectionPredicate { |
84 | ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)), | 84 | ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())), |
85 | projection_ty: super::ProjectionTy { associated_ty: target, parameters }, | 85 | projection_ty: super::ProjectionTy { associated_ty: target, parameters }, |
86 | }; | 86 | }; |
87 | 87 | ||
@@ -89,7 +89,8 @@ fn deref_by_trait( | |||
89 | 89 | ||
90 | let in_env = InEnvironment { value: obligation, environment: ty.environment }; | 90 | let in_env = InEnvironment { value: obligation, environment: ty.environment }; |
91 | 91 | ||
92 | let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; | 92 | let canonical = |
93 | Canonical::new(in_env, ty.value.kinds.iter().copied().chain(Some(super::TyKind::General))); | ||
93 | 94 | ||
94 | let solution = db.trait_solve(krate, canonical)?; | 95 | let solution = db.trait_solve(krate, canonical)?; |
95 | 96 | ||
@@ -110,7 +111,7 @@ fn deref_by_trait( | |||
110 | // assumptions will be broken. We would need to properly introduce | 111 | // assumptions will be broken. We would need to properly introduce |
111 | // new variables in that case | 112 | // new variables in that case |
112 | 113 | ||
113 | for i in 1..vars.0.num_vars { | 114 | for i in 1..vars.0.kinds.len() { |
114 | if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) | 115 | if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) |
115 | { | 116 | { |
116 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); | 117 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); |
@@ -119,7 +120,7 @@ fn deref_by_trait( | |||
119 | } | 120 | } |
120 | Some(Canonical { | 121 | Some(Canonical { |
121 | value: vars.0.value[vars.0.value.len() - 1].clone(), | 122 | value: vars.0.value[vars.0.value.len() - 1].clone(), |
122 | num_vars: vars.0.num_vars, | 123 | kinds: vars.0.kinds.clone(), |
123 | }) | 124 | }) |
124 | } | 125 | } |
125 | Solution::Ambig(_) => { | 126 | Solution::Ambig(_) => { |
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index 269495ca0..2e895d911 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -9,7 +9,7 @@ use test_utils::mark; | |||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use crate::{ |
11 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, | 11 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, |
12 | TypeCtor, TypeWalk, | 12 | TyKind, TypeCtor, TypeWalk, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | impl<'a> InferenceContext<'a> { | 15 | impl<'a> InferenceContext<'a> { |
@@ -86,10 +86,20 @@ where | |||
86 | } | 86 | } |
87 | 87 | ||
88 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { | 88 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { |
89 | Canonicalized { | 89 | let kinds = self |
90 | value: Canonical { value: result, num_vars: self.free_vars.len() }, | 90 | .free_vars |
91 | free_vars: self.free_vars, | 91 | .iter() |
92 | } | 92 | .map(|v| match v { |
93 | // mapping MaybeNeverTypeVar to the same kind as general ones | ||
94 | // should be fine, because as opposed to int or float type vars, | ||
95 | // they don't restrict what kind of type can go into them, they | ||
96 | // just affect fallback. | ||
97 | InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General, | ||
98 | InferTy::IntVar(_) => TyKind::Integer, | ||
99 | InferTy::FloatVar(_) => TyKind::Float, | ||
100 | }) | ||
101 | .collect(); | ||
102 | Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars } | ||
93 | } | 103 | } |
94 | 104 | ||
95 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | 105 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { |
@@ -131,26 +141,41 @@ impl<T> Canonicalized<T> { | |||
131 | ty | 141 | ty |
132 | } | 142 | } |
133 | 143 | ||
134 | pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Vec<Ty>>) { | 144 | pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Substs>) { |
135 | // the solution may contain new variables, which we need to convert to new inference vars | 145 | // the solution may contain new variables, which we need to convert to new inference vars |
136 | let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect()); | 146 | let new_vars = Substs( |
147 | solution | ||
148 | .kinds | ||
149 | .iter() | ||
150 | .map(|k| match k { | ||
151 | TyKind::General => ctx.table.new_type_var(), | ||
152 | TyKind::Integer => ctx.table.new_integer_var(), | ||
153 | TyKind::Float => ctx.table.new_float_var(), | ||
154 | }) | ||
155 | .collect(), | ||
156 | ); | ||
137 | for (i, ty) in solution.value.into_iter().enumerate() { | 157 | for (i, ty) in solution.value.into_iter().enumerate() { |
138 | let var = self.free_vars[i]; | 158 | let var = self.free_vars[i]; |
139 | // eagerly replace projections in the type; we may be getting types | 159 | // eagerly replace projections in the type; we may be getting types |
140 | // e.g. from where clauses where this hasn't happened yet | 160 | // e.g. from where clauses where this hasn't happened yet |
141 | let ty = ctx.normalize_associated_types_in(ty.subst_bound_vars(&new_vars)); | 161 | let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars)); |
142 | ctx.table.unify(&Ty::Infer(var), &ty); | 162 | ctx.table.unify(&Ty::Infer(var), &ty); |
143 | } | 163 | } |
144 | } | 164 | } |
145 | } | 165 | } |
146 | 166 | ||
147 | pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { | 167 | pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> { |
148 | let mut table = InferenceTable::new(); | 168 | let mut table = InferenceTable::new(); |
149 | let num_vars = ty1.num_vars.max(ty2.num_vars); | 169 | let vars = Substs( |
150 | let vars = | 170 | tys.kinds |
151 | Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); | 171 | .iter() |
152 | let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars); | 172 | // we always use type vars here because we want everything to |
153 | let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars); | 173 | // fallback to Unknown in the end (kind of hacky, as below) |
174 | .map(|_| table.new_type_var()) | ||
175 | .collect(), | ||
176 | ); | ||
177 | let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars); | ||
178 | let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars); | ||
154 | if !table.unify(&ty1_with_vars, &ty2_with_vars) { | 179 | if !table.unify(&ty1_with_vars, &ty2_with_vars) { |
155 | return None; | 180 | return None; |
156 | } | 181 | } |
@@ -162,7 +187,7 @@ pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { | |||
162 | } | 187 | } |
163 | } | 188 | } |
164 | Some( | 189 | Some( |
165 | Substs::builder(ty1.num_vars) | 190 | Substs::builder(tys.kinds.len()) |
166 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) | 191 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) |
167 | .build(), | 192 | .build(), |
168 | ) | 193 | ) |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index c9513b752..7f3f5e771 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -662,13 +662,27 @@ impl TypeWalk for GenericPredicate { | |||
662 | 662 | ||
663 | /// Basically a claim (currently not validated / checked) that the contained | 663 | /// Basically a claim (currently not validated / checked) that the contained |
664 | /// type / trait ref contains no inference variables; any inference variables it | 664 | /// type / trait ref contains no inference variables; any inference variables it |
665 | /// contained have been replaced by bound variables, and `num_vars` tells us how | 665 | /// contained have been replaced by bound variables, and `kinds` tells us how |
666 | /// many there are. This is used to erase irrelevant differences between types | 666 | /// many there are and whether they were normal or float/int variables. This is |
667 | /// before using them in queries. | 667 | /// used to erase irrelevant differences between types before using them in |
668 | /// queries. | ||
668 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 669 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
669 | pub struct Canonical<T> { | 670 | pub struct Canonical<T> { |
670 | pub value: T, | 671 | pub value: T, |
671 | pub num_vars: usize, | 672 | pub kinds: Arc<[TyKind]>, |
673 | } | ||
674 | |||
675 | impl<T> Canonical<T> { | ||
676 | pub fn new(value: T, kinds: impl IntoIterator<Item = TyKind>) -> Self { | ||
677 | Self { value, kinds: kinds.into_iter().collect() } | ||
678 | } | ||
679 | } | ||
680 | |||
681 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
682 | pub enum TyKind { | ||
683 | General, | ||
684 | Integer, | ||
685 | Float, | ||
672 | } | 686 | } |
673 | 687 | ||
674 | /// A function signature as seen by type inference: Several parameter types and | 688 | /// A function signature as seen by type inference: Several parameter types and |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 5dbabd12b..a45febbf7 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | //! For details about how this works in rustc, see the method lookup page in the | 2 | //! For details about how this works in rustc, see the method lookup page in the |
3 | //! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) | 3 | //! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) |
4 | //! and the corresponding code mostly in librustc_typeck/check/method/probe.rs. | 4 | //! and the corresponding code mostly in librustc_typeck/check/method/probe.rs. |
5 | use std::sync::Arc; | 5 | use std::{iter, sync::Arc}; |
6 | 6 | ||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use hir_def::{ | 8 | use hir_def::{ |
@@ -17,7 +17,8 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
17 | use super::Substs; | 17 | use super::Substs; |
18 | use crate::{ | 18 | use crate::{ |
19 | autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy, | 19 | autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy, |
20 | Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, | 20 | Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor, |
21 | TypeWalk, | ||
21 | }; | 22 | }; |
22 | 23 | ||
23 | /// This is used as a key for indexing impls. | 24 | /// This is used as a key for indexing impls. |
@@ -372,7 +373,7 @@ fn iterate_method_candidates_with_autoref( | |||
372 | return true; | 373 | return true; |
373 | } | 374 | } |
374 | let refed = Canonical { | 375 | let refed = Canonical { |
375 | num_vars: deref_chain[0].num_vars, | 376 | kinds: deref_chain[0].kinds.clone(), |
376 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), | 377 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), |
377 | }; | 378 | }; |
378 | if iterate_method_candidates_by_receiver( | 379 | if iterate_method_candidates_by_receiver( |
@@ -388,7 +389,7 @@ fn iterate_method_candidates_with_autoref( | |||
388 | return true; | 389 | return true; |
389 | } | 390 | } |
390 | let ref_muted = Canonical { | 391 | let ref_muted = Canonical { |
391 | num_vars: deref_chain[0].num_vars, | 392 | kinds: deref_chain[0].kinds.clone(), |
392 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), | 393 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), |
393 | }; | 394 | }; |
394 | if iterate_method_candidates_by_receiver( | 395 | if iterate_method_candidates_by_receiver( |
@@ -607,18 +608,19 @@ pub(crate) fn inherent_impl_substs( | |||
607 | // we create a var for each type parameter of the impl; we need to keep in | 608 | // we create a var for each type parameter of the impl; we need to keep in |
608 | // mind here that `self_ty` might have vars of its own | 609 | // mind here that `self_ty` might have vars of its own |
609 | let vars = Substs::build_for_def(db, impl_id) | 610 | let vars = Substs::build_for_def(db, impl_id) |
610 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.num_vars) | 611 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.kinds.len()) |
611 | .build(); | 612 | .build(); |
612 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); | 613 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); |
613 | let self_ty_with_vars = | 614 | let mut kinds = self_ty.kinds.to_vec(); |
614 | Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; | 615 | kinds.extend(iter::repeat(TyKind::General).take(vars.len())); |
615 | let substs = super::infer::unify(&self_ty_with_vars, self_ty); | 616 | let tys = Canonical { kinds: kinds.into(), value: (self_ty_with_vars, self_ty.value.clone()) }; |
617 | let substs = super::infer::unify(&tys); | ||
616 | // We only want the substs for the vars we added, not the ones from self_ty. | 618 | // We only want the substs for the vars we added, not the ones from self_ty. |
617 | // Also, if any of the vars we added are still in there, we replace them by | 619 | // Also, if any of the vars we added are still in there, we replace them by |
618 | // Unknown. I think this can only really happen if self_ty contained | 620 | // Unknown. I think this can only really happen if self_ty contained |
619 | // Unknown, and in that case we want the result to contain Unknown in those | 621 | // Unknown, and in that case we want the result to contain Unknown in those |
620 | // places again. | 622 | // places again. |
621 | substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.num_vars)) | 623 | substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len())) |
622 | } | 624 | } |
623 | 625 | ||
624 | /// This replaces any 'free' Bound vars in `s` (i.e. those with indices past | 626 | /// This replaces any 'free' Bound vars in `s` (i.e. those with indices past |
@@ -678,15 +680,15 @@ fn generic_implements_goal( | |||
678 | trait_: TraitId, | 680 | trait_: TraitId, |
679 | self_ty: Canonical<Ty>, | 681 | self_ty: Canonical<Ty>, |
680 | ) -> Canonical<InEnvironment<super::Obligation>> { | 682 | ) -> Canonical<InEnvironment<super::Obligation>> { |
681 | let num_vars = self_ty.num_vars; | 683 | let mut kinds = self_ty.kinds.to_vec(); |
682 | let substs = super::Substs::build_for_def(db, trait_) | 684 | let substs = super::Substs::build_for_def(db, trait_) |
683 | .push(self_ty.value) | 685 | .push(self_ty.value) |
684 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, num_vars) | 686 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) |
685 | .build(); | 687 | .build(); |
686 | let num_vars = substs.len() - 1 + self_ty.num_vars; | 688 | kinds.extend(iter::repeat(TyKind::General).take(substs.len() - 1)); |
687 | let trait_ref = TraitRef { trait_, substs }; | 689 | let trait_ref = TraitRef { trait_, substs }; |
688 | let obligation = super::Obligation::Trait(trait_ref); | 690 | let obligation = super::Obligation::Trait(trait_ref); |
689 | Canonical { num_vars, value: InEnvironment::new(env, obligation) } | 691 | Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) } |
690 | } | 692 | } |
691 | 693 | ||
692 | fn autoderef_method_receiver( | 694 | fn autoderef_method_receiver( |
@@ -699,9 +701,9 @@ fn autoderef_method_receiver( | |||
699 | if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = | 701 | if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = |
700 | deref_chain.last().map(|ty| &ty.value) | 702 | deref_chain.last().map(|ty| &ty.value) |
701 | { | 703 | { |
702 | let num_vars = deref_chain.last().unwrap().num_vars; | 704 | let kinds = deref_chain.last().unwrap().kinds.clone(); |
703 | let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); | 705 | let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); |
704 | deref_chain.push(Canonical { value: unsized_ty, num_vars }) | 706 | deref_chain.push(Canonical { value: unsized_ty, kinds }) |
705 | } | 707 | } |
706 | deref_chain | 708 | deref_chain |
707 | } | 709 | } |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 01c919a7e..766790576 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -3029,3 +3029,21 @@ fn infer_dyn_fn_output() { | |||
3029 | "### | 3029 | "### |
3030 | ); | 3030 | ); |
3031 | } | 3031 | } |
3032 | |||
3033 | #[test] | ||
3034 | fn variable_kinds() { | ||
3035 | check_types( | ||
3036 | r#" | ||
3037 | trait Trait<T> { fn get(self, t: T) -> T; } | ||
3038 | struct S; | ||
3039 | impl Trait<u128> for S {} | ||
3040 | impl Trait<f32> for S {} | ||
3041 | fn test() { | ||
3042 | S.get(1); | ||
3043 | //^^^^^^^^ u128 | ||
3044 | S.get(1.); | ||
3045 | //^^^^^^^^ f32 | ||
3046 | } | ||
3047 | "#, | ||
3048 | ); | ||
3049 | } | ||
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 6f43c3a22..2a6d7faef 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | //! Trait solving using Chalk. | 1 | //! Trait solving using Chalk. |
2 | use std::{panic, sync::Arc}; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use chalk_ir::cast::Cast; | 4 | use chalk_ir::cast::Cast; |
5 | use hir_def::{ | 5 | use hir_def::{ |
@@ -8,7 +8,7 @@ use hir_def::{ | |||
8 | use ra_db::{impl_intern_key, salsa, CrateId}; | 8 | use ra_db::{impl_intern_key, salsa, CrateId}; |
9 | use ra_prof::profile; | 9 | use ra_prof::profile; |
10 | 10 | ||
11 | use crate::{db::HirDatabase, DebruijnIndex}; | 11 | use crate::{db::HirDatabase, DebruijnIndex, Substs}; |
12 | 12 | ||
13 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | 13 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
14 | 14 | ||
@@ -190,15 +190,7 @@ fn solution_from_chalk( | |||
190 | solution: chalk_solve::Solution<Interner>, | 190 | solution: chalk_solve::Solution<Interner>, |
191 | ) -> Solution { | 191 | ) -> Solution { |
192 | let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| { | 192 | let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| { |
193 | let value = subst | 193 | let result = from_chalk(db, subst); |
194 | .value | ||
195 | .iter(&Interner) | ||
196 | .map(|p| match p.ty(&Interner) { | ||
197 | Some(ty) => from_chalk(db, ty.clone()), | ||
198 | None => unimplemented!(), | ||
199 | }) | ||
200 | .collect(); | ||
201 | let result = Canonical { value, num_vars: subst.binders.len(&Interner) }; | ||
202 | SolutionVariables(result) | 194 | SolutionVariables(result) |
203 | }; | 195 | }; |
204 | match solution { | 196 | match solution { |
@@ -222,7 +214,7 @@ fn solution_from_chalk( | |||
222 | } | 214 | } |
223 | 215 | ||
224 | #[derive(Clone, Debug, PartialEq, Eq)] | 216 | #[derive(Clone, Debug, PartialEq, Eq)] |
225 | pub struct SolutionVariables(pub Canonical<Vec<Ty>>); | 217 | pub struct SolutionVariables(pub Canonical<Substs>); |
226 | 218 | ||
227 | #[derive(Clone, Debug, PartialEq, Eq)] | 219 | #[derive(Clone, Debug, PartialEq, Eq)] |
228 | /// A (possible) solution for a proposed goal. | 220 | /// A (possible) solution for a proposed goal. |
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index ac82ea831..433d6aa03 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs | |||
@@ -17,7 +17,7 @@ use crate::{ | |||
17 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, | 17 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, |
18 | traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, | 18 | traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, |
19 | ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, | 19 | ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, |
20 | ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, | 20 | ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | use super::interner::*; | 23 | use super::interner::*; |
@@ -555,22 +555,39 @@ where | |||
555 | type Chalk = chalk_ir::Canonical<T::Chalk>; | 555 | type Chalk = chalk_ir::Canonical<T::Chalk>; |
556 | 556 | ||
557 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | 557 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { |
558 | let parameter = chalk_ir::CanonicalVarKind::new( | 558 | let kinds = self |
559 | chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General), | 559 | .kinds |
560 | chalk_ir::UniverseIndex::ROOT, | 560 | .iter() |
561 | ); | 561 | .map(|k| match k { |
562 | TyKind::General => chalk_ir::TyKind::General, | ||
563 | TyKind::Integer => chalk_ir::TyKind::Integer, | ||
564 | TyKind::Float => chalk_ir::TyKind::Float, | ||
565 | }) | ||
566 | .map(|tk| { | ||
567 | chalk_ir::CanonicalVarKind::new( | ||
568 | chalk_ir::VariableKind::Ty(tk), | ||
569 | chalk_ir::UniverseIndex::ROOT, | ||
570 | ) | ||
571 | }); | ||
562 | let value = self.value.to_chalk(db); | 572 | let value = self.value.to_chalk(db); |
563 | chalk_ir::Canonical { | 573 | chalk_ir::Canonical { value, binders: chalk_ir::CanonicalVarKinds::from(&Interner, kinds) } |
564 | value, | ||
565 | binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]), | ||
566 | } | ||
567 | } | 574 | } |
568 | 575 | ||
569 | fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | 576 | fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { |
570 | Canonical { | 577 | let kinds = canonical |
571 | num_vars: canonical.binders.len(&Interner), | 578 | .binders |
572 | value: from_chalk(db, canonical.value), | 579 | .iter(&Interner) |
573 | } | 580 | .map(|k| match k.kind { |
581 | chalk_ir::VariableKind::Ty(tk) => match tk { | ||
582 | chalk_ir::TyKind::General => TyKind::General, | ||
583 | chalk_ir::TyKind::Integer => TyKind::Integer, | ||
584 | chalk_ir::TyKind::Float => TyKind::Float, | ||
585 | }, | ||
586 | chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"), | ||
587 | chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"), | ||
588 | }) | ||
589 | .collect(); | ||
590 | Canonical { kinds, value: from_chalk(db, canonical.value) } | ||
574 | } | 591 | } |
575 | } | 592 | } |
576 | 593 | ||