about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src/solve
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-05-29 11:14:36 +0000
committerMichael Goulet <michael@errs.io>2025-05-29 11:14:36 +0000
commitf1da2885578519b3f5ad1d584bcb9fb0a22e9403 (patch)
tree6fc9c624c2608f95f90d1c0fdeb3216b2d8f058b /compiler/rustc_trait_selection/src/solve
parent38081f22c2d7380f272aa1d7fa9b935637701c2d (diff)
downloadrust-f1da2885578519b3f5ad1d584bcb9fb0a22e9403.tar.gz
rust-f1da2885578519b3f5ad1d584bcb9fb0a22e9403.zip
Tweak fast path trait handling
Diffstat (limited to 'compiler/rustc_trait_selection/src/solve')
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs58
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs9
2 files changed, 44 insertions, 23 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 038cdc1a564..e92e37b8738 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -11,8 +11,9 @@ use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtx
 use rustc_infer::traits::solve::Goal;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::Certainty;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, TypingMode};
-use rustc_next_trait_solver::solve::HasChanged;
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode,
+};
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 
 use crate::traits::{EvaluateConstErr, ObligationCause, specialization_graph};
@@ -61,11 +62,41 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         &self,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
         span: Span,
-    ) -> Option<HasChanged> {
+    ) -> Option<Certainty> {
+        if let Some(trait_pred) = goal.predicate.as_trait_clause() {
+            if trait_pred.polarity() == ty::PredicatePolarity::Positive {
+                match self.0.tcx.as_lang_item(trait_pred.def_id()) {
+                    Some(LangItem::Sized)
+                        if self
+                            .resolve_vars_if_possible(trait_pred.self_ty().skip_binder())
+                            .is_trivially_sized(self.0.tcx) =>
+                    {
+                        return Some(Certainty::Yes);
+                    }
+                    Some(LangItem::Copy | LangItem::Clone) => {
+                        let self_ty =
+                            self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder());
+                        // Unlike `Sized` traits, which always prefer the built-in impl,
+                        // `Copy`/`Clone` may be shadowed by a param-env candidate which
+                        // could force a lifetime error or guide inference. While that's
+                        // not generally desirable, it is observable, so for now let's
+                        // ignore this fast path for types that have regions or infer.
+                        if !self_ty
+                            .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER)
+                            && self_ty.is_trivially_pure_clone_copy()
+                        {
+                            return Some(Certainty::Yes);
+                        }
+                    }
+                    _ => {}
+                }
+            }
+        }
+
         let pred = goal.predicate.kind();
         match pred.no_bound_vars()? {
             ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => {
-                Some(HasChanged::No)
+                Some(Certainty::Yes)
             }
             ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => {
                 self.0.sub_regions(
@@ -73,7 +104,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
                     outlives.1,
                     outlives.0,
                 );
-                Some(HasChanged::No)
+                Some(Certainty::Yes)
             }
             ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
                 self.0.register_type_outlives_constraint(
@@ -82,22 +113,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
                     &ObligationCause::dummy_with_span(span),
                 );
 
-                Some(HasChanged::No)
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
-                match self.0.tcx.as_lang_item(trait_pred.def_id()) {
-                    Some(LangItem::Sized)
-                        if trait_pred.self_ty().is_trivially_sized(self.0.tcx) =>
-                    {
-                        Some(HasChanged::No)
-                    }
-                    Some(LangItem::Copy | LangItem::Clone)
-                        if trait_pred.self_ty().is_trivially_pure_clone_copy() =>
-                    {
-                        Some(HasChanged::No)
-                    }
-                    _ => None,
-                }
+                Some(Certainty::Yes)
             }
             _ => None,
         }
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index d273703a9b1..ed99c678a4d 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -195,10 +195,15 @@ where
 
                 let goal = obligation.as_goal();
                 let delegate = <&SolverDelegate<'tcx>>::from(infcx);
-                if let Some(fast_path_has_changed) =
+                if let Some(certainty) =
                     delegate.compute_goal_fast_path(goal, obligation.cause.span)
                 {
-                    any_changed |= matches!(fast_path_has_changed, HasChanged::Yes);
+                    match certainty {
+                        Certainty::Yes => {}
+                        Certainty::Maybe(_) => {
+                            self.obligations.register(obligation, None);
+                        }
+                    }
                     continue;
                 }