Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 62 additions & 3 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, evaluate_solver_constraint};
use rustc_type_ir::relate::Relate;
Expand All @@ -18,8 +18,8 @@ use rustc_type_ir::solve::{
};
use rustc_type_ir::{
self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased,
OpaqueTypeKey, PredicateKind, Region, TypeFoldable, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor, TypingMode, eager_resolve_vars,
OpaqueTypeKey, PredicateKind, Region, RegionVid, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, eager_resolve_vars, max_universe,
};
use thin_vec::ThinVec;
use tracing::{Level, debug, instrument, trace, warn};
Expand Down Expand Up @@ -1608,6 +1608,65 @@ where
r.retain(|(outlives, _)| !outlives.is_trivial() && unique.insert(*outlives));
}

#[derive(Default)]
struct TrivialVars {
counts: HashMap<RegionVid, usize>,
}
impl<I> TypeVisitor<I> for TrivialVars
where
I: Interner,
{
type Result = ();
fn visit_ty(&mut self, t: I::Ty) {
// If a nested type doesn't have any `ReVar`s, then visiting it won't affect
// our `counts` anyway, so skip visiting it entirely for better perf.
if !t.has_infer_regions() {
return;
}
t.super_visit_with(self);
}
fn visit_const(&mut self, c: I::Const) {
// The same goes for consts.
if !c.has_infer_regions() {
return;
}
c.super_visit_with(self);
}
fn visit_region(&mut self, r: Region<I>) {
if let ty::ReVar(vid) = r.kind() {
*self.counts.entry(vid).or_insert(0) += 1;
}
}
}

// If we have a constraint like `'re: '?1`, where '?1 can name 're and '?1 appears
// nowhere else in the response besides the constraint itself, then this kind of
// constraint is also trivial, since we're able to pick '?1 := 'empty, and 're: 'empty
// is always true for any 're.
if !external_constraints.region_constraints.is_empty() {
let mut vis = TrivialVars::default();
var_values.visit_with(&mut vis);
external_constraints.visit_with(&mut vis);

if let ExternalRegionConstraints::Old(r) = &mut external_constraints.region_constraints
{
r.retain(|(outlives, _)| {
if let ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, re)) = *outlives
&& let Some(sup_re) = sup.as_region()
&& let ty::RegionKind::ReVar(vid) = re.kind()
// This is only safe if we call `eager_resolve_vars` beforehand,
// which we do.
&& self.delegate.universe_of_lt(vid).unwrap()
.can_name(max_universe(&**self.delegate, sup_re))
{
vis.counts.get(&vid).is_some_and(|c| *c > 1)
} else {
true
}
});
}
}

let canonical = canonicalize_response(
self.delegate,
self.max_input_universe,
Expand Down
21 changes: 21 additions & 0 deletions tests/ui/traits/next-solver/no-dedup-universes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//@ compile-flags: -Znext-solver -Zno-leak-check

//! Make sure we don't drop trivial-looking region constraints that would otherwise fail
//! leak check.

trait Trait {}
trait Other<'a, 'b> {}

struct Foo;
// We need this indirection because something direct like `for<'a> &'a (): 'b` gives us a
// TypeOutlives constraint, whereas we want to be testing how we handle RegionOutlives, and
// only `impl Other for Bar`'s where-clause can give us that.
impl<'b> Trait for Foo where for<'a> Bar: Other<'a, 'b> {}

struct Bar;
impl<'a, 'b> Other<'a, 'b> for Bar where 'a: 'b {}

fn f<T: Trait>(_: T) {}

fn main() { f(Foo); }
//~^ ERROR higher-ranked lifetime error
10 changes: 10 additions & 0 deletions tests/ui/traits/next-solver/no-dedup-universes.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: higher-ranked lifetime error
--> $DIR/no-dedup-universes.rs:20:13
|
LL | fn main() { f(Foo); }
| ^^^^^^
|
= note: could not prove `Foo: Trait`

error: aborting due to 1 previous error

Loading