Skip to content

Commit b5a6590

Browse files
committed
Stop introducing a new enum variant for rewritten type tests
1 parent ad3c64d commit b5a6590

File tree

5 files changed

+249
-343
lines changed

5 files changed

+249
-343
lines changed

compiler/rustc_borrowck/src/eliminate_placeholders.rs

+121-164
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
88
use std::collections::VecDeque;
99

10-
use either::Either;
1110
use rustc_data_structures::fx::FxHashSet;
1211
use rustc_data_structures::graph::scc::{self, Sccs};
1312
use rustc_index::IndexVec;
@@ -17,7 +16,6 @@ use rustc_infer::infer::relate::TypeRelation;
1716
use rustc_middle::bug;
1817
use rustc_middle::ty::relate::{self, Relate, RelateResult};
1918
use rustc_middle::ty::{self, Region, RegionVid, Ty, TyCtxt, UniverseIndex};
20-
use rustc_span::Span;
2119
use tracing::{debug, instrument, trace};
2220

2321
use crate::ConstraintCategory;
@@ -26,15 +24,15 @@ use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet};
2624
use crate::consumers::OutlivesConstraint;
2725
use crate::diagnostics::{RegionErrorKind, RegionErrors};
2826
use crate::member_constraints::MemberConstraintSet;
29-
use crate::region_infer::{RegionDefinition, Representative, TypeTest};
27+
use crate::region_infer::{RegionDefinition, Representative, TypeTest, TypeTestOrigin};
3028
use crate::ty::VarianceDiagInfo;
3129
use crate::type_check::Locations;
3230
use crate::universal_regions::UniversalRegions;
3331

3432
/// A set of outlives constraints after rewriting to remove
3533
/// higher-kinded constraints.
3634
pub(crate) struct LoweredConstraints<'tcx> {
37-
pub(crate) type_tests: Vec<LoweredTypeTest<'tcx>>,
35+
pub(crate) type_tests: Vec<TypeTest<'tcx>>,
3836
pub(crate) sccs: Sccs<RegionVid, ConstraintSccIndex>,
3937
pub(crate) definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
4038
pub(crate) scc_representatives: IndexVec<ConstraintSccIndex, Representative>,
@@ -463,10 +461,7 @@ pub(crate) fn rewrite_higher_kinded_outlives_as_constraints<'tcx>(
463461
&mut annotations,
464462
);
465463
return LoweredConstraints {
466-
type_tests: type_tests
467-
.into_iter()
468-
.map(|type_test| LoweredTypeTest::Untouched(type_test))
469-
.collect(),
464+
type_tests, // Pass them through unmodified.
470465
member_constraints: member_constraints.into_mapped(
471466
|r| sccs.scc(r),
472467
|_| true,
@@ -670,158 +665,121 @@ fn find_region<'tcx>(
670665
bug!("Should have found something!");
671666
}
672667

673-
#[derive(Debug, Clone)]
674-
pub(crate) enum RewrittenVerifyBound<'tcx> {
675-
AnyBound(Vec<Either<VerifyBound<'tcx>, RewrittenVerifyBound<'tcx>>>),
676-
AllBounds(Vec<Either<VerifyBound<'tcx>, RewrittenVerifyBound<'tcx>>>),
677-
678-
/// Given a region `R`, true if `R: 'static`. Used during lowering
679-
/// of higher-kinded constraints.
680-
OutlivesStatic(Region<'tcx>),
681-
682-
/// The bottom bound, which is never satisfied.
683-
Unsatisfied,
684-
}
685-
686-
/// A type test rewritten to handle higher-kinded concerns.
687-
#[derive(Debug, Clone)]
688-
pub(crate) enum LoweredTypeTest<'tcx> {
689-
Untouched(TypeTest<'tcx>),
690-
Rewritten {
691-
rewritten_bound: RewrittenVerifyBound<'tcx>,
692-
/// The type `T` that must outlive the region.
693-
generic_kind: GenericKind<'tcx>,
694-
695-
/// The region `'x` that the type must outlive.
696-
lower_bound: RegionVid,
697-
698-
/// The span to blame.
699-
span: Span,
700-
},
668+
struct TypeTestRewriter<'c, 'tcx> {
669+
lower_scc: ConstraintSccIndex,
670+
sccs: &'c Sccs<RegionVid, ConstraintSccIndex>,
671+
scc_annotations: &'c IndexVec<ConstraintSccIndex, RegionTracker>,
672+
universal_regions: &'c UniversalRegions<'tcx>,
673+
tcx: TyCtxt<'tcx>,
674+
generic_kind: GenericKind<'tcx>,
701675
}
702676

703-
#[instrument(skip(sccs, scc_annotations, universal_regions, tcx), ret)]
704-
fn rewrite_verify_bound<'t>(
705-
bound: VerifyBound<'t>,
706-
lower_scc: ConstraintSccIndex,
707-
sccs: &Sccs<RegionVid, ConstraintSccIndex>,
708-
scc_annotations: &IndexVec<ConstraintSccIndex, RegionTracker>,
709-
universal_regions: &UniversalRegions<'t>,
710-
tcx: TyCtxt<'t>,
711-
generic_kind: GenericKind<'t>,
712-
) -> Either<VerifyBound<'t>, RewrittenVerifyBound<'t>> {
713-
let lower = scc_annotations[lower_scc];
714-
match bound {
715-
// You may think that an equality bound would imply universe
716-
// equality, and it does -- except that we do not track placeholders,
717-
// and so in the event that you have two empty regions, one of which is
718-
// in an unnameable universe, they would compare equal since they
719-
// are both empty. This bit ensures that whatever comes out of the
720-
// bound also matches the placeholder reachability of the lower bound.
721-
VerifyBound::IfEq(verify_if_eq_b) => {
722-
// this bit picks out the worst possible candidate that can end up for the match
723-
// in terms of its universe.
724-
let mut m = MatchUniverses::new(tcx, sccs, scc_annotations, universal_regions);
725-
let verify_if_eq = verify_if_eq_b.skip_binder();
726-
let what_error = m.relate(verify_if_eq.ty, generic_kind.to_ty(tcx));
727-
if let Err(e) = what_error {
728-
debug!("Type test {verify_if_eq_b:?} {generic_kind:?} failed to match with {e:?}");
729-
return Either::Right(RewrittenVerifyBound::Unsatisfied);
677+
impl<'c, 'tcx> TypeTestRewriter<'c, 'tcx> {
678+
fn annotation(&self, rvid: RegionVid) -> RegionTracker {
679+
self.scc_annotations[self.sccs.scc(rvid)]
680+
}
681+
682+
/// Determine if a region is compatible with the lower bound's
683+
/// universe.
684+
fn universe_compatible_with_bound(&self, r: Region<'tcx>) -> bool {
685+
let rvid = self.universal_regions.to_region_vid(r);
686+
rvid == self.universal_regions.fr_static
687+
|| self.annotation(rvid).universe_compatible_with(self.scc_annotations[self.lower_scc])
688+
}
689+
690+
#[instrument(skip(self), ret)]
691+
fn rewrite(&self, bound: &VerifyBound<'tcx>) -> Option<VerifyBound<'tcx>> {
692+
let lower = self.scc_annotations[self.lower_scc];
693+
match bound {
694+
// You may think that an equality bound would imply universe
695+
// equality, and it does -- except that we do not track placeholders,
696+
// and so in the event that you have two empty regions, one of which is
697+
// in an unnameable universe, they would compare equal since they
698+
// are both empty. This bit ensures that whatever comes out of the
699+
// bound also matches the placeholder reachability of the lower bound.
700+
VerifyBound::IfEq(verify_if_eq_b) => {
701+
// this bit picks out the worst possible candidate that can end up for the match
702+
// in terms of its universe.
703+
let mut m = MatchUniverses::new(
704+
self.tcx,
705+
self.sccs,
706+
self.scc_annotations,
707+
self.universal_regions,
708+
);
709+
let verify_if_eq = verify_if_eq_b.skip_binder();
710+
let what_error = m.relate(verify_if_eq.ty, self.generic_kind.to_ty(self.tcx));
711+
if let Err(e) = what_error {
712+
debug!(
713+
"Type test {verify_if_eq_b:?} {generic_kind:?} failed to match with {e:?}",
714+
generic_kind = self.generic_kind
715+
);
716+
return Some(VerifyBound::never_satisfied());
717+
}
718+
719+
let r = if let ty::RegionKind::ReBound(depth, _) = verify_if_eq.bound.kind() {
720+
assert!(depth == ty::INNERMOST);
721+
m.max_universe_region.map_or(self.tcx.lifetimes.re_static, |pair| pair.1)
722+
} else {
723+
verify_if_eq.bound
724+
};
725+
726+
if self.universe_compatible_with_bound(r) {
727+
None
728+
} else {
729+
Some(VerifyBound::never_satisfied())
730+
}
731+
}
732+
// Rewrite an outlives bound to an outlives-static bound upon referencing
733+
// an unnameable universe (from a placeholder).
734+
VerifyBound::OutlivedBy(region) => {
735+
if self.universe_compatible_with_bound(*region) {
736+
None
737+
} else {
738+
Some(VerifyBound::OutlivesStatic(*region))
739+
}
740+
}
741+
// Nothing in here to violate a universe, but since we can't detect
742+
// bounds being violated by placeholders when we don't track placeholders,
743+
// we ensure that we don't reach any.
744+
VerifyBound::IsEmpty => {
745+
if matches!(lower.reachable_placeholders, PlaceholderReachability::NoPlaceholders) {
746+
None
747+
} else {
748+
debug!("Empty bound reaches placeholders: {:?}", lower.reachable_placeholders);
749+
Some(VerifyBound::never_satisfied())
750+
}
751+
}
752+
VerifyBound::AnyBound(verify_bounds) => {
753+
self.rewrite_bounds(verify_bounds).map(VerifyBound::AnyBound)
730754
}
731755

732-
let r = if let ty::RegionKind::ReBound(depth, _) = verify_if_eq.bound.kind() {
733-
assert!(depth == ty::INNERMOST);
734-
m.max_universe_region.map_or(tcx.lifetimes.re_static, |pair| pair.1)
735-
} else {
736-
verify_if_eq.bound
737-
};
738-
739-
let l_scc = scc_annotations[lower_scc];
740-
let rvid = universal_regions.to_region_vid(r);
741-
742-
if rvid == universal_regions.fr_static
743-
|| scc_annotations[sccs.scc(rvid)].universe_compatible_with(l_scc)
744-
{
745-
Either::Left(bound)
746-
} else {
747-
Either::Right(RewrittenVerifyBound::Unsatisfied)
756+
VerifyBound::AllBounds(verify_bounds) => {
757+
self.rewrite_bounds(verify_bounds).map(VerifyBound::AllBounds)
748758
}
749-
}
750-
// Rewrite an outlives bound to an outlives-static bound upon referencing
751-
// an unnameable universe (from a placeholder).
752-
VerifyBound::OutlivedBy(region) => {
753-
let rvid = universal_regions.to_region_vid(region);
754-
if rvid == universal_regions.fr_static
755-
|| scc_annotations[sccs.scc(rvid)].universe_compatible_with(lower)
756-
{
757-
either::Left(bound)
758-
} else {
759-
Either::Right(RewrittenVerifyBound::OutlivesStatic(region))
759+
VerifyBound::OutlivesStatic(_) => {
760+
bug!("Unexpected OutlivesStatic bound; they should not have been introduced yet!")
760761
}
761762
}
762-
// Nothing in here to violate a universe, but since we can't detect
763-
// bounds being violated by placeholders when we don't track placeholders,
764-
// we ensure that we don't reach any.
765-
VerifyBound::IsEmpty => {
766-
if matches!(lower.reachable_placeholders, PlaceholderReachability::NoPlaceholders) {
767-
Either::Left(bound)
763+
}
764+
765+
fn rewrite_bounds(
766+
&self,
767+
verify_bounds: &Vec<VerifyBound<'tcx>>,
768+
) -> Option<Vec<VerifyBound<'tcx>>> {
769+
let mut bounds = Vec::with_capacity(verify_bounds.len());
770+
let mut rewrote_any = false;
771+
for bound in verify_bounds {
772+
let bound = if let Some(rewritten) = self.rewrite(&bound) {
773+
rewrote_any = true;
774+
rewritten
768775
} else {
769-
debug!("Empty bound reaches placeholders: {:?}", lower.reachable_placeholders);
770-
Either::Right(RewrittenVerifyBound::Unsatisfied)
771-
}
772-
}
773-
// It's tempting to try to rewrite this or the next one to be able to
774-
// return the regular bounds if in fact none of them needed rewriting,
775-
// but for reasons of "computer is dumb" this is trickier than you may think.
776-
VerifyBound::AnyBound(verify_bounds) => {
777-
either::Right(RewrittenVerifyBound::AnyBound(rewrite_verify_bounds(
778-
verify_bounds,
779-
lower_scc,
780-
sccs,
781-
scc_annotations,
782-
universal_regions,
783-
tcx,
784-
generic_kind,
785-
)))
786-
}
787-
VerifyBound::AllBounds(verify_bounds) => {
788-
either::Right(RewrittenVerifyBound::AllBounds(rewrite_verify_bounds(
789-
verify_bounds,
790-
lower_scc,
791-
sccs,
792-
scc_annotations,
793-
universal_regions,
794-
tcx,
795-
generic_kind,
796-
)))
776+
bound.clone()
777+
};
778+
bounds.push(bound);
797779
}
798-
}
799-
}
800780

801-
// FIXME This is crying out for a TypeTestRewritingContext.
802-
fn rewrite_verify_bounds<'t>(
803-
verify_bounds: Vec<VerifyBound<'t>>,
804-
lower_scc: ConstraintSccIndex,
805-
sccs: &Sccs<RegionVid, ConstraintSccIndex>,
806-
scc_annotations: &IndexVec<ConstraintSccIndex, RegionTracker>,
807-
universal_regions: &UniversalRegions<'t>,
808-
tcx: TyCtxt<'t>,
809-
generic_kind: GenericKind<'t>,
810-
) -> Vec<Either<VerifyBound<'t>, RewrittenVerifyBound<'t>>> {
811-
verify_bounds
812-
.into_iter()
813-
.map(|bound| {
814-
rewrite_verify_bound(
815-
bound,
816-
lower_scc,
817-
sccs,
818-
scc_annotations,
819-
universal_regions,
820-
tcx,
821-
generic_kind,
822-
)
823-
})
824-
.collect()
781+
if rewrote_any { Some(bounds) } else { None }
782+
}
825783
}
826784

827785
impl<'t> TypeTest<'t> {
@@ -832,26 +790,25 @@ impl<'t> TypeTest<'t> {
832790
scc_annotations: &IndexVec<ConstraintSccIndex, RegionTracker>,
833791
universal_regions: &UniversalRegions<'t>,
834792
tcx: TyCtxt<'t>,
835-
) -> LoweredTypeTest<'t> {
836-
let lower_scc = sccs.scc(self.lower_bound);
837-
match rewrite_verify_bound(
838-
self.verify_bound,
839-
lower_scc,
793+
) -> Self {
794+
let rewriter = TypeTestRewriter {
795+
generic_kind: self.generic_kind,
840796
sccs,
841797
scc_annotations,
842798
universal_regions,
843799
tcx,
844-
self.generic_kind,
845-
) {
846-
Either::Left(untouched_bound) => {
847-
LoweredTypeTest::Untouched(TypeTest { verify_bound: untouched_bound, ..self })
848-
}
849-
Either::Right(rewritten_bound) => LoweredTypeTest::Rewritten {
850-
rewritten_bound,
800+
lower_scc: sccs.scc(self.lower_bound),
801+
};
802+
803+
if let Some(rewritten_bound) = rewriter.rewrite(&self.verify_bound) {
804+
TypeTest {
805+
verify_bound: rewritten_bound,
851806
generic_kind: self.generic_kind,
852807
lower_bound: self.lower_bound,
853-
span: self.span,
854-
},
808+
source: TypeTestOrigin::Rewritten(Box::new(self)),
809+
}
810+
} else {
811+
self
855812
}
856813
}
857814
}

0 commit comments

Comments
 (0)