]> git.lizzy.rs Git - rust.git/commitdiff
Fix handling of binders in canonicalization
authorFlorian Diebold <flodiebold@gmail.com>
Fri, 21 Feb 2020 20:46:21 +0000 (21:46 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Sat, 22 Feb 2020 10:09:21 +0000 (11:09 +0100)
I'm looking forward to getting rid of this in favor of Chalk's implementation.

crates/ra_hir_ty/src/infer/unify.rs

index 2d03c5c33bd9629d230a0c00119de0523bf1d7d7..aed527fe591d3c43d11c1320ef5273349310a66b 100644 (file)
@@ -7,10 +7,7 @@
 use test_utils::tested_by;
 
 use super::{InferenceContext, Obligation};
-use crate::{
-    db::HirDatabase, utils::make_mut_slice, Canonical, InEnvironment, InferTy, ProjectionPredicate,
-    ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
-};
+use crate::{db::HirDatabase, Canonical, InEnvironment, InferTy, Substs, Ty, TypeCtor, TypeWalk};
 
 impl<'a, D: HirDatabase> InferenceContext<'a, D> {
     pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
@@ -50,42 +47,38 @@ fn add(&mut self, free_var: InferTy) -> usize {
         })
     }
 
-    fn do_canonicalize_ty(&mut self, ty: Ty) -> Ty {
-        ty.fold(&mut |ty| match ty {
-            Ty::Infer(tv) => {
-                let inner = tv.to_inner();
-                if self.var_stack.contains(&inner) {
-                    // recursive type
-                    return tv.fallback_value();
-                }
-                if let Some(known_ty) =
-                    self.ctx.table.var_unification_table.inlined_probe_value(inner).known()
-                {
-                    self.var_stack.push(inner);
-                    let result = self.do_canonicalize_ty(known_ty.clone());
-                    self.var_stack.pop();
-                    result
-                } else {
-                    let root = self.ctx.table.var_unification_table.find(inner);
-                    let free_var = match tv {
-                        InferTy::TypeVar(_) => InferTy::TypeVar(root),
-                        InferTy::IntVar(_) => InferTy::IntVar(root),
-                        InferTy::FloatVar(_) => InferTy::FloatVar(root),
-                        InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root),
-                    };
-                    let position = self.add(free_var);
-                    Ty::Bound(position as u32)
+    fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: usize) -> T {
+        t.fold_binders(
+            &mut |ty, binders| match ty {
+                Ty::Infer(tv) => {
+                    let inner = tv.to_inner();
+                    if self.var_stack.contains(&inner) {
+                        // recursive type
+                        return tv.fallback_value();
+                    }
+                    if let Some(known_ty) =
+                        self.ctx.table.var_unification_table.inlined_probe_value(inner).known()
+                    {
+                        self.var_stack.push(inner);
+                        let result = self.do_canonicalize(known_ty.clone(), binders);
+                        self.var_stack.pop();
+                        result
+                    } else {
+                        let root = self.ctx.table.var_unification_table.find(inner);
+                        let free_var = match tv {
+                            InferTy::TypeVar(_) => InferTy::TypeVar(root),
+                            InferTy::IntVar(_) => InferTy::IntVar(root),
+                            InferTy::FloatVar(_) => InferTy::FloatVar(root),
+                            InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root),
+                        };
+                        let position = self.add(free_var);
+                        Ty::Bound((position + binders) as u32)
+                    }
                 }
-            }
-            _ => ty,
-        })
-    }
-
-    fn do_canonicalize_trait_ref(&mut self, mut trait_ref: TraitRef) -> TraitRef {
-        for ty in make_mut_slice(&mut trait_ref.substs.0) {
-            *ty = self.do_canonicalize_ty(ty.clone());
-        }
-        trait_ref
+                _ => ty,
+            },
+            binders,
+        )
     }
 
     fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
@@ -95,28 +88,8 @@ fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
         }
     }
 
-    fn do_canonicalize_projection_ty(&mut self, mut projection_ty: ProjectionTy) -> ProjectionTy {
-        for ty in make_mut_slice(&mut projection_ty.parameters.0) {
-            *ty = self.do_canonicalize_ty(ty.clone());
-        }
-        projection_ty
-    }
-
-    fn do_canonicalize_projection_predicate(
-        &mut self,
-        projection: ProjectionPredicate,
-    ) -> ProjectionPredicate {
-        let ty = self.do_canonicalize_ty(projection.ty);
-        let projection_ty = self.do_canonicalize_projection_ty(projection.projection_ty);
-
-        ProjectionPredicate { ty, projection_ty }
-    }
-
-    // FIXME: add some point, we need to introduce a `Fold` trait that abstracts
-    // over all the things that can be canonicalized (like Chalk and rustc have)
-
     pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
-        let result = self.do_canonicalize_ty(ty);
+        let result = self.do_canonicalize(ty, 0);
         self.into_canonicalized(result)
     }
 
@@ -125,10 +98,8 @@ pub(crate) fn canonicalize_obligation(
         obligation: InEnvironment<Obligation>,
     ) -> Canonicalized<InEnvironment<Obligation>> {
         let result = match obligation.value {
-            Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize_trait_ref(tr)),
-            Obligation::Projection(pr) => {
-                Obligation::Projection(self.do_canonicalize_projection_predicate(pr))
-            }
+            Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize(tr, 0)),
+            Obligation::Projection(pr) => Obligation::Projection(self.do_canonicalize(pr, 0)),
         };
         self.into_canonicalized(InEnvironment {
             value: result,