diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 74da4d4c6db8b..0dc1f5e5eec58 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -22,6 +22,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.next_trait_solver } + fn disable_trait_solver_fast_paths(&self) -> bool { + self.disable_trait_solver_fast_paths() + } + fn typing_mode(&self) -> ty::TypingMode<'tcx> { self.typing_mode() } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 05043f8617a92..104a4e4d1ec4b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -640,6 +640,11 @@ impl<'tcx> InferCtxt<'tcx> { self.next_trait_solver } + #[inline(always)] + pub fn disable_trait_solver_fast_paths(&self) -> bool { + self.tcx.disable_trait_solver_fast_paths() + } + #[inline(always)] pub fn typing_mode(&self) -> TypingMode<'tcx> { self.typing_mode diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d1048a65a7be0..ba028ac9aad38 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2657,6 +2657,10 @@ impl<'tcx> TyCtxt<'tcx> { self.sess.opts.unstable_opts.next_solver.coherence } + pub fn disable_trait_solver_fast_paths(self) -> bool { + self.sess.opts.unstable_opts.disable_fast_paths + } + #[allow(rustc::bad_opt_access)] pub fn use_typing_mode_borrowck(self) -> bool { self.next_trait_solver_globally() || self.sess.opts.unstable_opts.typing_mode_borrowck diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 615cc9e8f81d2..b9e1758be0fd4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -447,6 +447,7 @@ where ref sub_roots, stalled_certainty, }) = stalled_on + && !self.delegate.disable_trait_solver_fast_paths() && !stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value)) && !sub_roots .iter() @@ -666,7 +667,10 @@ where // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); for (source, goal, stalled_on) in mem::take(&mut self.nested_goals) { - if let Some(certainty) = self.delegate.compute_goal_fast_path(goal, self.origin_span) { + if !self.delegate.disable_trait_solver_fast_paths() + && let Some(certainty) = + self.delegate.compute_goal_fast_path(goal, self.origin_span) + { match certainty { Certainty::Yes => {} Certainty::Maybe { .. } => { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f7a3387e5238a..4767b0cfbe868 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2269,6 +2269,8 @@ options! { themselves (default: no)"), direct_access_external_data: Option = (None, parse_opt_bool, [TRACKED], "Direct or use GOT indirect to reference external data symbols"), + disable_fast_paths: bool = (false, parse_bool, [TRACKED], + "disable various performance optimizations in trait solving"), dual_proc_macros: bool = (false, parse_bool, [TRACKED], "load proc macros for both target and host, but only link to the target (default: no)"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 8848b4c40f510..d8b9c400b4d7d 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -186,8 +186,9 @@ where let goal = obligation.as_goal(); let delegate = <&SolverDelegate<'tcx>>::from(infcx); - if let Some(certainty) = - delegate.compute_goal_fast_path(goal, obligation.cause.span) + if !delegate.disable_trait_solver_fast_paths() + && let Some(certainty) = + delegate.compute_goal_fast_path(goal, obligation.cause.span) { match certainty { // This fast path doesn't depend on region identity so it doesn't diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 0b1d4a8453d05..b4b54cd16bd5f 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -325,6 +325,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { /// compile-time benchmarks are very sensitive to even small changes. #[inline(always)] fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { + if self.selcx.infcx.disable_trait_solver_fast_paths() { + return true; + } + // If we were stalled on some unresolved variables, first check whether // any of them have been resolved; if not, don't bother doing more work // yet. @@ -388,7 +392,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx; - if sizedness_fast_path(infcx.tcx, obligation.predicate, obligation.param_env) { + if !infcx.disable_trait_solver_fast_paths() + && sizedness_fast_path(infcx.tcx, obligation.predicate, obligation.param_env) + { return ProcessResult::Changed(thin_vec![]); } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index b2c1f9a5eed14..3a8a3fc66e663 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -110,7 +110,9 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable> + 't ), NoSolution, > { - if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { + if !infcx.disable_trait_solver_fast_paths() + && let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) + { return Ok((result, None, PredicateObligations::new(), Certainty::Proven)); } @@ -159,7 +161,9 @@ where "query type op", span, |ocx| { - if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &self) { + if !infcx.disable_trait_solver_fast_paths() + && let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &self) + { return Ok(result); } QueryTypeOp::perform_locally_with_next_solver(ocx, self, span) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 9eca0f31a4402..3a8e2429069f5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -604,7 +604,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - if sizedness_fast_path(self.tcx(), obligation.predicate, obligation.param_env) { + if !self.infcx.disable_trait_solver_fast_paths() + && sizedness_fast_path(self.tcx(), obligation.predicate, obligation.param_env) + { return Ok(EvaluatedToOk); } diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 8f72bdf097261..6bc6543a0a01b 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -24,7 +24,7 @@ fn evaluate_obligation<'tcx>( debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; - if sizedness_fast_path(tcx, predicate, param_env) { + if !tcx.disable_trait_solver_fast_paths() && sizedness_fast_path(tcx, predicate, param_env) { return Ok(EvaluationResult::EvaluatedToOk); } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 1b6bdf8c34dd8..99588cb20aed0 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -230,6 +230,8 @@ pub trait InferCtxtLike: Sized { true } + fn disable_trait_solver_fast_paths(&self) -> bool; + fn typing_mode(&self) -> TypingMode; fn universe(&self) -> ty::UniverseIndex;