Skip to content
Merged
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
151 changes: 83 additions & 68 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1614,74 +1614,7 @@ where
r.retain(|(outlives, _)| !outlives.is_trivial() && unique.insert(*outlives));
}

#[derive(Default)]
struct NonTrivialVars {
vars: HashSet<RegionVid>,
}
impl<I> TypeVisitor<I> for NonTrivialVars
where
I: Interner,
{
type Result = ();
fn visit_ty(&mut self, t: I::Ty) {
// If a nested type doesn't have any `ReVar`s, then we won't insert
// anything into `vars` anyway, so skip 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.vars.insert(vid);
}
}
}

// If we have a constraint like `'re: '?1`, where '?1 can name 're and '?1 appears
// only on the RHS of region constraints, 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 let ExternalRegionConstraints::Old(r) = &mut external_constraints.region_constraints
&& !r.is_empty()
{
let mut vis = NonTrivialVars::default();
var_values.visit_with(&mut vis);
// We have to visit each component of `external_constraints` individually here
// because we skip the RHS of outlives constraints, and `TypeVisitor` doesn't
// have a method we can easily override in order to do this.
external_constraints.opaque_types.visit_with(&mut vis);
external_constraints.normalization_nested_goals.visit_with(&mut vis);
for (constraint, _) in r.iter() {
match constraint {
ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, _)) => {
sup.visit_with(&mut vis)
}
ty::RegionConstraint::Eq(eq) => eq.visit_with(&mut vis),
}
}

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_region(vid).unwrap()
.can_name(max_universe(&**self.delegate, sup_re))
{
vis.vars.contains(&vid)
} else {
true
}
});
}
filter_irrelevant_region_constraints(self.delegate, &var_values, &mut external_constraints);

let canonical = canonicalize_response(
self.delegate,
Expand Down Expand Up @@ -1802,6 +1735,88 @@ where
}
}

fn filter_irrelevant_region_constraints<D, I>(
delegate: &D,
var_values: &CanonicalVarValues<I>,
external_constraints: &mut ExternalConstraintsData<I>,
) where
D: SolverDelegate<Interner = I>,
I: Interner,
{
#[derive(Default)]
struct NonTrivialVars {
vars: HashSet<RegionVid>,
}
impl<I> TypeVisitor<I> for NonTrivialVars
where
I: Interner,
{
type Result = ();
fn visit_ty(&mut self, t: I::Ty) {
// If a nested type doesn't have any `ReVar`s, then we won't insert
// anything into `vars` anyway, so skip 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.vars.insert(vid);
}
}
}

let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } =
external_constraints;

// If we have a constraint like `'re: '?1`, where '?1 can name 're and '?1 appears
// only on the RHS of region constraints, then this kind of constraint is also trivial,
// since we're able to pick '?1 := glb('re, other_regions), and by definition of glb,
// `'re: glb`.
if let ExternalRegionConstraints::Old(r) = region_constraints
&& !r.is_empty()
{
let mut vis = NonTrivialVars::default();
var_values.visit_with(&mut vis);
// We have to visit each component of `external_constraints` individually here
// because we skip the RHS of outlives constraints, and `TypeVisitor` doesn't
// have a method we can easily override in order to do this.
opaque_types.visit_with(&mut vis);
normalization_nested_goals.visit_with(&mut vis);
for (constraint, _) in r.iter() {
match constraint {
ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, _)) => {
sup.visit_with(&mut vis)
}
ty::RegionConstraint::Eq(eq) => eq.visit_with(&mut vis),
}
}

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` before calling,
// this function, which we do.
&& delegate.universe_of_region(vid).unwrap()
.can_name(max_universe(&**delegate, sup_re))
{
vis.vars.contains(&vid)
} else {
true
}
});
}
}

#[derive(Debug)]
enum RerunDecision {
Yes,
Expand Down
Loading