diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2017-11-08 12:36:28 -0500 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2017-11-18 07:47:37 -0500 |
| commit | 54f4f396d90e492fe9ede8608fe1a870e21fd10e (patch) | |
| tree | 8d9d2134fa8af23821a479633f8800c0e175d299 | |
| parent | eb26e30b915ada4debd0d10ad95a9f6348faf4d5 (diff) | |
| download | rust-54f4f396d90e492fe9ede8608fe1a870e21fd10e.tar.gz rust-54f4f396d90e492fe9ede8608fe1a870e21fd10e.zip | |
convert the `closure_kinds` map to just store the origin information
The closure kinds themselves are now completely found in the `ClosureSubsts`.
| -rw-r--r-- | src/librustc/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustc/middle/mem_categorization.rs | 6 | ||||
| -rw-r--r-- | src/librustc/traits/error_reporting.rs | 10 | ||||
| -rw-r--r-- | src/librustc/ty/context.rs | 22 | ||||
| -rw-r--r-- | src/librustc/ty/mod.rs | 3 | ||||
| -rw-r--r-- | src/librustc_borrowck/borrowck/mod.rs | 6 | ||||
| -rw-r--r-- | src/librustc_borrowck/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustc_typeck/check/closure.rs | 1 | ||||
| -rw-r--r-- | src/librustc_typeck/check/upvar.rs | 169 | ||||
| -rw-r--r-- | src/librustc_typeck/check/writeback.rs | 4 |
10 files changed, 108 insertions, 115 deletions
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 5e9019c92c5..36286a3ac88 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -51,6 +51,7 @@ #![feature(inclusive_range_syntax)] #![cfg_attr(windows, feature(libc))] #![feature(macro_vis_matcher)] +#![feature(match_default_bindings)] #![feature(never_type)] #![feature(nonzero)] #![feature(quote)] diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a41a8093071..1636ab40d39 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -753,16 +753,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ty::TyClosure(closure_def_id, closure_substs) => { match self.infcx { // During upvar inference we may not know the - // closure kind, just use `Fn`. + // closure kind, just use the LATTICE_BOTTOM value. Some(infcx) => infcx.closure_kind(closure_def_id, closure_substs) - .unwrap_or(ty::ClosureKind::Fn), + .unwrap_or(ty::ClosureKind::LATTICE_BOTTOM), 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()) + .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 ccea981b78e..46ec2be4a1f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -663,14 +663,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some(tables) = self.in_progress_tables { let tables = tables.borrow(); let closure_hir_id = self.tcx.hir.node_to_hir_id(node_id); - match tables.closure_kinds().get(closure_hir_id) { - Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => { - err.span_note(span, &format!( + match (found_kind, tables.closure_kind_origins().get(closure_hir_id)) { + (ty::ClosureKind::FnOnce, Some((span, name))) => { + err.span_note(*span, &format!( "closure is `FnOnce` because it moves the \ variable `{}` out of its environment", name)); }, - Some(&(ty::ClosureKind::FnMut, Some((span, name)))) => { - err.span_note(span, &format!( + (ty::ClosureKind::FnMut, Some((span, name))) => { + err.span_note(*span, &format!( "closure is `FnMut` because it mutates the \ variable `{}` here", name)); }, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a3fe8398de2..6bd1a3564b1 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -359,9 +359,9 @@ pub struct TypeckTables<'tcx> { /// Records the type of each closure. closure_tys: ItemLocalMap<ty::PolyFnSig<'tcx>>, - /// Records the kind of each closure and the span and name of the variable - /// that caused the closure to be this kind. - closure_kinds: ItemLocalMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, + /// Records the reasons that we picked the kind of each closure; + /// not all closures are present in the map. + closure_kind_origins: ItemLocalMap<(Span, ast::Name)>, generator_sigs: ItemLocalMap<Option<ty::GenSig<'tcx>>>, @@ -414,7 +414,7 @@ impl<'tcx> TypeckTables<'tcx> { generator_sigs: ItemLocalMap(), generator_interiors: ItemLocalMap(), closure_tys: ItemLocalMap(), - closure_kinds: ItemLocalMap(), + closure_kind_origins: ItemLocalMap(), liberated_fn_sigs: ItemLocalMap(), fru_field_types: ItemLocalMap(), cast_kinds: ItemLocalMap(), @@ -624,19 +624,17 @@ impl<'tcx> TypeckTables<'tcx> { } } - pub fn closure_kinds(&self) -> LocalTableInContext<(ty::ClosureKind, - Option<(Span, ast::Name)>)> { + pub fn closure_kind_origins(&self) -> LocalTableInContext<(Span, ast::Name)> { LocalTableInContext { local_id_root: self.local_id_root, - data: &self.closure_kinds + data: &self.closure_kind_origins } } - pub fn closure_kinds_mut(&mut self) - -> LocalTableInContextMut<(ty::ClosureKind, Option<(Span, ast::Name)>)> { + pub fn closure_kind_origins_mut(&mut self) -> LocalTableInContextMut<(Span, ast::Name)> { LocalTableInContextMut { local_id_root: self.local_id_root, - data: &mut self.closure_kinds + data: &mut self.closure_kind_origins } } @@ -733,7 +731,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> { ref pat_adjustments, ref upvar_capture_map, ref closure_tys, - ref closure_kinds, + ref closure_kind_origins, ref liberated_fn_sigs, ref fru_field_types, @@ -776,7 +774,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> { }); closure_tys.hash_stable(hcx, hasher); - closure_kinds.hash_stable(hcx, hasher); + closure_kind_origins.hash_stable(hcx, hasher); liberated_fn_sigs.hash_stable(hcx, hasher); fru_field_types.hash_stable(hcx, hasher); cast_kinds.hash_stable(hcx, hasher); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1ae49808d3f..450e48f5fdc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1937,6 +1937,9 @@ pub enum ClosureKind { } impl<'a, 'tcx> ClosureKind { + // This is the initial value used when doing upvar inference. + pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn; + pub fn trait_did(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> DefId { match *self { ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem), diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 7b09e45fe96..36b397bbbe5 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -655,10 +655,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { ty::TypeVariants::TyClosure(id, _) => { let node_id = self.tcx.hir.as_local_node_id(id).unwrap(); let hir_id = self.tcx.hir.node_to_hir_id(node_id); - if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) = - self.tables.closure_kinds().get(hir_id) - { - err.span_note(span, &format!( + if let Some((span, name)) = self.tables.closure_kind_origins().get(hir_id) { + err.span_note(*span, &format!( "closure cannot be invoked more than once because \ it moves the variable `{}` out of its environment", name diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 78aacd49f80..c8b71be86f8 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -15,6 +15,7 @@ #![allow(non_camel_case_types)] +#![feature(match_default_bindings)] #![feature(quote)] #[macro_use] extern crate log; diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 5eda205c26d..2052160ac47 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -140,7 +140,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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)); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 048f53f2988..2e0d0ddfc39 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -45,6 +45,7 @@ use super::FnCtxt; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; +use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; use rustc::infer::UpvarRegion; use syntax::ast; @@ -52,9 +53,6 @@ use syntax_pos::Span; use rustc::hir; use rustc::hir::def_id::LocalDefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc::util::nodemap::FxHashMap; - -use std::collections::hash_map::Entry; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze(&self, body: &'gcx hir::Body) { @@ -98,7 +96,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, body: &hir::Body, capture_clause: hir::CaptureClause, - gen: bool, + is_generator: bool, ) { /*! * Analysis starting point. @@ -110,24 +108,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body.id() ); - let infer_kind = if gen { - false - } else { - match self.tables - .borrow_mut() - .closure_kinds_mut() - .entry(closure_hir_id) - { - Entry::Occupied(_) => false, - Entry::Vacant(entry) => { - debug!("check_closure: adding closure {:?} as Fn", closure_node_id); - entry.insert((ty::ClosureKind::Fn, None)); - true - } + // Extract the type of the closure. + let (closure_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 closure_def_id = self.tcx.hir.local_def_id(closure_node_id); + let infer_kind = if is_generator { + false + } else { + self.closure_kind(closure_def_id, closure_substs).is_none() + }; self.tcx.with_freevars(closure_node_id, |freevars| { for freevar in freevars { @@ -157,24 +155,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }); - // 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(), + closure_def_id: closure_def_id, + current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM, + current_origin: None, adjust_upvar_captures: ty::UpvarCaptureMap::default(), }; euv::ExprUseVisitor::with_infer( @@ -185,22 +172,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &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 { + // Unify the (as yet unbound) type variable in the closure + // substs with the kind we inferred. + let inferred_kind = delegate.current_closure_kind; + let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx); + self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty); + + // If we have an origin, store it. + if let Some(origin) = delegate.current_origin { 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); + .closure_kind_origins_mut() + .insert(closure_hir_id, origin); } } @@ -230,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { final_upvar_tys ); for (upvar_ty, final_upvar_ty) in closure_substs - .upvar_tys(def_id, self.tcx) + .upvar_tys(closure_def_id, self.tcx) .zip(final_upvar_tys) { self.demand_eqtype(span, final_upvar_ty, upvar_ty); @@ -238,11 +222,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If we are also inferred the closure kind here, // process any deferred resolutions. - if infer_kind { - let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id); - for deferred_call_resolution in deferred_call_resolutions { - deferred_call_resolution.resolve(self); - } + let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id); + for deferred_call_resolution in deferred_call_resolutions { + deferred_call_resolution.resolve(self); } } @@ -294,7 +276,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - adjust_closure_kinds: FxHashMap<LocalDefId, (ty::ClosureKind, Option<(Span, ast::Name)>)>, + + // The def-id of the closure whose kind and upvar accesses are being inferred. + closure_def_id: DefId, + + // The kind that we have inferred that the current closure + // requires. Note that we *always* infer a minimal kind, even if + // we don't always *use* that in the final result (i.e., sometimes + // we've taken the closure kind from the expectations instead, and + // for generators we don't even implement the closure traits + // really). + current_closure_kind: ty::ClosureKind, + + // If we modified `current_closure_kind`, this field contains a `Some()` with the + // variable access that caused us to do so. + current_origin: Option<(Span, ast::Name)>, + + // For each upvar that we access, we track the minimal kind of + // access we need (ref, ref mut, move, etc). adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>, } @@ -542,42 +541,36 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { var_name ); - let closure_kind = self.adjust_closure_kinds - .get(&closure_id) - .cloned() - .or_else(|| { - let closure_id = self.fcx.tcx.hir.local_def_id_to_hir_id(closure_id); - self.fcx - .tables - .borrow() - .closure_kinds() - .get(closure_id) - .cloned() - }); - - if let Some((existing_kind, _)) = closure_kind { - debug!( - "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", - closure_id, - existing_kind, - new_kind - ); - - match (existing_kind, new_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, _) => { - // no change needed - } + // Is this the closure whose kind is currently being inferred? + if closure_id.to_def_id() != self.closure_def_id { + debug!("adjust_closure_kind: not current closure"); + return; + } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // new kind is stronger than the old kind - self.adjust_closure_kinds - .insert(closure_id, (new_kind, Some((upvar_span, var_name)))); - } + // closures start out as `Fn`. + let existing_kind = self.current_closure_kind; + + debug!( + "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", + closure_id, + existing_kind, + new_kind + ); + + match (existing_kind, new_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, _) => { + // no change needed + } + + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // new kind is stronger than the old kind + self.current_closure_kind = new_kind; + self.current_origin = Some((upvar_span, var_name)); } } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index ce2ac73a27e..48af2f0eff7 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -252,12 +252,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.tables.closure_tys_mut().insert(hir_id, closure_ty); } - for (&id, &closure_kind) in fcx_tables.closure_kinds().iter() { + for (&id, &origin) in fcx_tables.closure_kind_origins().iter() { let hir_id = hir::HirId { owner: common_local_id_root.index, local_id: id, }; - self.tables.closure_kinds_mut().insert(hir_id, closure_kind); + self.tables.closure_kind_origins_mut().insert(hir_id, origin); } } |
