From 2dff9a49e5be5857610336e585eb8e7267dd142e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Nov 2017 09:45:48 -0500 Subject: [PATCH] stop using the `closure_kinds` query / table for anything Closure Kind is now extracted from the closure substs exclusively. --- src/librustc/infer/mod.rs | 25 ++---- src/librustc/middle/mem_categorization.rs | 17 +++- src/librustc/traits/error_reporting.rs | 4 +- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/select.rs | 6 +- src/librustc/ty/instance.rs | 2 +- src/librustc/ty/sty.rs | 19 ++-- src/librustc_mir/build/mod.rs | 8 +- src/librustc_trans/common.rs | 2 +- src/librustc_trans_utils/monomorphize.rs | 2 +- src/librustc_typeck/check/callee.rs | 6 +- src/librustc_typeck/check/closure.rs | 18 ++-- src/librustc_typeck/check/upvar.rs | 103 +++++++++++----------- src/test/compile-fail/issue-22638.rs | 2 +- 14 files changed, 107 insertions(+), 109 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 4f923f0b249..905e45bf9f0 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1463,26 +1463,17 @@ pub fn type_moves_by_default(&self, !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 { - 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. diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 2c6bcc654a5..a41a8093071 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -750,10 +750,19 @@ fn cat_upvar(&self, 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), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index caed3639b56..ccea981b78e 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -643,8 +643,8 @@ pub fn report_selection_error(&self, 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!( diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 1595679e9eb..6b681322c9b 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -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![])) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 2ab44b9c8bb..fba894d528e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -719,7 +719,7 @@ fn evaluate_predicate_recursively<'o>(&mut self, } 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 @@ fn assemble_closure_candidates(&mut self, // 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) { diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 6ea953c3f73..70636f8b6fe 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -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), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index bc55ffdc31f..e20db5e3807 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -290,16 +290,8 @@ impl Iterator> + '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 { - 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 @@ pub fn closure_kind_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'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 @@ pub fn to_opt_closure_kind(&self) -> Option { TyInfer(_) => None, + TyError => Some(ty::ClosureKind::Fn), + _ => bug!("cannot convert type `{:?}` to a closure kind", self), } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index e722a589b66..c4966c012c7 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -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, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index e3856cabcf9..7309b05d5a0 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -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, diff --git a/src/librustc_trans_utils/monomorphize.rs b/src/librustc_trans_utils/monomorphize.rs index ab61dacf010..1f8d273d8fb 100644 --- a/src/librustc_trans_utils/monomorphize.rs +++ b/src/librustc_trans_utils/monomorphize.rs @@ -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), diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 91ce4511a31..8f409b68752 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -108,7 +108,7 @@ fn try_overloaded_call_step(&self, // 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 @@ fn try_overloaded_call_step(&self, 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>, 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 @@ pub fn resolve(self, fcx: &FnCtxt<'a, '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, diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 1f96afe3ac8..5eda205c26d 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -107,6 +107,9 @@ fn check_closure( 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 @@ fn check_closure( 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 diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index c4cdd958680..048f53f2988 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -46,7 +46,6 @@ 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 @@ fn analyze_closure( } }); - { - 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 @@ fn analyze_closure( // 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={:?}", diff --git a/src/test/compile-fail/issue-22638.rs b/src/test/compile-fail/issue-22638.rs index 53b0d9f4e9f..1c534ebbd43 100644 --- a/src/test/compile-fail/issue-22638.rs +++ b/src/test/compile-fail/issue-22638.rs @@ -19,7 +19,6 @@ impl A { pub fn matches(&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 @@ pub fn matches(&self, f: &F) { impl D { pub fn matches(&self, f: &F) { + //~^ ERROR reached the type-length limit while instantiating `D::matches::<[closure let &D(ref a) = self; a.matches(f) } -- GitLab