Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 733bb16

Browse files
committedMar 19, 2025
Revise the handling of equals type-tests for lazy constraint rewriting
1 parent dc8de74 commit 733bb16

File tree

2 files changed

+136
-23
lines changed

2 files changed

+136
-23
lines changed
 

‎compiler/rustc_borrowck/src/eliminate_placeholders.rs

+133-20
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ use rustc_data_structures::fx::FxHashSet;
1212
use rustc_data_structures::graph::scc::{self, Sccs};
1313
use rustc_index::IndexVec;
1414
use rustc_infer::infer::NllRegionVariableOrigin;
15-
use rustc_infer::infer::outlives::test_type_match::MatchAgainstHigherRankedOutlives;
1615
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
1716
use rustc_infer::infer::relate::TypeRelation;
18-
use rustc_middle::ty::{self, Region, RegionVid, TyCtxt, UniverseIndex};
17+
use rustc_middle::ty::relate::{self, Relate, RelateResult};
18+
use rustc_middle::ty::{self, Region, RegionVid, Ty, TyCtxt, UniverseIndex};
1919
use rustc_span::Span;
2020
use tracing::{debug, instrument, trace};
2121

@@ -627,33 +627,27 @@ fn rewrite_verify_bound<'t>(
627627
// are both empty. This bit ensures that whatever comes out of the
628628
// bound also matches the placeholder reachability of the lower bound.
629629
VerifyBound::IfEq(verify_if_eq_b) => {
630-
let mut m = MatchAgainstHigherRankedOutlives::new(tcx);
630+
let mut m = MatchUniverses::new(tcx, sccs, scc_annotations, universal_regions);
631631
let verify_if_eq = verify_if_eq_b.skip_binder();
632-
// We ignore the error here because we are not concerned with if the
633-
// match actually held -- we can't tell that yet -- we just want to
634-
// see if the resulting region can't match for universe-related
635-
// reasons.
636-
let _what_error = m.relate(verify_if_eq.ty, generic_kind.to_ty(tcx));
632+
let what_error = m.relate(verify_if_eq.ty, generic_kind.to_ty(tcx));
633+
if let Err(e) = what_error {
634+
debug!("Type test {verify_if_eq_b:?} {generic_kind:?} failed to match with {e:?}");
635+
return Either::Right(RewrittenVerifyBound::Unsatisfied);
636+
}
637637

638-
let r = if let ty::RegionKind::ReBound(depth, br) = verify_if_eq.bound.kind() {
638+
let r = if let ty::RegionKind::ReBound(depth, _) = verify_if_eq.bound.kind() {
639639
assert!(depth == ty::INNERMOST);
640-
match m.map.get(&br) {
641-
Some(&r) => r,
642-
None => tcx.lifetimes.re_static,
643-
}
640+
m.max_universe_region.map_or(tcx.lifetimes.re_static, |pair| pair.1)
644641
} else {
645642
verify_if_eq.bound
646643
};
647644

648-
let r_vid = universal_regions.to_region_vid(r);
649-
let r_scc = scc_annotations[sccs.scc(r_vid)];
650645
let l_scc = scc_annotations[lower_scc];
651-
let in_same_universe =
652-
r_scc.universe_compatible_with(l_scc) && l_scc.universe_compatible_with(r_scc);
653-
let reaches_same_placeholders =
654-
r_scc.reachable_placeholders == l_scc.reachable_placeholders;
646+
let rvid = universal_regions.to_region_vid(r);
655647

656-
if in_same_universe && reaches_same_placeholders {
648+
if rvid == universal_regions.fr_static
649+
|| scc_annotations[sccs.scc(rvid)].universe_compatible_with(l_scc)
650+
{
657651
Either::Left(bound)
658652
} else {
659653
Either::Right(RewrittenVerifyBound::Unsatisfied)
@@ -750,3 +744,122 @@ impl<'t> TypeTest<'t> {
750744
}
751745
}
752746
}
747+
748+
impl<'tcx, 'v> TypeRelation<TyCtxt<'tcx>> for MatchUniverses<'tcx, 'v> {
749+
fn cx(&self) -> TyCtxt<'tcx> {
750+
self.tcx
751+
}
752+
753+
#[instrument(level = "trace", skip(self))]
754+
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
755+
&mut self,
756+
variance: ty::Variance,
757+
_: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
758+
a: T,
759+
b: T,
760+
) -> RelateResult<'tcx, T> {
761+
// Opaque types args have lifetime parameters.
762+
// We must not check them to be equal, as we never insert anything to make them so.
763+
if variance != ty::Bivariant { self.relate(a, b) } else { Ok(a) }
764+
}
765+
766+
#[instrument(skip(self), level = "trace")]
767+
fn regions(
768+
&mut self,
769+
pattern: ty::Region<'tcx>,
770+
value: ty::Region<'tcx>,
771+
) -> RelateResult<'tcx, ty::Region<'tcx>> {
772+
// `pattern` is from inside `VerifyBound::IfEq`, and `value` from `generic_kind` (what we're looking for).
773+
if pattern == value {
774+
self.update_max_universe(pattern);
775+
} else {
776+
assert!(
777+
pattern.is_bound() || self.universe_of(pattern).is_root(),
778+
"{pattern:?} neither bound nor in root universe. Universe is: {:?}, kind: {:?}",
779+
self.universe_of(pattern),
780+
pattern.kind()
781+
);
782+
}
783+
784+
if let Some((_, max_universed_region)) = self.max_universe_region.as_ref() {
785+
Ok(*max_universed_region)
786+
} else {
787+
Ok(pattern)
788+
}
789+
}
790+
791+
#[instrument(skip(self), level = "trace")]
792+
fn tys(&mut self, pattern: Ty<'tcx>, value: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
793+
relate::structurally_relate_tys(self, pattern, value)
794+
}
795+
796+
#[instrument(skip(self), level = "trace")]
797+
fn consts(
798+
&mut self,
799+
pattern: ty::Const<'tcx>,
800+
value: ty::Const<'tcx>,
801+
) -> RelateResult<'tcx, ty::Const<'tcx>> {
802+
relate::structurally_relate_consts(self, pattern, value)
803+
}
804+
805+
#[instrument(skip(self), level = "trace")]
806+
fn binders<T>(
807+
&mut self,
808+
pattern: ty::Binder<'tcx, T>,
809+
value: ty::Binder<'tcx, T>,
810+
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
811+
where
812+
T: Relate<TyCtxt<'tcx>>,
813+
{
814+
self.pattern_depth.shift_in(1);
815+
let result = Ok(pattern.rebind(self.relate(pattern.skip_binder(), value.skip_binder())?));
816+
self.pattern_depth.shift_out(1);
817+
result
818+
}
819+
}
820+
821+
struct MatchUniverses<'tcx, 'v> {
822+
tcx: TyCtxt<'tcx>,
823+
pattern_depth: ty::DebruijnIndex,
824+
max_universe_region: Option<(UniverseIndex, ty::Region<'tcx>)>,
825+
sccs: &'v Sccs<RegionVid, ConstraintSccIndex>,
826+
scc_annotations: &'v IndexVec<ConstraintSccIndex, RegionTracker>,
827+
universal_regions: &'v UniversalRegions<'tcx>,
828+
}
829+
830+
impl<'tcx, 'v> MatchUniverses<'tcx, 'v> {
831+
fn new(
832+
tcx: TyCtxt<'tcx>,
833+
sccs: &'v Sccs<RegionVid, ConstraintSccIndex>,
834+
scc_annotations: &'v IndexVec<ConstraintSccIndex, RegionTracker>,
835+
universal_regions: &'v UniversalRegions<'tcx>,
836+
) -> MatchUniverses<'tcx, 'v> {
837+
MatchUniverses {
838+
tcx,
839+
pattern_depth: ty::INNERMOST,
840+
max_universe_region: None,
841+
scc_annotations,
842+
sccs,
843+
universal_regions,
844+
}
845+
}
846+
847+
fn universe_of(&self, r: ty::Region<'tcx>) -> UniverseIndex {
848+
self.scc_annotations[self.sccs.scc(self.universal_regions.to_region_vid(r))].min_universe()
849+
}
850+
851+
#[instrument(skip(self), level = "trace")]
852+
fn update_max_universe(&mut self, r: ty::Region<'tcx>) {
853+
let r_universe = self.universe_of(r);
854+
855+
let Some((current_max_u, current_max_r)) = self.max_universe_region else {
856+
self.max_universe_region = Some((r_universe, r));
857+
return;
858+
};
859+
self.max_universe_region = if r_universe > current_max_u {
860+
Some((r_universe, r))
861+
} else {
862+
Some((current_max_u, current_max_r))
863+
}
864+
}
865+
}

‎compiler/rustc_infer/src/infer/outlives/test_type_match.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ pub(super) fn can_match_erased_ty<'tcx>(
8686
}
8787
}
8888

89-
pub struct MatchAgainstHigherRankedOutlives<'tcx> {
89+
struct MatchAgainstHigherRankedOutlives<'tcx> {
9090
tcx: TyCtxt<'tcx>,
9191
pattern_depth: ty::DebruijnIndex,
92-
pub map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
92+
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
9393
}
9494

9595
impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
96-
pub fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstHigherRankedOutlives<'tcx> {
96+
fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstHigherRankedOutlives<'tcx> {
9797
MatchAgainstHigherRankedOutlives {
9898
tcx,
9999
pattern_depth: ty::INNERMOST,

0 commit comments

Comments
 (0)
Failed to load comments.