Skip to content

Commit cd48e61

Browse files
committed
Auto merge of rust-lang#86795 - JohnTitor:fix-bind, r=jackh726
Fix const-generics ICE related to binding Fixes rust-lang#83765, fixes rust-lang#85848 r? `@jackh726` as you're familiar with `Binding`. I'd like to get some views if the current approach is right path.
2 parents 798baeb + 58f6cb4 commit cd48e61

File tree

17 files changed

+280
-125
lines changed

17 files changed

+280
-125
lines changed

compiler/rustc_middle/src/ty/fold.rs

-82
Original file line numberDiff line numberDiff line change
@@ -754,88 +754,6 @@ impl<'tcx> TyCtxt<'tcx> {
754754
}
755755
}
756756

757-
pub struct BoundVarsCollector<'tcx> {
758-
binder_index: ty::DebruijnIndex,
759-
vars: BTreeMap<u32, ty::BoundVariableKind>,
760-
// We may encounter the same variable at different levels of binding, so
761-
// this can't just be `Ty`
762-
visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
763-
}
764-
765-
impl<'tcx> BoundVarsCollector<'tcx> {
766-
pub fn new() -> Self {
767-
BoundVarsCollector {
768-
binder_index: ty::INNERMOST,
769-
vars: BTreeMap::new(),
770-
visited: SsoHashSet::default(),
771-
}
772-
}
773-
774-
pub fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List<ty::BoundVariableKind> {
775-
let max = self.vars.iter().map(|(k, _)| *k).max().unwrap_or_else(|| 0);
776-
for i in 0..max {
777-
if let None = self.vars.get(&i) {
778-
panic!("Unknown variable: {:?}", i);
779-
}
780-
}
781-
782-
tcx.mk_bound_variable_kinds(self.vars.into_iter().map(|(_, v)| v))
783-
}
784-
}
785-
786-
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
787-
type BreakTy = ();
788-
789-
fn visit_binder<T: TypeFoldable<'tcx>>(
790-
&mut self,
791-
t: &Binder<'tcx, T>,
792-
) -> ControlFlow<Self::BreakTy> {
793-
self.binder_index.shift_in(1);
794-
let result = t.super_visit_with(self);
795-
self.binder_index.shift_out(1);
796-
result
797-
}
798-
799-
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
800-
if t.outer_exclusive_binder < self.binder_index
801-
|| !self.visited.insert((self.binder_index, t))
802-
{
803-
return ControlFlow::CONTINUE;
804-
}
805-
use std::collections::btree_map::Entry;
806-
match *t.kind() {
807-
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
808-
match self.vars.entry(bound_ty.var.as_u32()) {
809-
Entry::Vacant(entry) => {
810-
entry.insert(ty::BoundVariableKind::Ty(bound_ty.kind));
811-
}
812-
Entry::Occupied(entry) => match entry.get() {
813-
ty::BoundVariableKind::Ty(_) => {}
814-
_ => bug!("Conflicting bound vars"),
815-
},
816-
}
817-
}
818-
819-
_ => (),
820-
};
821-
822-
t.super_visit_with(self)
823-
}
824-
825-
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
826-
match r {
827-
ty::ReLateBound(index, _br) if *index == self.binder_index => {
828-
// If you hit this, you should be using `Binder::bind_with_vars` or `Binder::rebind`
829-
bug!("Trying to collect bound vars with a bound region: {:?} {:?}", index, _br)
830-
}
831-
832-
_ => (),
833-
};
834-
835-
r.super_visit_with(self)
836-
}
837-
}
838-
839757
pub struct ValidateBoundVars<'tcx> {
840758
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
841759
binder_index: ty::DebruijnIndex,

compiler/rustc_middle/src/ty/sty.rs

-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use self::TyKind::*;
66

77
use crate::infer::canonical::Canonical;
8-
use crate::ty::fold::BoundVarsCollector;
98
use crate::ty::fold::ValidateBoundVars;
109
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
1110
use crate::ty::InferTy::{self, *};
@@ -970,13 +969,6 @@ where
970969
Binder(value, ty::List::empty())
971970
}
972971

973-
/// Wraps `value` in a binder, binding higher-ranked vars (if any).
974-
pub fn bind(value: T, tcx: TyCtxt<'tcx>) -> Binder<'tcx, T> {
975-
let mut collector = BoundVarsCollector::new();
976-
value.visit_with(&mut collector);
977-
Binder(value, collector.into_vars(tcx))
978-
}
979-
980972
pub fn bind_with_vars(value: T, vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> {
981973
if cfg!(debug_assertions) {
982974
let mut validator = ValidateBoundVars::new(vars);

compiler/rustc_middle/src/ty/util.rs

+5-1
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_mir/src/transform/check_consts/validation.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -822,12 +822,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
822822
let obligation = Obligation::new(
823823
ObligationCause::dummy(),
824824
param_env,
825-
Binder::bind(
826-
TraitPredicate {
827-
trait_ref: TraitRef::from_method(tcx, trait_id, substs),
828-
},
829-
tcx,
830-
),
825+
Binder::dummy(TraitPredicate { trait_ref }),
831826
);
832827

833828
let implsrc = tcx.infer_ctxt().enter(|infcx| {

compiler/rustc_trait_selection/src/traits/project.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1301,7 +1301,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
13011301
ty: self_ty.ptr_metadata_ty(tcx),
13021302
};
13031303

1304-
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate, tcx), false)
1304+
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
13051305
}
13061306

13071307
fn confirm_fn_pointer_candidate<'cx, 'tcx>(

compiler/rustc_ty_utils/src/instance.rs

+107-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,114 @@ 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::btree_map::Entry;
13+
use std::collections::BTreeMap;
14+
use std::ops::ControlFlow;
15+
1116
use tracing::debug;
1217

18+
// FIXME(#86795): `BoundVarsCollector` here should **NOT** be used
19+
// outside of `resolve_associated_item`. It's just to address #64494,
20+
// #83765, and #85848 which are creating bound types/regions that lose
21+
// their `Binder` *unintentionally*.
22+
// It's ideal to remove `BoundVarsCollector` and just use
23+
// `ty::Binder::*` methods but we use this stopgap until we figure out
24+
// the "real" fix.
25+
struct BoundVarsCollector<'tcx> {
26+
binder_index: ty::DebruijnIndex,
27+
vars: BTreeMap<u32, ty::BoundVariableKind>,
28+
// We may encounter the same variable at different levels of binding, so
29+
// this can't just be `Ty`
30+
visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
31+
}
32+
33+
impl<'tcx> BoundVarsCollector<'tcx> {
34+
fn new() -> Self {
35+
BoundVarsCollector {
36+
binder_index: ty::INNERMOST,
37+
vars: BTreeMap::new(),
38+
visited: SsoHashSet::default(),
39+
}
40+
}
41+
42+
fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List<ty::BoundVariableKind> {
43+
let max = self.vars.iter().map(|(k, _)| *k).max().unwrap_or(0);
44+
for i in 0..max {
45+
if let None = self.vars.get(&i) {
46+
panic!("Unknown variable: {:?}", i);
47+
}
48+
}
49+
50+
tcx.mk_bound_variable_kinds(self.vars.into_iter().map(|(_, v)| v))
51+
}
52+
}
53+
54+
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
55+
type BreakTy = ();
56+
57+
fn visit_binder<T: TypeFoldable<'tcx>>(
58+
&mut self,
59+
t: &Binder<'tcx, T>,
60+
) -> ControlFlow<Self::BreakTy> {
61+
self.binder_index.shift_in(1);
62+
let result = t.super_visit_with(self);
63+
self.binder_index.shift_out(1);
64+
result
65+
}
66+
67+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
68+
if t.outer_exclusive_binder() < self.binder_index
69+
|| !self.visited.insert((self.binder_index, t))
70+
{
71+
return ControlFlow::CONTINUE;
72+
}
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+
match r {
94+
ty::ReLateBound(index, br) if *index == self.binder_index => {
95+
match self.vars.entry(br.var.as_u32()) {
96+
Entry::Vacant(entry) => {
97+
entry.insert(ty::BoundVariableKind::Region(br.kind));
98+
}
99+
Entry::Occupied(entry) => match entry.get() {
100+
ty::BoundVariableKind::Region(_) => {}
101+
_ => bug!("Conflicting bound vars"),
102+
},
103+
}
104+
}
105+
106+
_ => (),
107+
};
108+
109+
r.super_visit_with(self)
110+
}
111+
}
112+
13113
#[instrument(level = "debug", skip(tcx))]
14114
fn resolve_instance<'tcx>(
15115
tcx: TyCtxt<'tcx>,
@@ -115,7 +215,12 @@ fn resolve_associated_item<'tcx>(
115215
);
116216

117217
let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
118-
let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref, tcx)))?;
218+
219+
// See FIXME on `BoundVarsCollector`.
220+
let mut bound_vars_collector = BoundVarsCollector::new();
221+
trait_ref.visit_with(&mut bound_vars_collector);
222+
let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx));
223+
let vtbl = tcx.codegen_fulfill_obligation((param_env, trait_binder))?;
119224

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

compiler/rustc_ty_utils/src/lib.rs

+1
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)]

compiler/rustc_typeck/src/astconv/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1694,7 +1694,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16941694
};
16951695

16961696
self.one_bound_for_assoc_type(
1697-
|| traits::supertraits(tcx, ty::Binder::bind(trait_ref, tcx)),
1697+
|| traits::supertraits(tcx, ty::Binder::dummy(trait_ref)),
16981698
|| "Self".to_string(),
16991699
assoc_ident,
17001700
span,

compiler/rustc_typeck/src/check/compare_method.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,7 @@ fn compare_predicate_entailment<'tcx>(
222222
let mut selcx = traits::SelectionContext::new(&infcx);
223223

224224
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
225-
let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars(
226-
impl_m_span,
227-
infer::HigherRankedType,
228-
ty::Binder::bind(impl_m_own_bounds.predicates, tcx),
229-
);
230-
for predicate in impl_m_own_bounds {
225+
for predicate in impl_m_own_bounds.predicates {
231226
let traits::Normalized { value: predicate, obligations } =
232227
traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
233228

@@ -258,14 +253,14 @@ fn compare_predicate_entailment<'tcx>(
258253
);
259254
let impl_sig =
260255
inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, impl_sig);
261-
let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig, tcx));
256+
let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
262257
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
263258

264259
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
265260
let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
266261
let trait_sig =
267262
inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
268-
let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig, tcx));
263+
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
269264

270265
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
271266

compiler/rustc_typeck/src/check/method/confirm.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
101101

102102
let (method_sig, method_predicates) =
103103
self.normalize_associated_types_in(self.span, (method_sig, method_predicates));
104+
let method_sig = ty::Binder::dummy(method_sig);
104105

105106
// Make sure nobody calls `drop()` explicitly.
106107
self.enforce_illegal_method_limitations(&pick);
@@ -119,12 +120,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
119120
// We won't add these if we encountered an illegal sized bound, so that we can use
120121
// a custom error in that case.
121122
if illegal_sized_bound.is_none() {
122-
let method_ty = self.tcx.mk_fn_ptr(ty::Binder::bind(method_sig, self.tcx));
123-
self.add_obligations(method_ty, all_substs, method_predicates);
123+
self.add_obligations(self.tcx.mk_fn_ptr(method_sig), all_substs, method_predicates);
124124
}
125125

126126
// Create the final `MethodCallee`.
127-
let callee = MethodCallee { def_id: pick.item.def_id, substs: all_substs, sig: method_sig };
127+
let callee = MethodCallee {
128+
def_id: pick.item.def_id,
129+
substs: all_substs,
130+
sig: method_sig.skip_binder(),
131+
};
128132
ConfirmResult { callee, illegal_sized_bound }
129133
}
130134

compiler/rustc_typeck/src/check/method/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
404404
obligations.extend(traits::predicates_for_generics(cause.clone(), self.param_env, bounds));
405405

406406
// Also add an obligation for the method type being well-formed.
407-
let method_ty = tcx.mk_fn_ptr(ty::Binder::bind(fn_sig, tcx));
407+
let method_ty = tcx.mk_fn_ptr(ty::Binder::dummy(fn_sig));
408408
debug!(
409409
"lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
410410
method_ty, obligation

compiler/rustc_typeck/src/check/wfcheck.rs

-5
Original file line numberDiff line numberDiff line change
@@ -1087,14 +1087,9 @@ fn check_method_receiver<'fcx, 'tcx>(
10871087
debug!("check_method_receiver: sig={:?}", sig);
10881088

10891089
let self_ty = fcx.normalize_associated_types_in(span, self_ty);
1090-
let self_ty =
1091-
fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(self_ty, fcx.tcx));
10921090

10931091
let receiver_ty = sig.inputs()[0];
1094-
10951092
let receiver_ty = fcx.normalize_associated_types_in(span, receiver_ty);
1096-
let receiver_ty =
1097-
fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(receiver_ty, fcx.tcx));
10981093

10991094
if fcx.tcx.features().arbitrary_self_types {
11001095
if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {

0 commit comments

Comments
 (0)