From 421ea58e1830a93c418ebfb33bf74c304ac9c040 Mon Sep 17 00:00:00 2001 From: Amirhossein Akhlaghpour Date: Thu, 29 Oct 2026 21:13:46 +0330 Subject: [PATCH] reduce redundant type-outlives constraints in large canonical responses Signed-off-by: Amirhossein Akhlaghpour --- .../src/solve/eval_ctxt/mod.rs | 68 ++++++++++++++++++- .../region-signatures.rs | 55 +++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/next-solver/issue-308-region-signatures/region-signatures.rs 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 ba70ebb27540f..08370db07c798 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 @@ -3,7 +3,7 @@ use std::ops::ControlFlow; #[cfg(feature = "nightly")] use rustc_macros::StableHash; -use rustc_type_ir::data_structures::HashSet; +use rustc_type_ir::data_structures::{HashMap, HashSet}; use rustc_type_ir::inherent::*; use rustc_type_ir::region_constraint::RegionConstraint; use rustc_type_ir::relate::Relate; @@ -1712,6 +1712,72 @@ where filter_irrelevant_region_constraints(self.delegate, var_values, &mut external_constraints); + // skip duplicate type outlives constraints with the same region requirements + // leave constraints we can't compare unchanged + if let ExternalRegionConstraints::Old(constraints) = + &mut external_constraints.region_constraints + && constraints.len() >= 10_000 + { + let before = constraints.len(); + + let mut component_cache: HashMap>> = Default::default(); + + // use numeric IDs so region sets can be sorted and compared + let mut region_ids: HashMap, usize> = Default::default(); + + let mut signatures = HashSet::default(); + let mut kept = Vec::with_capacity(before); + + for (constraint, vis) in std::mem::take(constraints) { + if let ty::RegionConstraint::Outlives(ty::OutlivesClause(lhs, rhs)) = constraint + && let ty::GenericArgKind::Type(t) = lhs.kind() + && matches!(vis, crate::solve::VisibleForLeakCheck::Unreachable) + && matches!(rhs.kind(), ty::RePlaceholder(_)) + && !t.has_infer() + && !t.has_escaping_bound_vars() + { + let signature = component_cache.entry(t).or_insert_with(|| { + let mut components = Default::default(); + rustc_type_ir::outlives::push_outlives_components( + self.cx(), + t, + &mut components, + ); + + let mut ids = Vec::new(); + + for component in components { + match component { + rustc_type_ir::outlives::Component::Region(reg) => { + let next_id = region_ids.len(); + let id = *region_ids.entry(reg).or_insert(next_id); + ids.push(id); + } + _ => return None, + } + } + + ids.sort_unstable(); + ids.dedup(); + + (!ids.is_empty()).then_some(ids) + }); + + if let Some(signature) = signature { + // these constraints are ignored by leak checking + // only one needs to be kept + if !signatures.insert((rhs, signature.clone())) { + continue; + } + } + } + + kept.push((constraint, vis)); + } + + *constraints = kept; + } + let mut canonical = canonicalize_response( self.delegate, self.max_input_universe, diff --git a/tests/ui/traits/next-solver/issue-308-region-signatures/region-signatures.rs b/tests/ui/traits/next-solver/issue-308-region-signatures/region-signatures.rs new file mode 100644 index 0000000000000..8b10824c71166 --- /dev/null +++ b/tests/ui/traits/next-solver/issue-308-region-signatures/region-signatures.rs @@ -0,0 +1,55 @@ +//@ revisions: valid short_x short_y short_both +//@[valid] check-pass +//@[short_x] check-fail +//@[short_y] check-fail +//@[short_both] check-fail +//@ compile-flags: -Znext-solver=globally -Zpolonius=off +//@ dont-check-compiler-stderr + +// different types can have the same lifetime requirements + +trait NeedsRegions<'a> {} + +impl<'a, 'x, 'y> NeedsRegions<'a> for (&'x str, &'y str) +where + (&'x str, u8): 'a, + (&'x str, u16): 'a, + (&'y str, u8): 'a, + (&'y str, u16): 'a, + (&'x str, &'y str, u8): 'a, + (&'x str, &'y str, u16): 'a, +{} + +trait Check {} + +impl<'x, 'y> Check for (&'x str, &'y str) +where + for<'a> (&'x str, &'y str): NeedsRegions<'a>, +{} + +fn require() {} + +#[cfg(valid)] +fn check() { + require::<(&'static str, &'static str)>(); +} + +#[cfg(short_x)] +fn check<'short>(_: &'short str) { + require::<(&'short str, &'static str)>(); + //[short_x]~^ ERROR lifetime may not live long enough +} + +#[cfg(short_y)] +fn check<'short>(_: &'short str) { + require::<(&'static str, &'short str)>(); + //[short_y]~^ ERROR lifetime may not live long enough +} + +#[cfg(short_both)] +fn check<'short>(_: &'short str) { + require::<(&'short str, &'short str)>(); + //[short_both]~^ ERROR lifetime may not live long enough +} + +fn main() {}