Properly consider binder vars in HasTypeFlagsVisitor
This commit is contained in:
parent
5adddad28c
commit
7ae301ec47
3 changed files with 72 additions and 15 deletions
|
@ -34,6 +34,26 @@ impl FlagComputation {
|
|||
result.flags
|
||||
}
|
||||
|
||||
pub fn bound_var_flags(vars: &ty::List<ty::BoundVariableKind>) -> FlagComputation {
|
||||
let mut computation = FlagComputation::new();
|
||||
|
||||
for bv in vars {
|
||||
match bv {
|
||||
ty::BoundVariableKind::Ty(_) => {
|
||||
computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
|
||||
}
|
||||
ty::BoundVariableKind::Region(_) => {
|
||||
computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
|
||||
}
|
||||
ty::BoundVariableKind::Const => {
|
||||
computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
computation
|
||||
}
|
||||
|
||||
fn add_flags(&mut self, flags: TypeFlags) {
|
||||
self.flags = self.flags | flags;
|
||||
}
|
||||
|
@ -57,21 +77,7 @@ impl FlagComputation {
|
|||
where
|
||||
F: FnOnce(&mut Self, T),
|
||||
{
|
||||
let mut computation = FlagComputation::new();
|
||||
|
||||
for bv in value.bound_vars() {
|
||||
match bv {
|
||||
ty::BoundVariableKind::Ty(_) => {
|
||||
computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
|
||||
}
|
||||
ty::BoundVariableKind::Region(_) => {
|
||||
computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
|
||||
}
|
||||
ty::BoundVariableKind::Const => {
|
||||
computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut computation = FlagComputation::bound_var_flags(value.bound_vars());
|
||||
|
||||
f(&mut computation, value.skip_binder());
|
||||
|
||||
|
|
|
@ -481,9 +481,33 @@ impl std::fmt::Debug for HasTypeFlagsVisitor {
|
|||
// `Ty`/`Const`/`Predicate`, but not within those types. This is because the
|
||||
// type flags at the outer layer are enough. So it's faster than it first
|
||||
// looks, particular for `Ty`/`Predicate` where it's just a field access.
|
||||
//
|
||||
// N.B. The only case where this isn't totally true is binders, which also
|
||||
// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that
|
||||
// are present, regardless of whether those bound variables are used. This
|
||||
// is important for anonymization of binders in `TyCtxt::erase_regions`. We
|
||||
// specifically detect this case in `visit_binder`.
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
|
||||
type BreakTy = FoundFlags;
|
||||
|
||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: &Binder<'tcx, T>,
|
||||
) -> ControlFlow<Self::BreakTy> {
|
||||
// If we're looking for any of the HAS_*_LATE_BOUND flags, we need to
|
||||
// additionally consider the bound vars on the binder itself, even if
|
||||
// the contents of a the binder (e.g. a `TraitRef`) doesn't reference
|
||||
// the bound vars.
|
||||
if self.flags.intersects(TypeFlags::HAS_LATE_BOUND) {
|
||||
let bound_var_flags = FlagComputation::bound_var_flags(t.bound_vars());
|
||||
if bound_var_flags.flags.intersects(self.flags) {
|
||||
return ControlFlow::Break(FoundFlags);
|
||||
}
|
||||
}
|
||||
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
// Note: no `super_visit_with` call.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue