Skip to content

Commit ad3c64d

Browse files
committed
Add some more documentation
1 parent 3d754f6 commit ad3c64d

File tree

1 file changed

+99
-42
lines changed

1 file changed

+99
-42
lines changed

compiler/rustc_borrowck/src/eliminate_placeholders.rs

Lines changed: 99 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_index::IndexVec;
1414
use rustc_infer::infer::NllRegionVariableOrigin;
1515
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
1616
use rustc_infer::infer::relate::TypeRelation;
17+
use rustc_middle::bug;
1718
use rustc_middle::ty::relate::{self, Relate, RelateResult};
1819
use rustc_middle::ty::{self, Region, RegionVid, Ty, TyCtxt, UniverseIndex};
1920
use rustc_span::Span;
@@ -30,6 +31,8 @@ use crate::ty::VarianceDiagInfo;
3031
use crate::type_check::Locations;
3132
use crate::universal_regions::UniversalRegions;
3233

34+
/// A set of outlives constraints after rewriting to remove
35+
/// higher-kinded constraints.
3336
pub(crate) struct LoweredConstraints<'tcx> {
3437
pub(crate) type_tests: Vec<LoweredTypeTest<'tcx>>,
3538
pub(crate) sccs: Sccs<RegionVid, ConstraintSccIndex>,
@@ -66,6 +69,7 @@ enum PlaceholderReachability {
6669
max_placeholder: RegionVid,
6770
},
6871
}
72+
6973
impl PlaceholderReachability {
7074
fn merge(self, other: PlaceholderReachability) -> PlaceholderReachability {
7175
use PlaceholderReachability::*;
@@ -101,7 +105,8 @@ impl PlaceholderReachability {
101105
}
102106

103107
/// An annotation for region graph SCCs that tracks
104-
/// the values of its elements.
108+
/// the values of its elements and properties of
109+
/// SCCs reached from them.
105110
#[derive(Copy, Debug, Clone)]
106111
struct RegionTracker {
107112
/// The representative Region Variable Id for this SCC.
@@ -113,7 +118,13 @@ struct RegionTracker {
113118
// Metadata about reachable placeholders
114119
reachable_placeholders: PlaceholderReachability,
115120

116-
// Track the existential with the smallest universe we reach.
121+
/// Track the existential with the smallest universe we reach.
122+
/// For existentials, the assigned universe corresponds to the
123+
/// largest universed placeholder they are allowed to end up in.
124+
///
125+
/// In other words, this tracks the smallest maximum (hardest constraint)
126+
/// of any existential this SCC reaches, and the rvid of the existential
127+
/// that brought it.
117128
min_universe_reachable_existential: Option<(UniverseIndex, RegionVid)>,
118129
}
119130

@@ -148,8 +159,8 @@ impl scc::Annotation for RegionTracker {
148159
// illegally reached universes, but they are not equally good as blame candidates.
149160
// In general, the ones with the smallest indices of their RegionVids will
150161
// be the best ones, and those will also be visited first. This code
151-
// then will suptly prefer a universe violation caused by a placeholder
152-
// with a small RegionVid over one with a large RegionVid.
162+
// then will suptly prefer a universe violation happening close from where the
163+
// constraint graph walk started over one that happens later.
153164
// FIXME: a potential optimisation if this is slow is to reimplement
154165
// this check as a boolean fuse, since it will idempotently turn
155166
// true once triggered and never go false again.
@@ -164,10 +175,14 @@ impl scc::Annotation for RegionTracker {
164175
}
165176
}
166177

178+
/// Select the worst universe-constrained of two existentials.
167179
fn smallest_reachable_existential(
168180
min_universe_reachable_existential_1: Option<(UniverseIndex, RegionVid)>,
169181
min_universe_reachable_existential_2: Option<(UniverseIndex, RegionVid)>,
170182
) -> Option<(UniverseIndex, RegionVid)> {
183+
// Note: this will prefer a small region vid over a large one. That's generally
184+
// good, but this probably does not affect the outcome. It might affect diagnostics
185+
// in the future.
171186
match (min_universe_reachable_existential_1, min_universe_reachable_existential_2) {
172187
(Some(a), Some(b)) => Some(std::cmp::min(a, b)),
173188
(a, b) => a.or(b),
@@ -307,6 +322,17 @@ impl scc::Annotations<RegionVid, ConstraintSccIndex, Representative>
307322
}
308323
}
309324

325+
/// Identify errors where placeholders illegally reach other regions, and generate
326+
/// errors stored into `errors_buffer`.
327+
///
328+
/// There are two sources of such errors:
329+
/// 1. A placeholder reaches (possibly transitively) another placeholder.
330+
/// 2. A placeholder `p` reaches (possibly transitively) an existential `e`,
331+
/// where `e` has an allowed maximum universe smaller than `p`'s.
332+
///
333+
/// There are other potential placeholder errors, but those are detected after
334+
/// region inference, since it may apply type tests or member constraints that
335+
/// alter the contents of SCCs and thus can't be detected at this point.
310336
#[instrument(skip(definitions, sccs, annotations, errors_buffer), level = "debug")]
311337
fn find_placeholder_mismatch_errors<'tcx>(
312338
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
@@ -395,8 +421,7 @@ fn find_placeholder_mismatch_errors<'tcx>(
395421
///
396422
/// This code is a stop-gap measure in preparation for the future trait solver.
397423
///
398-
/// Every constraint added by this method is an
399-
/// internal `IllegalUniverse` constraint.
424+
/// Every constraint added by this method is an internal `IllegalUniverse` constraint.
400425
#[instrument(skip(tcx, outlives_constraints))]
401426
pub(crate) fn rewrite_higher_kinded_outlives_as_constraints<'tcx>(
402427
mut outlives_constraints: OutlivesConstraintSet<'tcx>,
@@ -501,12 +526,17 @@ pub(crate) fn rewrite_higher_kinded_outlives_as_constraints<'tcx>(
501526
scc_annotations[sccs.scc(r1)].min_universe() != scc_annotations[sccs.scc(r2)].min_universe()
502527
};
503528

529+
// Rewrite member constraints to exclude choices of regions that would violate
530+
// the respective region's computed (minimum) universe.
504531
let member_constraints = member_constraints.into_mapped(
505532
|r| sccs.scc(r),
506533
|r| scc_annotations[sccs.scc(r)].in_root_universe(),
507534
different_universes,
508535
);
509536

537+
// We strip out the extra information and only keep the `Representative`;
538+
// all the information about placeholders and their universes is no longer
539+
// needed.
510540
let scc_representatives = scc_annotations
511541
.into_iter()
512542
.map(|rich_annotation| rich_annotation.into_representative())
@@ -529,13 +559,16 @@ fn rewrite_outlives<'tcx>(
529559
outlives_constraints: &mut OutlivesConstraintSet<'tcx>,
530560
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
531561
) -> FxHashSet<ConstraintSccIndex> {
532-
// Is this SCC already outliving static directly or transitively?
562+
// Is this SCC already outliving 'static directly or transitively?
533563
let mut outlives_static = FxHashSet::default();
534564

535565
let mut memoised_constraint_graph: Option<ConstraintGraph<Normal>> = None;
536566

537567
for scc in sccs.all_sccs() {
538568
let annotation: RegionTracker = annotations.scc_to_annotation[scc];
569+
// you may be tempted to add 'static to `outlives_static`, but
570+
// we need it to be empty if no constraints were added for a
571+
// later cheap check to see if we did any work.
539572
if scc == sccs.scc(fr_static) {
540573
trace!("Skipping adding 'static: 'static.");
541574
// No use adding 'static: 'static.
@@ -631,7 +664,10 @@ fn find_region<'tcx>(
631664
}
632665
}
633666
}
634-
unreachable!("Should have found something!");
667+
// since this function is used exclusively in this module, we know
668+
// we are only searching for regions we found in the region graph,
669+
// so if we don't find what we are looking for there's a bug somwehere.
670+
bug!("Should have found something!");
635671
}
636672

637673
#[derive(Debug, Clone)]
@@ -647,6 +683,7 @@ pub(crate) enum RewrittenVerifyBound<'tcx> {
647683
Unsatisfied,
648684
}
649685

686+
/// A type test rewritten to handle higher-kinded concerns.
650687
#[derive(Debug, Clone)]
651688
pub(crate) enum LoweredTypeTest<'tcx> {
652689
Untouched(TypeTest<'tcx>),
@@ -682,6 +719,8 @@ fn rewrite_verify_bound<'t>(
682719
// are both empty. This bit ensures that whatever comes out of the
683720
// bound also matches the placeholder reachability of the lower bound.
684721
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.
685724
let mut m = MatchUniverses::new(tcx, sccs, scc_annotations, universal_regions);
686725
let verify_if_eq = verify_if_eq_b.skip_binder();
687726
let what_error = m.relate(verify_if_eq.ty, generic_kind.to_ty(tcx));
@@ -731,43 +770,60 @@ fn rewrite_verify_bound<'t>(
731770
Either::Right(RewrittenVerifyBound::Unsatisfied)
732771
}
733772
}
734-
// Note that this (and below) claims the contents are always rewritten, even if they weren't.
735-
// This does not affect correctness, but is surprising.
736-
VerifyBound::AnyBound(verify_bounds) => Either::Right(RewrittenVerifyBound::AnyBound(
737-
verify_bounds
738-
.into_iter()
739-
.map(|bound| {
740-
rewrite_verify_bound(
741-
bound,
742-
lower_scc,
743-
sccs,
744-
scc_annotations,
745-
universal_regions,
746-
tcx,
747-
generic_kind,
748-
)
749-
})
750-
.collect(),
751-
)),
752-
VerifyBound::AllBounds(verify_bounds) => Either::Right(RewrittenVerifyBound::AllBounds(
753-
verify_bounds
754-
.into_iter()
755-
.map(|bound| {
756-
rewrite_verify_bound(
757-
bound,
758-
lower_scc,
759-
sccs,
760-
scc_annotations,
761-
universal_regions,
762-
tcx,
763-
generic_kind,
764-
)
765-
})
766-
.collect(),
767-
)),
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+
)))
797+
}
768798
}
769799
}
770800

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()
825+
}
826+
771827
impl<'t> TypeTest<'t> {
772828
#[instrument(skip(sccs, tcx, universal_regions, scc_annotations), ret)]
773829
fn rewrite_higher_kinded_constraints(
@@ -873,6 +929,7 @@ impl<'tcx, 'v> TypeRelation<TyCtxt<'tcx>> for MatchUniverses<'tcx, 'v> {
873929
}
874930
}
875931

932+
/// A `TypeRelation` visitor that computes the largest universe.
876933
struct MatchUniverses<'tcx, 'v> {
877934
tcx: TyCtxt<'tcx>,
878935
pattern_depth: ty::DebruijnIndex,

0 commit comments

Comments
 (0)