diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index f8efe9bfa9f82..71fb6058cd2c5 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -168,24 +168,27 @@ fn satisfied_from_param_env<'tcx>(
         param_env: ty::ParamEnv<'tcx>,
 
         infcx: &'a InferCtxt<'tcx>,
+        single_match: Option<Result<ty::Const<'tcx>, ()>>,
     }
+
     impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
         type BreakTy = ();
         fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             debug!("is_const_evaluatable: candidate={:?}", c);
-            if let Ok(()) = self.infcx.commit_if_ok(|_| {
+            if self.infcx.probe(|_| {
                 let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
-                if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
-                    && let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct)
+                ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty()).is_ok()
+                    && ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok()
                     && ocx.select_all_or_error().is_empty()
-                {
-                    Ok(())
-                } else {
-                    Err(())
-                }
             }) {
-                ControlFlow::BREAK
-            } else if let ty::ConstKind::Expr(e) = c.kind() {
+                self.single_match = match self.single_match {
+                    None => Some(Ok(c)),
+                    Some(Ok(o)) if o == c => Some(Ok(c)),
+                    Some(_) => Some(Err(())),
+                };
+            }
+
+            if let ty::ConstKind::Expr(e) = c.kind() {
                 e.visit_with(self)
             } else {
                 // FIXME(generic_const_exprs): This doesn't recurse into `<T as Trait<U>>::ASSOC`'s substs.
@@ -200,22 +203,29 @@ fn satisfied_from_param_env<'tcx>(
         }
     }
 
+    let mut single_match: Option<Result<ty::Const<'tcx>, ()>> = None;
+
     for pred in param_env.caller_bounds() {
         match pred.kind().skip_binder() {
             ty::PredicateKind::ConstEvaluatable(ce) => {
                 let b_ct = tcx.expand_abstract_consts(ce);
-                let mut v = Visitor { ct, infcx, param_env };
-                let result = b_ct.visit_with(&mut v);
+                let mut v = Visitor { ct, infcx, param_env, single_match };
+                let _ = b_ct.visit_with(&mut v);
 
-                if let ControlFlow::Break(()) = result {
-                    debug!("is_const_evaluatable: yes");
-                    return true;
-                }
+                single_match = v.single_match;
             }
             _ => {} // don't care
         }
     }
 
+    if let Some(Ok(c)) = single_match {
+        let ocx = ObligationCtxt::new(infcx);
+        assert!(ocx.eq(&ObligationCause::dummy(), param_env, c.ty(), ct.ty()).is_ok());
+        assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok());
+        assert!(ocx.select_all_or_error().is_empty());
+        return true;
+    }
+
     debug!("is_const_evaluatable: no");
     false
 }
diff --git a/src/test/ui/const-generics/ensure_is_evaluatable.rs b/src/test/ui/const-generics/ensure_is_evaluatable.rs
new file mode 100644
index 0000000000000..1e8d8c3d3559b
--- /dev/null
+++ b/src/test/ui/const-generics/ensure_is_evaluatable.rs
@@ -0,0 +1,20 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize, const M: usize>() -> [(); N+2]
+where
+    [(); N + 1]:,
+    [(); M + 1]:,
+{
+    bar()
+    //~^ ERROR: unconstrained
+}
+
+fn bar<const N: usize>() -> [(); N]
+where
+    [(); N + 1]:,
+{
+    [(); N]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/ensure_is_evaluatable.stderr b/src/test/ui/const-generics/ensure_is_evaluatable.stderr
new file mode 100644
index 0000000000000..bf6c35ad8fd86
--- /dev/null
+++ b/src/test/ui/const-generics/ensure_is_evaluatable.stderr
@@ -0,0 +1,18 @@
+error: unconstrained generic constant
+  --> $DIR/ensure_is_evaluatable.rs:9:5
+   |
+LL |     bar()
+   |     ^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); N + 1]:`
+note: required by a bound in `bar`
+  --> $DIR/ensure_is_evaluatable.rs:15:10
+   |
+LL | fn bar<const N: usize>() -> [(); N]
+   |    --- required by a bound in this
+LL | where
+LL |     [(); N + 1]:,
+   |          ^^^^^ required by this bound in `bar`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/fn_with_two_const_inputs.rs b/src/test/ui/const-generics/fn_with_two_const_inputs.rs
new file mode 100644
index 0000000000000..0d6246a9f02c3
--- /dev/null
+++ b/src/test/ui/const-generics/fn_with_two_const_inputs.rs
@@ -0,0 +1,23 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+const fn both(_: usize, b: usize) -> usize {
+    b
+}
+
+fn foo<const N: usize, const M: usize>() -> [(); N + 2]
+where
+    [(); both(N + 1, M + 1)]:,
+{
+    bar()
+    //~^ ERROR: unconstrained generic constant
+}
+
+fn bar<const N: usize>() -> [(); N]
+where
+    [(); N + 1]:,
+{
+    [(); N]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/fn_with_two_const_inputs.stderr b/src/test/ui/const-generics/fn_with_two_const_inputs.stderr
new file mode 100644
index 0000000000000..614e7e0d2fc20
--- /dev/null
+++ b/src/test/ui/const-generics/fn_with_two_const_inputs.stderr
@@ -0,0 +1,18 @@
+error: unconstrained generic constant
+  --> $DIR/fn_with_two_const_inputs.rs:12:5
+   |
+LL |     bar()
+   |     ^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); N + 1]:`
+note: required by a bound in `bar`
+  --> $DIR/fn_with_two_const_inputs.rs:18:10
+   |
+LL | fn bar<const N: usize>() -> [(); N]
+   |    --- required by a bound in this
+LL | where
+LL |     [(); N + 1]:,
+   |          ^^^^^ required by this bound in `bar`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/fn_with_two_same_const_inputs.rs b/src/test/ui/const-generics/fn_with_two_same_const_inputs.rs
new file mode 100644
index 0000000000000..f0ce093e07a4f
--- /dev/null
+++ b/src/test/ui/const-generics/fn_with_two_same_const_inputs.rs
@@ -0,0 +1,22 @@
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+const fn both(_: usize, b: usize) -> usize {
+    b
+}
+
+fn foo<const N: usize>()
+where
+    [(); both(N + 1, N + 1)]:,
+{
+    bar::<N>();
+}
+
+fn bar<const N: usize>()
+where
+    [(); N + 1]:,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-105037.rs b/src/test/ui/const-generics/issues/issue-105037.rs
new file mode 100644
index 0000000000000..f7d2394994396
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-105037.rs
@@ -0,0 +1,35 @@
+// run-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+#![allow(dead_code)]
+
+trait Table<const D: usize>: Sync {
+    const COLUMNS: usize;
+}
+
+struct Table1<const D: usize>;
+impl<const D: usize> Table<D> for Table1<D> {
+    const COLUMNS: usize = 123;
+}
+
+struct Table2<const D: usize>;
+impl<const D: usize> Table<D> for Table2<D> {
+    const COLUMNS: usize = 456;
+}
+
+fn process_table<T: Table<D>, const D: usize>(_table: T)
+where
+    [(); T::COLUMNS]:,
+{
+}
+
+fn process_all_tables<const D: usize>()
+where
+    [(); Table2::<D>::COLUMNS]:,
+    [(); Table1::<D>::COLUMNS]:,
+{
+    process_table(Table1::<D>);
+    process_table(Table2::<D>);
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/two_matching_preds.rs b/src/test/ui/const-generics/two_matching_preds.rs
new file mode 100644
index 0000000000000..de608f73e2c0c
--- /dev/null
+++ b/src/test/ui/const-generics/two_matching_preds.rs
@@ -0,0 +1,19 @@
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize>()
+where
+    [(); N + 1]:,
+    [(); N + 1]:,
+{
+    bar::<N>();
+}
+
+fn bar<const N: usize>()
+where
+    [(); N + 1]:,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/unify_with_nested_expr.rs b/src/test/ui/const-generics/unify_with_nested_expr.rs
new file mode 100644
index 0000000000000..1271e0902a3bd
--- /dev/null
+++ b/src/test/ui/const-generics/unify_with_nested_expr.rs
@@ -0,0 +1,18 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize>()
+where
+    [(); N + 1 + 1]:,
+{
+    bar();
+    //~^ ERROR: type annotations
+}
+
+fn bar<const N: usize>()
+where
+    [(); N + 1]:,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/unify_with_nested_expr.stderr b/src/test/ui/const-generics/unify_with_nested_expr.stderr
new file mode 100644
index 0000000000000..8bab0dff7f263
--- /dev/null
+++ b/src/test/ui/const-generics/unify_with_nested_expr.stderr
@@ -0,0 +1,22 @@
+error[E0284]: type annotations needed
+  --> $DIR/unify_with_nested_expr.rs:8:5
+   |
+LL |     bar();
+   |     ^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
+   |
+note: required by a bound in `bar`
+  --> $DIR/unify_with_nested_expr.rs:14:10
+   |
+LL | fn bar<const N: usize>()
+   |    --- required by a bound in this
+LL | where
+LL |     [(); N + 1]:,
+   |          ^^^^^ required by this bound in `bar`
+help: consider specifying the generic argument
+   |
+LL |     bar::<N>();
+   |        +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0284`.