Skip to content

Commit 05e774a

Browse files
committed
Auto merge of #165093 - amirHdev:next-solver-region-signature-dedup, r=<try>
reduce redundant type-outlives constraints in large canonical responses
2 parents 41089d0 + e0f0845 commit 05e774a

2 files changed

Lines changed: 125 additions & 0 deletions

File tree

  • compiler/rustc_next_trait_solver/src/solve/eval_ctxt
  • tests/ui/traits/next-solver/issue-308-region-signatures

‎compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,6 +1711,76 @@ where
17111711

17121712
filter_irrelevant_region_constraints(self.delegate, var_values, &mut external_constraints);
17131713

1714+
// skip duplicate type outlives constraints with the same region requirements
1715+
// leave constraints we can't compare unchanged
1716+
if let ExternalRegionConstraints::Old(constraints) =
1717+
&mut external_constraints.region_constraints
1718+
&& constraints.len() >= 10_000
1719+
{
1720+
let before = constraints.len();
1721+
1722+
let mut component_cache: rustc_data_structures::fx::FxHashMap<
1723+
I::Ty,
1724+
Option<Vec<usize>>,
1725+
> = Default::default();
1726+
1727+
// use numeric IDs so region sets can be sorted and compared
1728+
let mut region_ids: rustc_data_structures::fx::FxHashMap<Region<I>, usize> =
1729+
Default::default();
1730+
1731+
let mut signatures = HashSet::default();
1732+
let mut kept = Vec::with_capacity(before);
1733+
1734+
for (constraint, vis) in std::mem::take(constraints) {
1735+
if let ty::RegionConstraint::Outlives(ty::OutlivesClause(lhs, rhs)) = constraint
1736+
&& let ty::GenericArgKind::Type(t) = lhs.kind()
1737+
&& matches!(vis, crate::solve::VisibleForLeakCheck::Unreachable)
1738+
&& matches!(rhs.kind(), ty::RePlaceholder(_))
1739+
&& !t.has_infer()
1740+
&& !t.has_escaping_bound_vars()
1741+
{
1742+
let signature = component_cache.entry(t).or_insert_with(|| {
1743+
let mut components = Default::default();
1744+
rustc_type_ir::outlives::push_outlives_components(
1745+
self.cx(),
1746+
t,
1747+
&mut components,
1748+
);
1749+
1750+
let mut ids = Vec::new();
1751+
1752+
for component in components {
1753+
match component {
1754+
rustc_type_ir::outlives::Component::Region(reg) => {
1755+
let next_id = region_ids.len();
1756+
let id = *region_ids.entry(reg).or_insert(next_id);
1757+
ids.push(id);
1758+
}
1759+
_ => return None,
1760+
}
1761+
}
1762+
1763+
ids.sort_unstable();
1764+
ids.dedup();
1765+
1766+
(!ids.is_empty()).then_some(ids)
1767+
});
1768+
1769+
if let Some(signature) = signature {
1770+
// these constraints are ignored by leak checking
1771+
// only one needs to be kept
1772+
if !signatures.insert((rhs, signature.clone())) {
1773+
continue;
1774+
}
1775+
}
1776+
}
1777+
1778+
kept.push((constraint, vis));
1779+
}
1780+
1781+
*constraints = kept;
1782+
}
1783+
17141784
let canonical = canonicalize_response(
17151785
self.delegate,
17161786
self.max_input_universe,
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//@ revisions: valid short_x short_y short_both
2+
//@[valid] check-pass
3+
//@[short_x] check-fail
4+
//@[short_y] check-fail
5+
//@[short_both] check-fail
6+
//@ compile-flags: -Znext-solver=globally -Zpolonius=off
7+
//@ dont-check-compiler-stderr
8+
9+
// different types can have the same lifetime requirements
10+
11+
trait NeedsRegions<'a> {}
12+
13+
impl<'a, 'x, 'y> NeedsRegions<'a> for (&'x str, &'y str)
14+
where
15+
(&'x str, u8): 'a,
16+
(&'x str, u16): 'a,
17+
(&'y str, u8): 'a,
18+
(&'y str, u16): 'a,
19+
(&'x str, &'y str, u8): 'a,
20+
(&'x str, &'y str, u16): 'a,
21+
{}
22+
23+
trait Check {}
24+
25+
impl<'x, 'y> Check for (&'x str, &'y str)
26+
where
27+
for<'a> (&'x str, &'y str): NeedsRegions<'a>,
28+
{}
29+
30+
fn require<T: Check>() {}
31+
32+
#[cfg(valid)]
33+
fn check() {
34+
require::<(&'static str, &'static str)>();
35+
}
36+
37+
#[cfg(short_x)]
38+
fn check<'short>(_: &'short str) {
39+
require::<(&'short str, &'static str)>();
40+
//[short_x]~^ ERROR lifetime may not live long enough
41+
}
42+
43+
#[cfg(short_y)]
44+
fn check<'short>(_: &'short str) {
45+
require::<(&'static str, &'short str)>();
46+
//[short_y]~^ ERROR lifetime may not live long enough
47+
}
48+
49+
#[cfg(short_both)]
50+
fn check<'short>(_: &'short str) {
51+
require::<(&'short str, &'short str)>();
52+
//[short_both]~^ ERROR lifetime may not live long enough
53+
}
54+
55+
fn main() {}

0 commit comments

Comments
 (0)