about summary refs log tree commit diff
path: root/compiler/rustc_next_trait_solver/src
diff options
context:
space:
mode:
authorDavid Wood <david.wood2@arm.com>2025-03-17 10:24:56 +0000
committerDavid Wood <david.wood2@arm.com>2025-06-16 23:04:36 +0000
commit607eb322a85c9c6dcc4af6999ecfc9d9d001be21 (patch)
tree68909055a4c4f3da52b4fb7ebdec2e9525b00d1f /compiler/rustc_next_trait_solver/src
parent47abf2e144e26e3a4d4f445b8c27a3fd73768e9d (diff)
downloadrust-607eb322a85c9c6dcc4af6999ecfc9d9d001be21.tar.gz
rust-607eb322a85c9c6dcc4af6999ecfc9d9d001be21.zip
trait_sel: skip elaboration of sizedness supertrait
As a performance optimization, skip elaborating the supertraits of
`Sized`, and if a `MetaSized` obligation is being checked, then look for
a `Sized` predicate in the parameter environment. This makes the
`ParamEnv` smaller which should improve compiler performance as it avoids
all the iteration over the larger `ParamEnv`.
Diffstat (limited to 'compiler/rustc_next_trait_solver/src')
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs51
1 files changed, 47 insertions, 4 deletions
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index a8bbc2d60f1..8ee116b090d 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -6,7 +6,7 @@ use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind};
 use rustc_type_ir::{
-    self as ty, Interner, Movability, TraitPredicate, TypeVisitableExt as _, TypingMode,
+    self as ty, Interner, Movability, TraitPredicate, TraitRef, TypeVisitableExt as _, TypingMode,
     Upcast as _, elaborate,
 };
 use tracing::{debug, instrument, trace};
@@ -131,9 +131,11 @@ where
         assumption: I::Clause,
     ) -> Result<(), NoSolution> {
         if let Some(trait_clause) = assumption.as_trait_clause() {
-            if trait_clause.def_id() == goal.predicate.def_id()
-                && trait_clause.polarity() == goal.predicate.polarity
-            {
+            if trait_clause.polarity() != goal.predicate.polarity {
+                return Err(NoSolution);
+            }
+
+            if trait_clause.def_id() == goal.predicate.def_id() {
                 if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
                     goal.predicate.trait_ref.args,
                     trait_clause.skip_binder().trait_ref.args,
@@ -141,6 +143,17 @@ where
                     return Ok(());
                 }
             }
+
+            // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
+            // check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds
+            // are syntactic sugar for a lack of bounds so don't need this.
+            if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
+                && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
+            {
+                let meta_sized_clause =
+                    trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
+                return Self::fast_reject_assumption(ecx, goal, meta_sized_clause);
+            }
         }
 
         Err(NoSolution)
@@ -154,6 +167,17 @@ where
     ) -> QueryResult<I> {
         let trait_clause = assumption.as_trait_clause().unwrap();
 
+        // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
+        // check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds
+        // are syntactic sugar for a lack of bounds so don't need this.
+        if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
+            && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
+        {
+            let meta_sized_clause =
+                trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
+            return Self::match_assumption(ecx, goal, meta_sized_clause, then);
+        }
+
         let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
         ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
 
@@ -817,6 +841,25 @@ where
     }
 }
 
+/// Small helper function to change the `def_id` of a trait predicate - this is not normally
+/// something that you want to do, as different traits will require different args and so making
+/// it easy to change the trait is something of a footgun, but it is useful in the narrow
+/// circumstance of changing from `MetaSized` to `Sized`, which happens as part of the lazy
+/// elaboration of sizedness candidates.
+#[inline(always)]
+fn trait_predicate_with_def_id<I: Interner>(
+    cx: I,
+    clause: ty::Binder<I, ty::TraitPredicate<I>>,
+    did: I::DefId,
+) -> I::Clause {
+    clause
+        .map_bound(|c| TraitPredicate {
+            trait_ref: TraitRef::new_from_args(cx, did, c.trait_ref.args),
+            polarity: c.polarity,
+        })
+        .upcast(cx)
+}
+
 impl<D, I> EvalCtxt<'_, D>
 where
     D: SolverDelegate<Interner = I>,