Skip to content

Commit 33ac2c4

Browse files
committed
treat more kinds of regions as trivial in evaluate_added_goals_and_make_canonical_response
1 parent e776960 commit 33ac2c4

3 files changed

Lines changed: 93 additions & 3 deletions

File tree

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

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ops::ControlFlow;
33

44
#[cfg(feature = "nightly")]
55
use rustc_macros::StableHash;
6-
use rustc_type_ir::data_structures::HashSet;
6+
use rustc_type_ir::data_structures::{HashMap, HashSet};
77
use rustc_type_ir::inherent::*;
88
use rustc_type_ir::region_constraint::{RegionConstraint, evaluate_solver_constraint};
99
use rustc_type_ir::relate::Relate;
@@ -18,8 +18,8 @@ use rustc_type_ir::solve::{
1818
};
1919
use rustc_type_ir::{
2020
self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased,
21-
OpaqueTypeKey, PredicateKind, Region, TypeFoldable, TypeSuperVisitable, TypeVisitable,
22-
TypeVisitableExt, TypeVisitor, TypingMode, eager_resolve_vars,
21+
OpaqueTypeKey, PredicateKind, Region, RegionVid, TypeFoldable, TypeSuperVisitable,
22+
TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, eager_resolve_vars, max_universe,
2323
};
2424
use thin_vec::ThinVec;
2525
use tracing::{Level, debug, instrument, trace, warn};
@@ -1608,6 +1608,65 @@ where
16081608
r.retain(|(outlives, _)| !outlives.is_trivial() && unique.insert(*outlives));
16091609
}
16101610

1611+
#[derive(Default)]
1612+
struct TrivialVars {
1613+
counts: HashMap<RegionVid, usize>,
1614+
}
1615+
impl<I> TypeVisitor<I> for TrivialVars
1616+
where
1617+
I: Interner,
1618+
{
1619+
type Result = ();
1620+
fn visit_ty(&mut self, t: I::Ty) {
1621+
// If a nested type doesn't have any `ReVar`s, then visiting it won't affect
1622+
// our `counts` anyway, so skip visiting it entirely for better perf.
1623+
if !t.has_infer_regions() {
1624+
return;
1625+
}
1626+
t.super_visit_with(self);
1627+
}
1628+
fn visit_const(&mut self, c: I::Const) {
1629+
// The same goes for consts.
1630+
if !c.has_infer_regions() {
1631+
return;
1632+
}
1633+
c.super_visit_with(self);
1634+
}
1635+
fn visit_region(&mut self, r: Region<I>) {
1636+
if let ty::ReVar(vid) = r.kind() {
1637+
*self.counts.entry(vid).or_insert(0) += 1;
1638+
}
1639+
}
1640+
}
1641+
1642+
// If we have a constraint like `'re: '?1`, where '?1 can name 're and '?1 appears
1643+
// nowhere else in the response besides the constraint itself, then this kind of
1644+
// constraint is also trivial, since we're able to pick '?1 := 'empty, and 're: 'empty
1645+
// is always true for any 're.
1646+
if !external_constraints.region_constraints.is_empty() {
1647+
let mut vis = TrivialVars::default();
1648+
var_values.visit_with(&mut vis);
1649+
external_constraints.visit_with(&mut vis);
1650+
1651+
if let ExternalRegionConstraints::Old(r) = &mut external_constraints.region_constraints
1652+
{
1653+
r.retain(|(outlives, _)| {
1654+
if let ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, re)) = *outlives
1655+
&& let Some(sup_re) = sup.as_region()
1656+
&& let ty::RegionKind::ReVar(vid) = re.kind()
1657+
// This is only safe if we call `eager_resolve_vars` beforehand,
1658+
// which we do.
1659+
&& self.delegate.universe_of_lt(vid).unwrap()
1660+
.can_name(max_universe(&**self.delegate, sup_re))
1661+
{
1662+
vis.counts.get(&vid).is_some_and(|c| *c > 1)
1663+
} else {
1664+
true
1665+
}
1666+
});
1667+
}
1668+
}
1669+
16111670
let canonical = canonicalize_response(
16121671
self.delegate,
16131672
self.max_input_universe,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ compile-flags: -Znext-solver -Zno-leak-check
2+
3+
//! Make sure we don't drop trivial-looking region constraints that would otherwise fail
4+
//! leak check.
5+
6+
trait Trait {}
7+
trait Other<'a, 'b> {}
8+
9+
struct Foo;
10+
// We need this indirection because something direct like `for<'a> &'a (): 'b` gives us a
11+
// TypeOutlives constraint, whereas we want to be testing how we handle RegionOutlives, and
12+
// only `impl Other for Bar`'s where-clause can give us that.
13+
impl<'b> Trait for Foo where for<'a> Bar: Other<'a, 'b> {}
14+
15+
struct Bar;
16+
impl<'a, 'b> Other<'a, 'b> for Bar where 'a: 'b {}
17+
18+
fn f<T: Trait>(_: T) {}
19+
20+
fn main() { f(Foo); }
21+
//~^ ERROR higher-ranked lifetime error
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: higher-ranked lifetime error
2+
--> $DIR/no-dedup-universes.rs:19:13
3+
|
4+
LL | fn main() { f(Foo); }
5+
| ^^^^^^
6+
|
7+
= note: could not prove `Foo: Trait`
8+
9+
error: aborting due to 1 previous error
10+

0 commit comments

Comments
 (0)