about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-08-18 06:29:38 +0000
committerbors <bors@rust-lang.org>2023-08-18 06:29:38 +0000
commita1e1dba9cc40a90409bccb8b19e359c4bdf573e5 (patch)
treec40740cf5c37a1425e0d1bc4ad9943ee60a1f587
parentfe3eae3f310b2f709aa5b39d76a94fc1ea843854 (diff)
parent698f0e39e161cb0fdabb06ac34401ee87cfc5c9e (diff)
downloadrust-a1e1dba9cc40a90409bccb8b19e359c4bdf573e5.tar.gz
rust-a1e1dba9cc40a90409bccb8b19e359c4bdf573e5.zip
Auto merge of #114611 - nnethercote:type-system-chess, r=compiler-errors
Speed up compilation of `type-system-chess`

[`type-system-chess`](https://github.com/rust-lang/rustc-perf/pull/1680) is an unusual program that implements a compile-time chess position solver in the trait system(!)  This PR is about making it compile faster.

r? `@ghost`
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs13
2 files changed, 27 insertions, 10 deletions
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index dc41630196b..a5b2ccce85e 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -9,6 +9,7 @@ mod structural_impls;
 pub mod util;
 
 use std::cmp;
+use std::hash::{Hash, Hasher};
 
 use hir::def_id::LocalDefId;
 use rustc_hir as hir;
@@ -36,7 +37,7 @@ pub use rustc_middle::traits::*;
 /// either identifying an `impl` (e.g., `impl Eq for i32`) that
 /// satisfies the obligation, or else finding a bound that is in
 /// scope. The eventual result is usually a `Selection` (defined below).
-#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(Clone)]
 pub struct Obligation<'tcx, T> {
     /// The reason we have to prove this thing.
     pub cause: ObligationCause<'tcx>,
@@ -55,6 +56,27 @@ pub struct Obligation<'tcx, T> {
     pub recursion_depth: usize,
 }
 
+impl<'tcx, T: PartialEq> PartialEq<Obligation<'tcx, T>> for Obligation<'tcx, T> {
+    #[inline]
+    fn eq(&self, other: &Obligation<'tcx, T>) -> bool {
+        // Ignore `cause` and `recursion_depth`. This is a small performance
+        // win for a few crates, and a huge performance win for the crate in
+        // https://github.com/rust-lang/rustc-perf/pull/1680, which greatly
+        // stresses the trait system.
+        self.param_env == other.param_env && self.predicate == other.predicate
+    }
+}
+
+impl<T: Eq> Eq for Obligation<'_, T> {}
+
+impl<T: Hash> Hash for Obligation<'_, T> {
+    fn hash<H: Hasher>(&self, state: &mut H) -> () {
+        // See the comment on `Obligation::eq`.
+        self.param_env.hash(state);
+        self.predicate.hash(state);
+    }
+}
+
 impl<'tcx, P> From<Obligation<'tcx, P>> for solve::Goal<'tcx, P> {
     fn from(value: Obligation<'tcx, P>) -> Self {
         solve::Goal { param_env: value.param_env, predicate: value.predicate }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 3d800421b76..06a1027e5df 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1214,7 +1214,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
 
             let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term);
 
-            let mut result = if projected_term.has_projections() {
+            let result = if projected_term.has_projections() {
                 let mut normalizer = AssocTypeNormalizer::new(
                     selcx,
                     param_env,
@@ -1224,19 +1224,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
                 );
                 let normalized_ty = normalizer.fold(projected_term);
 
+                let mut deduped = SsoHashSet::with_capacity(projected_obligations.len());
+                projected_obligations.retain(|obligation| deduped.insert(obligation.clone()));
+
                 Normalized { value: normalized_ty, obligations: projected_obligations }
             } else {
                 Normalized { value: projected_term, obligations: projected_obligations }
             };
 
-            let mut deduped: SsoHashSet<_> = Default::default();
-            result.obligations.retain(|projected_obligation| {
-                if !deduped.insert(projected_obligation.clone()) {
-                    return false;
-                }
-                true
-            });
-
             if use_cache {
                 infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
             }