Skip to content

Commit 65fc086

Browse files
committed
add a IsEmpty for use in verified bounds
We currently have a kind of arbitrary check for `Verify` conditions which says that if the "test region" is `'empty`, then the check passes. This was added to fix rust-lang#42467 -- it happens to be correct for the purposes that we use verify bounds for, but it doesn't feel generally correct. Replace with a more principled test.
1 parent 82c1435 commit 65fc086

File tree

4 files changed

+30
-8
lines changed

4 files changed

+30
-8
lines changed

src/librustc/infer/lexical_region_resolve/mod.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -592,12 +592,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
592592
debug!("collect_errors: verify={:?}", verify);
593593
let sub = var_data.normalize(self.tcx(), verify.region);
594594

595-
// This was an inference variable which didn't get
596-
// constrained, therefore it can be assume to hold.
597-
if let ty::ReEmpty = *sub {
598-
continue;
599-
}
600-
601595
let verify_kind_ty = verify.kind.to_ty(self.tcx());
602596
if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
603597
continue;
@@ -893,6 +887,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
893887
self.region_rels.is_subregion_of(min, var_values.normalize(self.tcx(), r))
894888
}
895889

890+
VerifyBound::IsEmpty => {
891+
if let ty::ReEmpty = min {
892+
true
893+
} else {
894+
false
895+
}
896+
}
897+
896898
VerifyBound::AnyBound(bs) => {
897899
bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min))
898900
}

src/librustc/infer/outlives/verify.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
6060
// scope type parameters:
6161
let param_bounds = param_bounds.chain(self.implicit_region_bound);
6262

63-
VerifyBound::AnyBound(param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect())
63+
let any_bounds: Vec<_> = param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect();
64+
65+
if any_bounds.is_empty() {
66+
// We know that all types `T` outlive `'empty`, so if we
67+
// can find no other bound, then check that the region
68+
// being tested is `'empty`.
69+
VerifyBound::IsEmpty
70+
} else {
71+
// If we can find any other bound R such that `T: R`, then
72+
// we don't need to check for `'empty`, because `R: 'empty`.
73+
VerifyBound::AnyBound(any_bounds)
74+
}
6475
}
6576

6677
/// Given a projection like `T::Item`, searches the environment

src/librustc/infer/region_constraints/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ pub enum VerifyBound<'tcx> {
233233
/// if `R: min`, then by transitivity `G: min`.
234234
OutlivedBy(Region<'tcx>),
235235

236+
/// Given a region `R`, true if it is `'empty`.
237+
IsEmpty,
238+
236239
/// Given a set of bounds `B`, expands to the function:
237240
///
238241
/// ```rust
@@ -867,6 +870,7 @@ impl<'tcx> VerifyBound<'tcx> {
867870
VerifyBound::IfEq(..) => false,
868871
VerifyBound::OutlivedBy(ty::ReStatic) => true,
869872
VerifyBound::OutlivedBy(_) => false,
873+
VerifyBound::IsEmpty => false,
870874
VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
871875
VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
872876
}
@@ -875,7 +879,7 @@ impl<'tcx> VerifyBound<'tcx> {
875879
pub fn cannot_hold(&self) -> bool {
876880
match self {
877881
VerifyBound::IfEq(_, b) => b.cannot_hold(),
878-
VerifyBound::OutlivedBy(ty::ReEmpty) => true,
882+
VerifyBound::IsEmpty => false,
879883
VerifyBound::OutlivedBy(_) => false,
880884
VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
881885
VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()),

src/librustc_mir/borrow_check/region_infer/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11081108
self.eval_if_eq(tcx, body, generic_ty, lower_bound, test_ty, verify_bound1)
11091109
}
11101110

1111+
VerifyBound::IsEmpty => {
1112+
let lower_bound_scc = self.constraint_sccs.scc(lower_bound);
1113+
self.scc_values.elements_contained_in(lower_bound_scc).next().is_none()
1114+
}
1115+
11111116
VerifyBound::OutlivedBy(r) => {
11121117
let r_vid = self.to_region_vid(r);
11131118
self.eval_outlives(r_vid, lower_bound)

0 commit comments

Comments
 (0)