diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 6ed70b39c5b7f..45a3a376a952a 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -853,19 +853,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.eval_if_eq(infcx, generic_ty, lower_bound, *verify_if_eq_b) } - 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) } - VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| { - self.eval_verify_bound(infcx, generic_ty, lower_bound, verify_bound) - }), + VerifyBound::AnyBound(verify_bounds) => { + !verify_bounds.is_empty() + && verify_bounds.iter().any(|verify_bound| { + self.eval_verify_bound(infcx, generic_ty, lower_bound, verify_bound) + }) + } VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| { self.eval_verify_bound(infcx, generic_ty, lower_bound, verify_bound) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 703223e2e54a3..80488d140d674 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,10 +6,10 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::traits::query::type_op::DeeplyNormalize; -use rustc_middle::bug; use rustc_middle::ty::{ self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions, }; +use rustc_middle::{bug, span_bug}; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use tracing::{debug, instrument}; @@ -240,6 +240,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { verify_bound: VerifyBound<'tcx>, ) -> TypeTest<'tcx> { let lower_bound = self.to_region_vid(region); + if let VerifyBound::AnyBound(bs) = &verify_bound + && bs.is_empty() + { + span_bug!(self.span, "No empty any bound should make it to borrow check!"); + } TypeTest { generic_kind, lower_bound, span: self.span, verify_bound } } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 5134b7b7ca8f1..73d3558e368af 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -952,16 +952,24 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { self.sub_region_values(a, b) } - VerifyBound::IsEmpty => match min.kind() { + // An empty bound holds for an empty variable. + VerifyBound::AnyBound(bs) if bs.is_empty() => match min.kind() { ty::ReVar(rid) => match var_values.values[rid] { VarValue::ErrorValue => false, - VarValue::Empty(_) => true, + VarValue::Empty(_) => { + debug!( + "This bound was empty which should be true: {:?} {min:?}, {generic_ty:?}", + var_values.values + ); + false + } VarValue::Value(_) => false, }, _ => false, }, VerifyBound::AnyBound(bs) => { + // Edge case: an empty any bound does not hold. bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min)) } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index affeb01e6d052..46fc712157736 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -63,17 +63,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { param_bounds.push(VerifyBound::OutlivedBy(r)); } - if param_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 param_bounds.len() == 1 { + if param_bounds.len() == 1 { // Micro-opt: no need to store the vector if it's just len 1 param_bounds.pop().unwrap() } 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(param_bounds) } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index ae7481b5d1e76..7bb18ee186959 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -163,9 +163,6 @@ 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: /// /// ```ignore (pseudo-rust) @@ -690,7 +687,6 @@ impl<'tcx> VerifyBound<'tcx> { match self { VerifyBound::IfEq(..) => false, VerifyBound::OutlivedBy(re) => re.is_static(), - VerifyBound::IsEmpty => false, VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()), VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()), } @@ -699,8 +695,8 @@ impl<'tcx> VerifyBound<'tcx> { pub fn cannot_hold(&self) -> bool { match self { VerifyBound::IfEq(..) => false, - VerifyBound::IsEmpty => false, VerifyBound::OutlivedBy(_) => false, + // Edge case: am empty any (or all) bound cannot hold: VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()), VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()), }