stop using the closure_kinds query / table for anything

Closure Kind is now extracted from the closure substs exclusively.
This commit is contained in:
Niko Matsakis 2017-11-08 09:45:48 -05:00
parent 716f75b1b8
commit 2dff9a49e5
14 changed files with 107 additions and 109 deletions

View File

@ -1463,26 +1463,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
!traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
}
/// Obtains the latest type of the given closure; this may be a
/// closure in the current function, in which case its
/// `ClosureKind` may not yet be known.
pub fn closure_kind(&self,
def_id: DefId)
closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'tcx>)
-> Option<ty::ClosureKind>
{
if let Some(tables) = self.in_progress_tables {
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
let hir_id = self.tcx.hir.node_to_hir_id(id);
return tables.borrow()
.closure_kinds()
.get(hir_id)
.cloned()
.map(|(kind, _)| kind);
}
}
// During typeck, ALL closures are local. But afterwards,
// during trans, we see closure ids from other traits.
// That may require loading the closure data out of the
// cstore.
Some(self.tcx.closure_kind(def_id))
let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx);
let closure_kind_ty = self.shallow_resolve(&closure_kind_ty);
closure_kind_ty.to_opt_closure_kind()
}
/// Obtain the signature of a function or closure.

View File

@ -750,10 +750,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
let kind = match self.node_ty(fn_hir_id)?.sty {
ty::TyGenerator(..) => ty::ClosureKind::FnOnce,
ty::TyClosure(..) => {
match self.tables.closure_kinds().get(fn_hir_id) {
Some(&(kind, _)) => kind,
None => span_bug!(span, "missing closure kind"),
ty::TyClosure(closure_def_id, closure_substs) => {
match self.infcx {
// During upvar inference we may not know the
// closure kind, just use `Fn`.
Some(infcx) =>
infcx.closure_kind(closure_def_id, closure_substs)
.unwrap_or(ty::ClosureKind::Fn),
None =>
self.tcx.global_tcx()
.lift(&closure_substs)
.expect("no inference cx, but inference variables in closure ty")
.closure_kind(closure_def_id, self.tcx.global_tcx())
}
}
ref t => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", t),

View File

@ -643,8 +643,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
violations)
}
ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => {
let found_kind = self.closure_kind(closure_def_id).unwrap();
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap();
let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
let mut err = struct_span_err!(

View File

@ -439,7 +439,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
}
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
match closure_substs.opt_closure_kind(closure_def_id, selcx.tcx()) {
match selcx.infcx().closure_kind(closure_def_id, closure_substs) {
Some(closure_kind) => {
if closure_kind.extends(kind) {
Ok(Some(vec![]))

View File

@ -719,7 +719,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
match closure_substs.opt_closure_kind(closure_def_id, self.tcx()) {
match self.infcx.closure_kind(closure_def_id, closure_substs) {
Some(closure_kind) => {
if closure_kind.extends(kind) {
EvaluatedToOk
@ -1593,10 +1593,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// touch bound regions, they just capture the in-scope
// type/region parameters
match obligation.self_ty().skip_binder().sty {
ty::TyClosure(closure_def_id, _) => {
ty::TyClosure(closure_def_id, closure_substs) => {
debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}",
kind, obligation);
match self.infcx.closure_kind(closure_def_id) {
match self.infcx.closure_kind(closure_def_id, closure_substs) {
Some(closure_kind) => {
debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
if closure_kind.extends(kind) {

View File

@ -189,7 +189,7 @@ fn resolve_closure<'a, 'tcx>(
requested_kind: ty::ClosureKind)
-> Instance<'tcx>
{
let actual_kind = tcx.closure_kind(def_id);
let actual_kind = substs.closure_kind(def_id, tcx);
match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),

View File

@ -290,16 +290,8 @@ impl<'tcx> ClosureSubsts<'tcx> {
upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type"))
}
/// Returns the closure kind for this closure; may return `None`
/// if inference has not yet completed.
pub fn opt_closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>)
-> Option<ty::ClosureKind> {
let closure_kind_ty = self.closure_kind_ty(def_id, tcx);
closure_kind_ty.to_opt_closure_kind()
}
/// Returns the closure kind for this closure; may return `None`
/// if inference has not yet completed.
/// Returns the closure kind for this closure; may return a type
/// variable during inference.
pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> {
self.split(def_id, tcx).closure_kind_ty
}
@ -307,9 +299,10 @@ impl<'tcx> ClosureSubsts<'tcx> {
impl<'tcx> ClosureSubsts<'tcx> {
/// Returns the closure kind for this closure; only usable outside
/// of an inference context.
/// of an inference context, because in that context we know that
/// there are no type variables.
pub fn closure_kind(self, def_id: DefId, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> ty::ClosureKind {
self.opt_closure_kind(def_id, tcx).unwrap()
self.split(def_id, tcx).closure_kind_ty.to_opt_closure_kind().unwrap()
}
}
@ -1514,6 +1507,8 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
TyInfer(_) => None,
TyError => Some(ty::ClosureKind::Fn),
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
}
}

View File

@ -248,14 +248,18 @@ pub fn closure_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
let closure_expr_hir_id = tcx.hir.node_to_hir_id(closure_expr_id);
let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_hir_id);
let closure_def_id = tcx.hir.local_def_id(closure_expr_id);
let (closure_def_id, closure_substs) = match closure_ty.sty {
ty::TyClosure(closure_def_id, closure_substs) => (closure_def_id, closure_substs),
_ => bug!("closure expr does not have closure type: {:?}", closure_ty)
};
let region = ty::ReFree(ty::FreeRegion {
scope: closure_def_id,
bound_region: ty::BoundRegion::BrEnv,
});
let region = tcx.mk_region(region);
match tcx.closure_kind(closure_def_id) {
match closure_substs.closure_kind_ty(closure_def_id, tcx).to_opt_closure_kind().unwrap() {
ty::ClosureKind::Fn =>
tcx.mk_ref(region,
ty::TypeAndMut { ty: closure_ty,

View File

@ -511,7 +511,7 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let sig = tcx.fn_sig(def_id).subst(tcx, substs.substs);
let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
let env_ty = match tcx.closure_kind(def_id) {
let env_ty = match substs.closure_kind(def_id, tcx) {
ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty),
ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty),
ty::ClosureKind::FnOnce => ty,

View File

@ -86,7 +86,7 @@ pub fn resolve_closure<'a, 'tcx> (
requested_kind: ty::ClosureKind)
-> Instance<'tcx>
{
let actual_kind = tcx.closure_kind(def_id);
let actual_kind = substs.closure_kind(def_id, tcx);
match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),

View File

@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Check whether this is a call to a closure where we
// haven't yet decided on whether the closure is fn vs
// fnmut vs fnonce. If so, we have to defer further processing.
if self.closure_kind(def_id).is_none() {
if self.closure_kind(def_id, substs).is_none() {
let closure_ty = self.fn_sig(def_id).subst(self.tcx, substs.substs);
let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
infer::FnCall,
@ -122,6 +122,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
adjustments,
fn_sig,
closure_def_id: def_id,
closure_substs: substs,
});
return Some(CallStep::DeferredClosure(fn_sig));
}
@ -336,6 +337,7 @@ pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> {
adjustments: Vec<Adjustment<'tcx>>,
fn_sig: ty::FnSig<'tcx>,
closure_def_id: DefId,
closure_substs: ty::ClosureSubsts<'tcx>,
}
impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
@ -344,7 +346,7 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
// we should not be invoked until the closure kind has been
// determined by upvar inference
assert!(fcx.closure_kind(self.closure_def_id).is_some());
assert!(fcx.closure_kind(self.closure_def_id, self.closure_substs).is_some());
// We may now know enough to figure out fn vs fnmut etc.
match fcx.try_overloaded_call_traits(self.call_expr,

View File

@ -107,6 +107,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let closure_type = self.tcx.mk_closure(expr_def_id, substs);
if let Some(interior) = interior {
self.demand_eqtype(expr.span,
ty::ClosureKind::FnOnce.to_ty(self.tcx),
substs.closure_kind_ty(expr_def_id, self.tcx));
return self.tcx.mk_generator(expr_def_id, substs, interior);
}
@ -135,15 +138,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
opt_kind
);
{
let mut tables = self.tables.borrow_mut();
tables.closure_tys_mut().insert(expr.hir_id, sig);
match opt_kind {
Some(kind) => {
tables.closure_kinds_mut().insert(expr.hir_id, (kind, None));
}
None => {}
}
self.tables.borrow_mut().closure_tys_mut().insert(expr.hir_id, sig);
if let Some(kind) = opt_kind {
self.tables.borrow_mut().closure_kinds_mut().insert(expr.hir_id, (kind, None));
self.demand_eqtype(expr.span,
kind.to_ty(self.tcx),
substs.closure_kind_ty(expr_def_id, self.tcx));
}
closure_type

View File

@ -46,7 +46,6 @@ use middle::expr_use_visitor as euv;
use middle::mem_categorization as mc;
use middle::mem_categorization::Categorization;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::TypeFoldable;
use rustc::infer::UpvarRegion;
use syntax::ast;
use syntax_pos::Span;
@ -158,40 +157,58 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
});
{
let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id());
let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id);
let mut delegate = InferBorrowKind {
fcx: self,
adjust_closure_kinds: FxHashMap(),
adjust_upvar_captures: ty::UpvarCaptureMap::default(),
};
euv::ExprUseVisitor::with_infer(
&mut delegate,
&self.infcx,
self.param_env,
region_scope_tree,
&self.tables.borrow(),
).consume_body(body);
// Write the adjusted values back into the main tables.
if infer_kind {
if let Some(kind) = delegate
.adjust_closure_kinds
.remove(&closure_def_id.to_local())
{
self.tables
.borrow_mut()
.closure_kinds_mut()
.insert(closure_hir_id, kind);
}
// Extract the type of the closure.
let (def_id, closure_substs) = match self.node_ty(closure_hir_id).sty {
ty::TyClosure(def_id, substs) | ty::TyGenerator(def_id, substs, _) => (def_id, substs),
ref t => {
span_bug!(
span,
"type of closure expr {:?} is not a closure {:?}",
closure_node_id,
t
);
}
};
let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id());
let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id);
let mut delegate = InferBorrowKind {
fcx: self,
adjust_closure_kinds: FxHashMap(),
adjust_upvar_captures: ty::UpvarCaptureMap::default(),
};
euv::ExprUseVisitor::with_infer(
&mut delegate,
&self.infcx,
self.param_env,
region_scope_tree,
&self.tables.borrow(),
).consume_body(body);
// Write the adjusted values back into the main tables.
if infer_kind {
let opt_adjusted = delegate.adjust_closure_kinds.remove(&closure_def_id.to_local());
let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx);
if let Some((kind, origin)) = opt_adjusted {
self.tables
.borrow_mut()
.closure_kinds_mut()
.insert(closure_hir_id, (kind, origin));
self.demand_eqtype(span, kind.to_ty(self.tcx), closure_kind_ty);
} else {
// If there are only reads, or no upvars, then the
// default of `Fn` will never *have* to be adjusted, so there will be
// no entry in the map.
self.demand_eqtype(span, ty::ClosureKind::Fn.to_ty(self.tcx), closure_kind_ty);
}
self.tables
.borrow_mut()
.upvar_capture_map
.extend(delegate.adjust_upvar_captures);
}
self.tables
.borrow_mut()
.upvar_capture_map
.extend(delegate.adjust_upvar_captures);
// Now that we've analyzed the closure, we know how each
// variable is borrowed, and we know what traits the closure
// implements (Fn vs FnMut etc). We now have some updates to do
@ -204,27 +221,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// C, then the type would have infinite size (and the
// inference algorithm will reject it).
// Extract the type variables UV0...UVn.
let (def_id, closure_substs) = match self.node_ty(closure_hir_id).sty {
ty::TyClosure(def_id, substs) | ty::TyGenerator(def_id, substs, _) => (def_id, substs),
ref t => {
span_bug!(
span,
"type of closure expr {:?} is not a closure {:?}",
closure_node_id,
t
);
}
};
// Equate the type variable representing the closure kind.
let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx);
if closure_kind_ty.needs_infer() {
let final_closure_kind = self.tables.borrow().closure_kinds()[closure_hir_id].0;
self.demand_eqtype(span, final_closure_kind.to_ty(self.tcx), closure_kind_ty);
}
// Equate the type variables with the actual types.
// Equate the type variables for the upvars with the actual types.
let final_upvar_tys = self.final_upvar_tys(closure_node_id);
debug!(
"analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",

View File

@ -19,7 +19,6 @@ struct A (B);
impl A {
pub fn matches<F: Fn()>(&self, f: &F) {
//~^ ERROR reached the recursion limit while instantiating `A::matches::<[closure
let &A(ref term) = self;
term.matches(f);
}
@ -59,6 +58,7 @@ struct D (Box<A>);
impl D {
pub fn matches<F: Fn()>(&self, f: &F) {
//~^ ERROR reached the type-length limit while instantiating `D::matches::<[closure
let &D(ref a) = self;
a.matches(f)
}