mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-13 18:37:33 +00:00
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 #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.
This commit is contained in:
parent
82c143561f
commit
65fc086dba
@ -592,12 +592,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||
debug!("collect_errors: verify={:?}", verify);
|
||||
let sub = var_data.normalize(self.tcx(), verify.region);
|
||||
|
||||
// This was an inference variable which didn't get
|
||||
// constrained, therefore it can be assume to hold.
|
||||
if let ty::ReEmpty = *sub {
|
||||
continue;
|
||||
}
|
||||
|
||||
let verify_kind_ty = verify.kind.to_ty(self.tcx());
|
||||
if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
|
||||
continue;
|
||||
@ -893,6 +887,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||
self.region_rels.is_subregion_of(min, var_values.normalize(self.tcx(), r))
|
||||
}
|
||||
|
||||
VerifyBound::IsEmpty => {
|
||||
if let ty::ReEmpty = min {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
VerifyBound::AnyBound(bs) => {
|
||||
bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min))
|
||||
}
|
||||
|
@ -60,7 +60,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
// scope type parameters:
|
||||
let param_bounds = param_bounds.chain(self.implicit_region_bound);
|
||||
|
||||
VerifyBound::AnyBound(param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect())
|
||||
let any_bounds: Vec<_> = param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect();
|
||||
|
||||
if any_bounds.is_empty() {
|
||||
// We know that all types `T` outlive `'empty`, so if we
|
||||
// can find no other bound, then check that the region
|
||||
// being tested is `'empty`.
|
||||
VerifyBound::IsEmpty
|
||||
} else {
|
||||
// If we can find any other bound R such that `T: R`, then
|
||||
// we don't need to check for `'empty`, because `R: 'empty`.
|
||||
VerifyBound::AnyBound(any_bounds)
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a projection like `T::Item`, searches the environment
|
||||
|
@ -233,6 +233,9 @@ pub enum VerifyBound<'tcx> {
|
||||
/// if `R: min`, then by transitivity `G: min`.
|
||||
OutlivedBy(Region<'tcx>),
|
||||
|
||||
/// Given a region `R`, true if it is `'empty`.
|
||||
IsEmpty,
|
||||
|
||||
/// Given a set of bounds `B`, expands to the function:
|
||||
///
|
||||
/// ```rust
|
||||
@ -867,6 +870,7 @@ impl<'tcx> VerifyBound<'tcx> {
|
||||
VerifyBound::IfEq(..) => false,
|
||||
VerifyBound::OutlivedBy(ty::ReStatic) => true,
|
||||
VerifyBound::OutlivedBy(_) => false,
|
||||
VerifyBound::IsEmpty => false,
|
||||
VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
|
||||
VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
|
||||
}
|
||||
@ -875,7 +879,7 @@ impl<'tcx> VerifyBound<'tcx> {
|
||||
pub fn cannot_hold(&self) -> bool {
|
||||
match self {
|
||||
VerifyBound::IfEq(_, b) => b.cannot_hold(),
|
||||
VerifyBound::OutlivedBy(ty::ReEmpty) => true,
|
||||
VerifyBound::IsEmpty => false,
|
||||
VerifyBound::OutlivedBy(_) => false,
|
||||
VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
|
||||
VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()),
|
||||
|
@ -1108,6 +1108,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
self.eval_if_eq(tcx, body, generic_ty, lower_bound, test_ty, verify_bound1)
|
||||
}
|
||||
|
||||
VerifyBound::IsEmpty => {
|
||||
let lower_bound_scc = self.constraint_sccs.scc(lower_bound);
|
||||
self.scc_values.elements_contained_in(lower_bound_scc).next().is_none()
|
||||
}
|
||||
|
||||
VerifyBound::OutlivedBy(r) => {
|
||||
let r_vid = self.to_region_vid(r);
|
||||
self.eval_outlives(r_vid, lower_bound)
|
||||
|
Loading…
Reference in New Issue
Block a user