aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-11-16 11:53:13 +0000
committerFlorian Diebold <[email protected]>2019-11-16 12:25:54 +0000
commit351c29d859d74f7a61e654bdbcad634bfb136225 (patch)
tree39289f3a5fd0d828780ffa3128317afc8a0598e4
parent9c2a9a9a0635e53466749fdedcdc5a371e658cde (diff)
Fix handling of the binders in dyn/impl Trait
We need to be more careful now when substituting bound variables (previously, we didn't have anything that used bound variables except Chalk, so it was not a problem). This is obviously quite ad-hoc; Chalk has more infrastructure for handling this in a principled way, which we maybe should adopt.
-rw-r--r--crates/ra_hir/src/ty.rs89
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs22
-rw-r--r--crates/ra_hir/src/ty/tests.rs43
-rw-r--r--crates/ra_hir/src/ty/traits.rs7
4 files changed, 116 insertions, 45 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index ff6030ac4..a54135188 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -224,8 +224,8 @@ impl TypeWalk for ProjectionTy {
224 self.parameters.walk(f); 224 self.parameters.walk(f);
225 } 225 }
226 226
227 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 227 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
228 self.parameters.walk_mut(f); 228 self.parameters.walk_mut_binders(f, binders);
229 } 229 }
230} 230}
231 231
@@ -291,6 +291,20 @@ pub enum Ty {
291#[derive(Clone, PartialEq, Eq, Debug, Hash)] 291#[derive(Clone, PartialEq, Eq, Debug, Hash)]
292pub struct Substs(Arc<[Ty]>); 292pub struct Substs(Arc<[Ty]>);
293 293
294impl TypeWalk for Substs {
295 fn walk(&self, f: &mut impl FnMut(&Ty)) {
296 for t in self.0.iter() {
297 t.walk(f);
298 }
299 }
300
301 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
302 for t in make_mut_slice(&mut self.0) {
303 t.walk_mut_binders(f, binders);
304 }
305 }
306}
307
294impl Substs { 308impl Substs {
295 pub fn empty() -> Substs { 309 pub fn empty() -> Substs {
296 Substs(Arc::new([])) 310 Substs(Arc::new([]))
@@ -304,18 +318,6 @@ impl Substs {
304 Substs(self.0[..std::cmp::min(self.0.len(), n)].into()) 318 Substs(self.0[..std::cmp::min(self.0.len(), n)].into())
305 } 319 }
306 320
307 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
308 for t in self.0.iter() {
309 t.walk(f);
310 }
311 }
312
313 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
314 for t in make_mut_slice(&mut self.0) {
315 t.walk_mut(f);
316 }
317 }
318
319 pub fn as_single(&self) -> &Ty { 321 pub fn as_single(&self) -> &Ty {
320 if self.0.len() != 1 { 322 if self.0.len() != 1 {
321 panic!("expected substs of len 1, got {:?}", self); 323 panic!("expected substs of len 1, got {:?}", self);
@@ -440,8 +442,8 @@ impl TypeWalk for TraitRef {
440 self.substs.walk(f); 442 self.substs.walk(f);
441 } 443 }
442 444
443 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 445 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
444 self.substs.walk_mut(f); 446 self.substs.walk_mut_binders(f, binders);
445 } 447 }
446} 448}
447 449
@@ -491,10 +493,12 @@ impl TypeWalk for GenericPredicate {
491 } 493 }
492 } 494 }
493 495
494 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 496 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
495 match self { 497 match self {
496 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), 498 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
497 GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f), 499 GenericPredicate::Projection(projection_pred) => {
500 projection_pred.walk_mut_binders(f, binders)
501 }
498 GenericPredicate::Error => {} 502 GenericPredicate::Error => {}
499 } 503 }
500 } 504 }
@@ -544,9 +548,9 @@ impl TypeWalk for FnSig {
544 } 548 }
545 } 549 }
546 550
547 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 551 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
548 for t in make_mut_slice(&mut self.params_and_return) { 552 for t in make_mut_slice(&mut self.params_and_return) {
549 t.walk_mut(f); 553 t.walk_mut_binders(f, binders);
550 } 554 }
551 } 555 }
552} 556}
@@ -671,7 +675,20 @@ impl Ty {
671/// types, similar to Chalk's `Fold` trait. 675/// types, similar to Chalk's `Fold` trait.
672pub trait TypeWalk { 676pub trait TypeWalk {
673 fn walk(&self, f: &mut impl FnMut(&Ty)); 677 fn walk(&self, f: &mut impl FnMut(&Ty));
674 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)); 678 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
679 self.walk_mut_binders(&mut |ty, _binders| f(ty), 0);
680 }
681 /// Walk the type, counting entered binders.
682 ///
683 /// `Ty::Bound` variables use DeBruijn indexing, which means that 0 refers
684 /// to the innermost binder, 1 to the next, etc.. So when we want to
685 /// substitute a certain bound variable, we can't just walk the whole type
686 /// and blindly replace each instance of a certain index; when we 'enter'
687 /// things that introduce new bound variables, we have to keep track of
688 /// that. Currently, the only thing that introduces bound variables on our
689 /// side are `Ty::Dyn` and `Ty::Opaque`, which each introduce a bound
690 /// variable for the self type.
691 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize);
675 692
676 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self 693 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
677 where 694 where
@@ -700,14 +717,22 @@ pub trait TypeWalk {
700 } 717 }
701 718
702 /// Substitutes `Ty::Bound` vars (as opposed to type parameters). 719 /// Substitutes `Ty::Bound` vars (as opposed to type parameters).
703 fn subst_bound_vars(self, substs: &Substs) -> Self 720 fn subst_bound_vars(mut self, substs: &Substs) -> Self
704 where 721 where
705 Self: Sized, 722 Self: Sized,
706 { 723 {
707 self.fold(&mut |ty| match ty { 724 self.walk_mut_binders(
708 Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), 725 &mut |ty, binders| match ty {
709 ty => ty, 726 &mut Ty::Bound(idx) => {
710 }) 727 if idx as usize >= binders && (idx as usize - binders) < substs.len() {
728 *ty = substs.0[idx as usize - binders].clone();
729 }
730 }
731 _ => {}
732 },
733 0,
734 );
735 self
711 } 736 }
712 737
713 /// Shifts up `Ty::Bound` vars by `n`. 738 /// Shifts up `Ty::Bound` vars by `n`.
@@ -748,22 +773,22 @@ impl TypeWalk for Ty {
748 f(self); 773 f(self);
749 } 774 }
750 775
751 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 776 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
752 match self { 777 match self {
753 Ty::Apply(a_ty) => { 778 Ty::Apply(a_ty) => {
754 a_ty.parameters.walk_mut(f); 779 a_ty.parameters.walk_mut_binders(f, binders);
755 } 780 }
756 Ty::Projection(p_ty) => { 781 Ty::Projection(p_ty) => {
757 p_ty.parameters.walk_mut(f); 782 p_ty.parameters.walk_mut_binders(f, binders);
758 } 783 }
759 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 784 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
760 for p in make_mut_slice(predicates) { 785 for p in make_mut_slice(predicates) {
761 p.walk_mut(f); 786 p.walk_mut_binders(f, binders + 1);
762 } 787 }
763 } 788 }
764 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 789 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
765 } 790 }
766 f(self); 791 f(self, binders);
767 } 792 }
768} 793}
769 794
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index ca33cc7f8..64d9394cf 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -134,17 +134,19 @@ where
134} 134}
135 135
136impl<T> Canonicalized<T> { 136impl<T> Canonicalized<T> {
137 pub fn decanonicalize_ty(&self, ty: Ty) -> Ty { 137 pub fn decanonicalize_ty(&self, mut ty: Ty) -> Ty {
138 ty.fold(&mut |ty| match ty { 138 ty.walk_mut_binders(
139 Ty::Bound(idx) => { 139 &mut |ty, binders| match ty {
140 if (idx as usize) < self.free_vars.len() { 140 &mut Ty::Bound(idx) => {
141 Ty::Infer(self.free_vars[idx as usize]) 141 if idx as usize >= binders && (idx as usize - binders) < self.free_vars.len() {
142 } else { 142 *ty = Ty::Infer(self.free_vars[idx as usize - binders]);
143 Ty::Bound(idx) 143 }
144 } 144 }
145 } 145 _ => {}
146 ty => ty, 146 },
147 }) 147 0,
148 );
149 ty
148 } 150 }
149 151
150 pub fn apply_solution( 152 pub fn apply_solution(
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 838cb4d23..ca1693679 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -4185,6 +4185,49 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
4185} 4185}
4186 4186
4187#[test] 4187#[test]
4188fn impl_trait_assoc_binding_projection_bug() {
4189 let (db, pos) = TestDB::with_position(
4190 r#"
4191//- /main.rs crate:main deps:std
4192pub trait Language {
4193 type Kind;
4194}
4195pub enum RustLanguage {}
4196impl Language for RustLanguage {
4197 type Kind = SyntaxKind;
4198}
4199struct SyntaxNode<L> {}
4200fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
4201
4202trait Clone {
4203 fn clone(&self) -> Self;
4204}
4205
4206fn api_walkthrough() {
4207 for node in foo() {
4208 node.clone()<|>;
4209 }
4210}
4211
4212//- /std.rs crate:std
4213#[prelude_import] use iter::*;
4214mod iter {
4215 trait IntoIterator {
4216 type Item;
4217 }
4218 trait Iterator {
4219 type Item;
4220 }
4221 impl<T: Iterator> IntoIterator for T {
4222 type Item = <T as Iterator>::Item;
4223 }
4224}
4225"#,
4226 );
4227 assert_eq!("{unknown}", type_at_pos(&db, pos));
4228}
4229
4230#[test]
4188fn projection_eq_within_chalk() { 4231fn projection_eq_within_chalk() {
4189 // std::env::set_var("CHALK_DEBUG", "1"); 4232 // std::env::set_var("CHALK_DEBUG", "1");
4190 assert_snapshot!( 4233 assert_snapshot!(
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 771525deb..99dbab99e 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -165,9 +165,9 @@ impl TypeWalk for ProjectionPredicate {
165 self.ty.walk(f); 165 self.ty.walk(f);
166 } 166 }
167 167
168 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 168 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
169 self.projection_ty.walk_mut(f); 169 self.projection_ty.walk_mut_binders(f, binders);
170 self.ty.walk_mut(f); 170 self.ty.walk_mut_binders(f, binders);
171 } 171 }
172} 172}
173 173
@@ -188,6 +188,7 @@ pub(crate) fn trait_solve_query(
188 } 188 }
189 189
190 let canonical = goal.to_chalk(db).cast(); 190 let canonical = goal.to_chalk(db).cast();
191
191 // We currently don't deal with universes (I think / hope they're not yet 192 // We currently don't deal with universes (I think / hope they're not yet
192 // relevant for our use cases?) 193 // relevant for our use cases?)
193 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 194 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };