Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 74851f4

Browse files
committed
count bound vars
1 parent 97a22a4 commit 74851f4

File tree

2 files changed

+92
-6
lines changed

2 files changed

+92
-6
lines changed

compiler/rustc_middle/src/ty/fold.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,54 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
888888
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
889889
struct FoundFlags;
890890

891+
crate struct CountBoundVars {
892+
crate outer_index: ty::DebruijnIndex,
893+
crate bound_tys: FxHashSet<ty::BoundTy>,
894+
crate bound_regions: FxHashSet<ty::BoundRegion>,
895+
crate bound_consts: FxHashSet<ty::BoundVar>,
896+
}
897+
898+
impl<'tcx> TypeVisitor<'tcx> for CountBoundVars {
899+
type BreakTy = ();
900+
901+
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> {
902+
self.outer_index.shift_in(1);
903+
let result = t.super_visit_with(self);
904+
self.outer_index.shift_out(1);
905+
result
906+
}
907+
908+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
909+
match t.kind {
910+
ty::Bound(debruijn, ty) if debruijn == self.outer_index => {
911+
self.bound_tys.insert(ty);
912+
ControlFlow::CONTINUE
913+
}
914+
_ => t.super_visit_with(self),
915+
}
916+
}
917+
918+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
919+
match r {
920+
ty::ReLateBound(debruijn, re) if *debruijn == self.outer_index => {
921+
self.bound_regions.insert(*re);
922+
ControlFlow::CONTINUE
923+
}
924+
_ => r.super_visit_with(self),
925+
}
926+
}
927+
928+
fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
929+
match ct.val {
930+
ty::ConstKind::Bound(debruijn, c) if debruijn == self.outer_index => {
931+
self.bound_consts.insert(c);
932+
ControlFlow::CONTINUE
933+
}
934+
_ => ct.super_visit_with(self),
935+
}
936+
}
937+
}
938+
891939
// FIXME: Optimize for checking for infer flags
892940
struct HasTypeFlagsVisitor {
893941
flags: ty::TypeFlags,

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -959,24 +959,58 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> {
959959
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
960960
pub struct Binder<T>(T, u32);
961961

962-
impl<T> Binder<T> {
962+
impl<'tcx, T> Binder<T>
963+
where
964+
T: TypeFoldable<'tcx>,
965+
{
963966
/// Wraps `value` in a binder, asserting that `value` does not
964967
/// contain any bound vars that would be bound by the
965968
/// binder. This is commonly used to 'inject' a value T into a
966969
/// different binding level.
967-
pub fn dummy<'tcx>(value: T) -> Binder<T>
968-
where
969-
T: TypeFoldable<'tcx>,
970-
{
970+
pub fn dummy(value: T) -> Binder<T> {
971971
debug_assert!(!value.has_escaping_bound_vars());
972972
Binder(value, 0)
973973
}
974974

975975
/// Wraps `value` in a binder, binding higher-ranked vars (if any).
976976
pub fn bind(value: T) -> Binder<T> {
977-
Binder(value, 0)
977+
use crate::ty::fold::CountBoundVars;
978+
use rustc_data_structures::fx::FxHashSet;
979+
let mut counter = CountBoundVars {
980+
outer_index: ty::INNERMOST,
981+
bound_tys: FxHashSet::default(),
982+
bound_regions: FxHashSet::default(),
983+
bound_consts: FxHashSet::default(),
984+
};
985+
value.visit_with(&mut counter);
986+
let bound_tys = counter.bound_tys.len();
987+
let bound_regions = if !counter.bound_regions.is_empty() {
988+
let mut env = false;
989+
let mut anons = FxHashSet::default();
990+
let mut named = FxHashSet::default();
991+
for br in counter.bound_regions {
992+
match br.kind {
993+
ty::BrAnon(idx) => {
994+
anons.insert(idx);
995+
}
996+
ty::BrNamed(def_id, _) => {
997+
named.insert(def_id);
998+
}
999+
ty::BrEnv => env = true,
1000+
}
1001+
}
1002+
(if env { 1 } else { 0 }) + anons.len() + named.len()
1003+
} else {
1004+
0
1005+
};
1006+
let bound_consts = counter.bound_consts.len();
1007+
1008+
let bound_vars = bound_tys + bound_regions + bound_consts;
1009+
Binder(value, bound_vars as u32)
9781010
}
1011+
}
9791012

1013+
impl<T> Binder<T> {
9801014
/// Skips the binder and returns the "bound" value. This is a
9811015
/// risky thing to do because it's easy to get confused about
9821016
/// De Bruijn indices and the like. It is usually better to
@@ -997,6 +1031,10 @@ impl<T> Binder<T> {
9971031
self.0
9981032
}
9991033

1034+
pub fn bound_vars(&self) -> u32 {
1035+
self.1
1036+
}
1037+
10001038
pub fn as_ref(&self) -> Binder<&T> {
10011039
Binder(&self.0, self.1)
10021040
}

0 commit comments

Comments
 (0)