Skip to content

Commit 5737082

Browse files
authored
Rollup merge of #115834 - compiler-errors:binder-vars, r=jackh726
Properly consider binder vars in `HasTypeFlagsVisitor` Given a PolyTraitRef like `for<'a> Ty: Trait` (where neither `Ty` nor `Trait` mention `'a`), we do *not* return true for `.has_type_flags(TypeFlags::HAS_LATE_BOUND)`, even though binders are supposed to act as if they have late-bound vars even if they don't mention them in their bound value: 31ae3b2. This is because we use `HasTypeFlagsVisitor`, which only computes the type flags for `Ty`, `Const` and `Region` and `Predicates`, and we consequently skip any binders (and setting flags for their vars) that are not contained in one of these types. This ends up causing a problem, because when we call `TyCtxt::erase_regions` (which both erases regions *and* anonymizes bound vars), we will skip such a PolyTraitRef, not anonymizing it, and therefore not making it structurally equal to other binders. This breaks vtable computations. This PR computes the flags for all binders we enter in `HasTypeFlagsVisitor` if we're looking for `TypeFlags::HAS_LATE_BOUND` (or `TypeFlags::HAS_{RE,TY,CT}_LATE_BOUND`). Fixes #115807
2 parents 3dbcc28 + 7ae301e commit 5737082

File tree

3 files changed

+72
-15
lines changed

3 files changed

+72
-15
lines changed

compiler/rustc_middle/src/ty/flags.rs

+21-15
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,26 @@ impl FlagComputation {
3434
result.flags
3535
}
3636

37+
pub fn bound_var_flags(vars: &ty::List<ty::BoundVariableKind>) -> FlagComputation {
38+
let mut computation = FlagComputation::new();
39+
40+
for bv in vars {
41+
match bv {
42+
ty::BoundVariableKind::Ty(_) => {
43+
computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
44+
}
45+
ty::BoundVariableKind::Region(_) => {
46+
computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
47+
}
48+
ty::BoundVariableKind::Const => {
49+
computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
50+
}
51+
}
52+
}
53+
54+
computation
55+
}
56+
3757
fn add_flags(&mut self, flags: TypeFlags) {
3858
self.flags = self.flags | flags;
3959
}
@@ -57,21 +77,7 @@ impl FlagComputation {
5777
where
5878
F: FnOnce(&mut Self, T),
5979
{
60-
let mut computation = FlagComputation::new();
61-
62-
for bv in value.bound_vars() {
63-
match bv {
64-
ty::BoundVariableKind::Ty(_) => {
65-
computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
66-
}
67-
ty::BoundVariableKind::Region(_) => {
68-
computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
69-
}
70-
ty::BoundVariableKind::Const => {
71-
computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
72-
}
73-
}
74-
}
80+
let mut computation = FlagComputation::bound_var_flags(value.bound_vars());
7581

7682
f(&mut computation, value.skip_binder());
7783

compiler/rustc_middle/src/ty/visit.rs

+24
Original file line numberDiff line numberDiff line change
@@ -481,9 +481,33 @@ impl std::fmt::Debug for HasTypeFlagsVisitor {
481481
// `Ty`/`Const`/`Predicate`, but not within those types. This is because the
482482
// type flags at the outer layer are enough. So it's faster than it first
483483
// looks, particular for `Ty`/`Predicate` where it's just a field access.
484+
//
485+
// N.B. The only case where this isn't totally true is binders, which also
486+
// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that
487+
// are present, regardless of whether those bound variables are used. This
488+
// is important for anonymization of binders in `TyCtxt::erase_regions`. We
489+
// specifically detect this case in `visit_binder`.
484490
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
485491
type BreakTy = FoundFlags;
486492

493+
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
494+
&mut self,
495+
t: &Binder<'tcx, T>,
496+
) -> ControlFlow<Self::BreakTy> {
497+
// If we're looking for any of the HAS_*_LATE_BOUND flags, we need to
498+
// additionally consider the bound vars on the binder itself, even if
499+
// the contents of a the binder (e.g. a `TraitRef`) doesn't reference
500+
// the bound vars.
501+
if self.flags.intersects(TypeFlags::HAS_LATE_BOUND) {
502+
let bound_var_flags = FlagComputation::bound_var_flags(t.bound_vars());
503+
if bound_var_flags.flags.intersects(self.flags) {
504+
return ControlFlow::Break(FoundFlags);
505+
}
506+
}
507+
508+
t.super_visit_with(self)
509+
}
510+
487511
#[inline]
488512
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
489513
// Note: no `super_visit_with` call.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// build-pass
2+
// issue: #115807
3+
4+
trait Chip: for<'a> TraitWithLifetime<'a> + SomeMarker {
5+
fn compute(&self);
6+
}
7+
8+
trait SomeMarker {}
9+
10+
trait TraitWithLifetime<'a>: SomeMarker {}
11+
12+
trait Machine {
13+
fn run();
14+
}
15+
16+
struct BasicMachine;
17+
18+
impl Machine for BasicMachine {
19+
fn run() {
20+
let chips: [&dyn Chip; 0] = [];
21+
let _ = chips.map(|chip| chip.compute());
22+
}
23+
}
24+
25+
fn main() {
26+
BasicMachine::run();
27+
}

0 commit comments

Comments
 (0)