mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +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);
|
debug!("collect_errors: verify={:?}", verify);
|
||||||
let sub = var_data.normalize(self.tcx(), verify.region);
|
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());
|
let verify_kind_ty = verify.kind.to_ty(self.tcx());
|
||||||
if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
|
if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
|
||||||
continue;
|
continue;
|
||||||
@ -893,6 +887,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||||||
self.region_rels.is_subregion_of(min, var_values.normalize(self.tcx(), r))
|
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) => {
|
VerifyBound::AnyBound(bs) => {
|
||||||
bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min))
|
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:
|
// scope type parameters:
|
||||||
let param_bounds = param_bounds.chain(self.implicit_region_bound);
|
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
|
/// 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`.
|
/// if `R: min`, then by transitivity `G: min`.
|
||||||
OutlivedBy(Region<'tcx>),
|
OutlivedBy(Region<'tcx>),
|
||||||
|
|
||||||
|
/// Given a region `R`, true if it is `'empty`.
|
||||||
|
IsEmpty,
|
||||||
|
|
||||||
/// Given a set of bounds `B`, expands to the function:
|
/// Given a set of bounds `B`, expands to the function:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -867,6 +870,7 @@ impl<'tcx> VerifyBound<'tcx> {
|
|||||||
VerifyBound::IfEq(..) => false,
|
VerifyBound::IfEq(..) => false,
|
||||||
VerifyBound::OutlivedBy(ty::ReStatic) => true,
|
VerifyBound::OutlivedBy(ty::ReStatic) => true,
|
||||||
VerifyBound::OutlivedBy(_) => false,
|
VerifyBound::OutlivedBy(_) => false,
|
||||||
|
VerifyBound::IsEmpty => false,
|
||||||
VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
|
VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
|
||||||
VerifyBound::AllBounds(bs) => bs.iter().all(|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 {
|
pub fn cannot_hold(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
VerifyBound::IfEq(_, b) => b.cannot_hold(),
|
VerifyBound::IfEq(_, b) => b.cannot_hold(),
|
||||||
VerifyBound::OutlivedBy(ty::ReEmpty) => true,
|
VerifyBound::IsEmpty => false,
|
||||||
VerifyBound::OutlivedBy(_) => false,
|
VerifyBound::OutlivedBy(_) => false,
|
||||||
VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
|
VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
|
||||||
VerifyBound::AllBounds(bs) => bs.iter().any(|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)
|
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) => {
|
VerifyBound::OutlivedBy(r) => {
|
||||||
let r_vid = self.to_region_vid(r);
|
let r_vid = self.to_region_vid(r);
|
||||||
self.eval_outlives(r_vid, lower_bound)
|
self.eval_outlives(r_vid, lower_bound)
|
||||||
|
Loading…
Reference in New Issue
Block a user