Use BoundVarsCollector for now

This commit is contained in:
Yuki Okushi 2021-07-02 10:14:13 +09:00
parent 242ac57015
commit 13e116f1f7
No known key found for this signature in database
GPG Key ID: DABA5B072961C18A
3 changed files with 97 additions and 10 deletions

View File

@ -7,7 +7,7 @@
use crate::ty::query::TyCtxtAt; use crate::ty::query::TyCtxtAt;
use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
use crate::ty::TyKind::*; use crate::ty::TyKind::*;
use crate::ty::{self, DefIdTree, List, Ty, TyCtxt, TypeFoldable}; use crate::ty::{self, DebruijnIndex, DefIdTree, List, Ty, TyCtxt, TypeFoldable};
use rustc_apfloat::Float as _; use rustc_apfloat::Float as _;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_attr::{self as attr, SignedInt, UnsignedInt}; use rustc_attr::{self as attr, SignedInt, UnsignedInt};
@ -905,6 +905,10 @@ pub fn peel_refs(&'tcx self) -> Ty<'tcx> {
} }
ty ty
} }
pub fn outer_exclusive_binder(&'tcx self) -> DebruijnIndex {
self.outer_exclusive_binder
}
} }
pub enum ExplicitSelf<'tcx> { pub enum ExplicitSelf<'tcx> {

View File

@ -2,14 +2,98 @@
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::{sym, DUMMY_SP}; use rustc_span::{sym, DUMMY_SP};
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
use traits::{translate_substs, Reveal}; use traits::{translate_substs, Reveal};
use rustc_data_structures::sso::SsoHashSet;
use std::collections::BTreeMap;
use std::ops::ControlFlow;
use tracing::debug; use tracing::debug;
// FIXME(#86795): `BoundVarsCollector` here should **NOT** be used
// outside of `resolve_associated_item`. It's just to address #64494,
// #83765, and #85848 which are creating bound types/regions that lose
// their `Binder` *unintentionally*.
// It's ideal to remove `BoundVarsCollector` and just use
// `ty::Binder::*` methods but we use this stopgap until we figure out
// the "real" fix.
struct BoundVarsCollector<'tcx> {
binder_index: ty::DebruijnIndex,
vars: BTreeMap<u32, ty::BoundVariableKind>,
// We may encounter the same variable at different levels of binding, so
// this can't just be `Ty`
visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
}
impl<'tcx> BoundVarsCollector<'tcx> {
fn new() -> Self {
BoundVarsCollector {
binder_index: ty::INNERMOST,
vars: BTreeMap::new(),
visited: SsoHashSet::default(),
}
}
fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List<ty::BoundVariableKind> {
let max = self.vars.iter().map(|(k, _)| *k).max().unwrap_or_else(|| 0);
for i in 0..max {
if let None = self.vars.get(&i) {
panic!("Unknown variable: {:?}", i);
}
}
tcx.mk_bound_variable_kinds(self.vars.into_iter().map(|(_, v)| v))
}
}
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
type BreakTy = ();
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &Binder<'tcx, T>,
) -> ControlFlow<Self::BreakTy> {
self.binder_index.shift_in(1);
let result = t.super_visit_with(self);
self.binder_index.shift_out(1);
result
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if t.outer_exclusive_binder() < self.binder_index
|| !self.visited.insert((self.binder_index, t))
{
return ControlFlow::CONTINUE;
}
use std::collections::btree_map::Entry;
match *t.kind() {
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
match self.vars.entry(bound_ty.var.as_u32()) {
Entry::Vacant(entry) => {
entry.insert(ty::BoundVariableKind::Ty(bound_ty.kind));
}
Entry::Occupied(entry) => match entry.get() {
ty::BoundVariableKind::Ty(_) => {}
_ => bug!("Conflicting bound vars"),
},
}
}
_ => (),
};
t.super_visit_with(self)
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
r.super_visit_with(self)
}
}
#[instrument(level = "debug", skip(tcx))] #[instrument(level = "debug", skip(tcx))]
fn resolve_instance<'tcx>( fn resolve_instance<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
@ -115,14 +199,12 @@ fn resolve_associated_item<'tcx>(
); );
let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
let vtbl = if trait_item.kind == ty::AssocKind::Const {
let bound_vars = tcx // See FIXME on `BoundVarsCollector`.
.mk_bound_variable_kinds(std::iter::once(ty::BoundVariableKind::Region(ty::BrAnon(0)))); let mut bound_vars_collector = BoundVarsCollector::new();
let bind = ty::Binder::bind_with_vars(trait_ref, bound_vars); trait_ref.visit_with(&mut bound_vars_collector);
tcx.codegen_fulfill_obligation((param_env, bind))? let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx));
} else { let vtbl = tcx.codegen_fulfill_obligation((param_env, trait_binder))?;
tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref, tcx)))?
};
// Now that we know which impl is being used, we can dispatch to // Now that we know which impl is being used, we can dispatch to
// the actual function: // the actual function:

View File

@ -5,6 +5,7 @@
//! This API is completely unstable and subject to change. //! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(control_flow_enum)]
#![feature(half_open_range_patterns)] #![feature(half_open_range_patterns)]
#![feature(exclusive_range_pattern)] #![feature(exclusive_range_pattern)]
#![feature(nll)] #![feature(nll)]