]> git.lizzy.rs Git - rust.git/commitdiff
convert the `closure_kinds` map to just store the origin information
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 8 Nov 2017 17:36:28 +0000 (12:36 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Sat, 18 Nov 2017 12:47:37 +0000 (07:47 -0500)
The closure kinds themselves are now completely found in the `ClosureSubsts`.

src/librustc/lib.rs
src/librustc/middle/mem_categorization.rs
src/librustc/traits/error_reporting.rs
src/librustc/ty/context.rs
src/librustc/ty/mod.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_borrowck/lib.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/upvar.rs
src/librustc_typeck/check/writeback.rs

index 5e9019c92c5b73be37503504310f8b5eb5c04de6..36286a3ac883cfd9ea8930ee8281d5c562af07ae 100644 (file)
@@ -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)]
index a41a809307149f2c8e03dc14b81111b1c790b0c2..1636ab40d39eac04f4d26c60be92bcae70616da4 100644 (file)
@@ -753,16 +753,16 @@ fn cat_upvar(&self,
             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),
index ccea981b78e04a94f32f6b69234225589da9a5e8..46ec2be4a1f9bf2765347cde135c60652d3fddb2 100644 (file)
@@ -663,14 +663,14 @@ pub fn report_selection_error(&self,
                         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));
                                 },
index a3fe8398de21185059691337227e29cbaa7a92e7..6bd1a3564b1c097e64cbb5ccfddfe436f5b81a33 100644 (file)
@@ -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 @@ pub fn empty(local_id_root: Option<DefId>) -> 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 @@ pub fn closure_tys_mut(&mut self)
         }
     }
 
-    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 @@ fn hash_stable<W: StableHasherResult>(&self,
             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 @@ fn hash_stable<W: StableHasherResult>(&self,
             });
 
             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);
index 1ae49808d3f5e3548f51edeebe750e43f5d24e19..450e48f5fdcc76919bc8b4b53af907581bf4dc9a 100644 (file)
@@ -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),
index 7b09e45fe96e32dedd15af7cbbb6caec5c52a46d..36b397bbbe5465002d26c68f70363e2ebaf9cacb 100644 (file)
@@ -655,10 +655,8 @@ pub fn report_use_of_moved_value(&self,
                     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
index 78aacd49f807dafafc8ae37f7f29db8ed6e81e27..c8b71be86f862ef832dfaad95e23f51a39f82405 100644 (file)
@@ -15,6 +15,7 @@
 
 #![allow(non_camel_case_types)]
 
+#![feature(match_default_bindings)]
 #![feature(quote)]
 
 #[macro_use] extern crate log;
index 5eda205c26d50c50e219b23a73a5af20d542a9f4..2052160ac47084c1d513af2fd445ea7613defdcf 100644 (file)
@@ -140,7 +140,6 @@ fn check_closure(
 
         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));
index 048f53f298806fb587603603341fd8e2af6c706b..2e0d0ddfc393614047cf04cc84771f449a8534ac 100644 (file)
@@ -45,6 +45,7 @@
 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 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 @@ fn analyze_closure(
         span: Span,
         body: &hir::Body,
         capture_clause: hir::CaptureClause,
-        gen: bool,
+        is_generator: bool,
     ) {
         /*!
          * Analysis starting point.
@@ -110,24 +108,24 @@ fn analyze_closure(
             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 @@ fn analyze_closure(
             }
         });
 
-        // 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 @@ fn analyze_closure(
             &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 @@ fn analyze_closure(
             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 @@ fn analyze_closure(
 
         // 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 @@ fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec<Ty<'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 @@ fn adjust_closure_kind(
             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));
             }
         }
     }
index ce2ac73a27e0cb8b6f25fd031483c26e12bb8b51..48af2f0eff715b13b88489656146db60c98c2f75 100644 (file)
@@ -252,12 +252,12 @@ fn visit_closures(&mut self) {
             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);
         }
     }