Skip to content

Commit 13e116f

Browse files
committed
Use BoundVarsCollector for now
1 parent 242ac57 commit 13e116f

File tree

3 files changed

+97
-10
lines changed

3 files changed

+97
-10
lines changed

compiler/rustc_middle/src/ty/util.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::ty::layout::IntegerExt;
77
use crate::ty::query::TyCtxtAt;
88
use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
99
use crate::ty::TyKind::*;
10-
use crate::ty::{self, DefIdTree, List, Ty, TyCtxt, TypeFoldable};
10+
use crate::ty::{self, DebruijnIndex, DefIdTree, List, Ty, TyCtxt, TypeFoldable};
1111
use rustc_apfloat::Float as _;
1212
use rustc_ast as ast;
1313
use rustc_attr::{self as attr, SignedInt, UnsignedInt};
@@ -905,6 +905,10 @@ impl<'tcx> ty::TyS<'tcx> {
905905
}
906906
ty
907907
}
908+
909+
pub fn outer_exclusive_binder(&'tcx self) -> DebruijnIndex {
910+
self.outer_exclusive_binder
911+
}
908912
}
909913

910914
pub enum ExplicitSelf<'tcx> {

compiler/rustc_ty_utils/src/instance.rs

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,98 @@ use rustc_errors::ErrorReported;
22
use rustc_hir::def_id::{DefId, LocalDefId};
33
use rustc_infer::infer::TyCtxtInferExt;
44
use rustc_middle::ty::subst::SubstsRef;
5-
use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
5+
use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor};
66
use rustc_span::{sym, DUMMY_SP};
77
use rustc_target::spec::abi::Abi;
88
use rustc_trait_selection::traits;
99
use traits::{translate_substs, Reveal};
1010

11+
use rustc_data_structures::sso::SsoHashSet;
12+
use std::collections::BTreeMap;
13+
use std::ops::ControlFlow;
14+
1115
use tracing::debug;
1216

17+
// FIXME(#86795): `BoundVarsCollector` here should **NOT** be used
18+
// outside of `resolve_associated_item`. It's just to address #64494,
19+
// #83765, and #85848 which are creating bound types/regions that lose
20+
// their `Binder` *unintentionally*.
21+
// It's ideal to remove `BoundVarsCollector` and just use
22+
// `ty::Binder::*` methods but we use this stopgap until we figure out
23+
// the "real" fix.
24+
struct BoundVarsCollector<'tcx> {
25+
binder_index: ty::DebruijnIndex,
26+
vars: BTreeMap<u32, ty::BoundVariableKind>,
27+
// We may encounter the same variable at different levels of binding, so
28+
// this can't just be `Ty`
29+
visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
30+
}
31+
32+
impl<'tcx> BoundVarsCollector<'tcx> {
33+
fn new() -> Self {
34+
BoundVarsCollector {
35+
binder_index: ty::INNERMOST,
36+
vars: BTreeMap::new(),
37+
visited: SsoHashSet::default(),
38+
}
39+
}
40+
41+
fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List<ty::BoundVariableKind> {
42+
let max = self.vars.iter().map(|(k, _)| *k).max().unwrap_or_else(|| 0);
43+
for i in 0..max {
44+
if let None = self.vars.get(&i) {
45+
panic!("Unknown variable: {:?}", i);
46+
}
47+
}
48+
49+
tcx.mk_bound_variable_kinds(self.vars.into_iter().map(|(_, v)| v))
50+
}
51+
}
52+
53+
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
54+
type BreakTy = ();
55+
56+
fn visit_binder<T: TypeFoldable<'tcx>>(
57+
&mut self,
58+
t: &Binder<'tcx, T>,
59+
) -> ControlFlow<Self::BreakTy> {
60+
self.binder_index.shift_in(1);
61+
let result = t.super_visit_with(self);
62+
self.binder_index.shift_out(1);
63+
result
64+
}
65+
66+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
67+
if t.outer_exclusive_binder() < self.binder_index
68+
|| !self.visited.insert((self.binder_index, t))
69+
{
70+
return ControlFlow::CONTINUE;
71+
}
72+
use std::collections::btree_map::Entry;
73+
match *t.kind() {
74+
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
75+
match self.vars.entry(bound_ty.var.as_u32()) {
76+
Entry::Vacant(entry) => {
77+
entry.insert(ty::BoundVariableKind::Ty(bound_ty.kind));
78+
}
79+
Entry::Occupied(entry) => match entry.get() {
80+
ty::BoundVariableKind::Ty(_) => {}
81+
_ => bug!("Conflicting bound vars"),
82+
},
83+
}
84+
}
85+
86+
_ => (),
87+
};
88+
89+
t.super_visit_with(self)
90+
}
91+
92+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
93+
r.super_visit_with(self)
94+
}
95+
}
96+
1397
#[instrument(level = "debug", skip(tcx))]
1498
fn resolve_instance<'tcx>(
1599
tcx: TyCtxt<'tcx>,
@@ -115,14 +199,12 @@ fn resolve_associated_item<'tcx>(
115199
);
116200

117201
let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
118-
let vtbl = if trait_item.kind == ty::AssocKind::Const {
119-
let bound_vars = tcx
120-
.mk_bound_variable_kinds(std::iter::once(ty::BoundVariableKind::Region(ty::BrAnon(0))));
121-
let bind = ty::Binder::bind_with_vars(trait_ref, bound_vars);
122-
tcx.codegen_fulfill_obligation((param_env, bind))?
123-
} else {
124-
tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref, tcx)))?
125-
};
202+
203+
// See FIXME on `BoundVarsCollector`.
204+
let mut bound_vars_collector = BoundVarsCollector::new();
205+
trait_ref.visit_with(&mut bound_vars_collector);
206+
let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx));
207+
let vtbl = tcx.codegen_fulfill_obligation((param_env, trait_binder))?;
126208

127209
// Now that we know which impl is being used, we can dispatch to
128210
// the actual function:

compiler/rustc_ty_utils/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! This API is completely unstable and subject to change.
66
77
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
8+
#![feature(control_flow_enum)]
89
#![feature(half_open_range_patterns)]
910
#![feature(exclusive_range_pattern)]
1011
#![feature(nll)]

0 commit comments

Comments
 (0)