From a8223e187be75e3c7c55f1bd8fbee55a22ded6cc Mon Sep 17 00:00:00 2001 From: Makro Date: Mon, 13 Jul 2026 22:34:54 +0000 Subject: [PATCH] perf: only fork the inference context in WF checking when the compat retry can matter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Well-formedness checking forked the entire inference context — a deep clone of every inference table — once per checked item, purely so a second region resolution could retry with the bevy ParamSet implied-bounds hack enabled. The retry can only change the outcome when one of the assumed-wf types actually contains bevy_ecs::ParamSet, so detect that with a cheap type walk and skip the fork (and the second outlives environment) everywhere else, reporting the region errors directly. --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 14 +++++++++++++- .../query/type_op/implied_outlives_bounds.rs | 8 ++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f2a6c2747f380..96e6b49d6cf0c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -35,6 +35,7 @@ use rustc_trait_selection::traits::misc::{ ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty, }; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::ty_contains_bevy_param_set; use rustc_trait_selection::traits::{ self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, @@ -183,7 +184,14 @@ where let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?; debug!(?assumed_wf_types); - let infcx_compat = infcx.fork(); + // The compat retry below can only change the outcome when the bevy + // `ParamSet` implied-bounds hack applies to one of the assumed-wf types; + // otherwise both outlives environments are identical. Only pay for the + // inference-context fork (a deep clone of all inference storage, once per + // WF-checked item) when the retry could matter. + let needs_compat_retry = !tcx.sess.opts.unstable_opts.no_implied_bounds_compat + && assumed_wf_types.iter().any(|&ty| ty_contains_bevy_param_set(tcx, ty)); + let infcx_compat = needs_compat_retry.then(|| infcx.fork()); // We specifically want to *disable* the implied bounds hack, first, // so we can detect when failures are due to bevy's implied bounds. @@ -202,6 +210,10 @@ where return Ok(()); } + let Some(infcx_compat) = infcx_compat else { + return Err(infcx.err_ctxt().report_region_errors(body_def_id, &errors)); + }; + let outlives_env = OutlivesEnvironment::new_with_implied_bounds_compat( &infcx_compat, body_def_id, diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index a98f8b9a9af88..44d23152d1022 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -167,6 +167,14 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( Ok(outlives_bounds) } +/// Whether `ty` contains the `bevy_ecs::ParamSet` type that the implied-bounds +/// compat hack above applies to. Callers can use this to tell whether the +/// `disable_implied_bounds_hack` flag can make any difference for a set of +/// assumed-wf types. +pub fn ty_contains_bevy_param_set<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { + ty.visit_with(&mut ContainsBevyParamSet { tcx }).is_break() +} + struct ContainsBevyParamSet<'tcx> { tcx: TyCtxt<'tcx>, }