about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs26
1 files changed, 22 insertions, 4 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index ad229e03b0b..b587ed6487e 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -609,9 +609,29 @@ where
 /// Tries to unify two abstract constants using structural equality.
 pub(super) fn try_unify<'tcx>(
     tcx: TyCtxt<'tcx>,
-    a: AbstractConst<'tcx>,
-    b: AbstractConst<'tcx>,
+    mut a: AbstractConst<'tcx>,
+    mut b: AbstractConst<'tcx>,
 ) -> bool {
+    // We substitute generics repeatedly to allow AbstractConsts to unify where a
+    // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
+    // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
+    while let Node::Leaf(a_ct) = a.root() {
+        let a_ct = a_ct.subst(tcx, a.substs);
+        match AbstractConst::from_const(tcx, a_ct) {
+            Ok(Some(a_act)) => a = a_act,
+            Ok(None) => break,
+            Err(_) => return true,
+        }
+    }
+    while let Node::Leaf(b_ct) = b.root() {
+        let b_ct = b_ct.subst(tcx, b.substs);
+        match AbstractConst::from_const(tcx, b_ct) {
+            Ok(Some(b_act)) => b = b_act,
+            Ok(None) => break,
+            Err(_) => return true,
+        }
+    }
+
     match (a.root(), b.root()) {
         (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
             let a_ct = a_ct.subst(tcx, a.substs);
@@ -632,8 +652,6 @@ pub(super) fn try_unify<'tcx>(
                 // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
                 // means that we only allow inference variables if they are equal.
                 (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
-                // We may want to instead recurse into unevaluated constants here. That may require some
-                // care to prevent infinite recursion, so let's just ignore this for now.
                 (
                     ty::ConstKind::Unevaluated(a_def, a_substs, None),
                     ty::ConstKind::Unevaluated(b_def, b_substs, None),