diff --git a/Cargo.lock b/Cargo.lock index 7b0905db9af61..0eee3461ed6a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1183,6 +1183,11 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "indexmap" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "installer" version = "0.0.0" @@ -2719,6 +2724,7 @@ dependencies = [ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2970,6 +2976,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", @@ -3236,6 +3243,7 @@ dependencies = [ name = "serialize" version = "0.0.0" dependencies = [ + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4199,6 +4207,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum if_chain 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" "checksum ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8dc57fa12805f367736a38541ac1a9fc6a52812a0ca959b1d4d4b640a89eb002" "checksum im-rc 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0197597d095c0d11107975d3175173f810ee572c2501ff4de64f4f3f119806" +"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" "checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index 4a89bf3313b8a..e8c3914e695ad 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -109,6 +109,7 @@ macro_rules! arena_types { >, [few] crate_variances: rustc::ty::CrateVariancesMap<'tcx>, [few] inferred_outlives_crate: rustc::ty::CratePredicatesMap<'tcx>, + [] upvars: rustc_data_structures::fx::FxIndexMap, ], $tcx); ) } diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 03f24dbb29025..131a910bebb1a 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -139,9 +139,6 @@ pub enum Res { // Value namespace SelfCtor(DefId /* impl */), // `DefId` refers to the impl Local(Id), - Upvar(Id, // `HirId` of closed over local - usize, // index in the `upvars` list of the closure - ast::NodeId), // expr node that creates the closure // Macro namespace NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]` @@ -347,7 +344,6 @@ impl Res { Res::Def(_, id) => Some(id), Res::Local(..) | - Res::Upvar(..) | Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) | @@ -374,7 +370,6 @@ impl Res { Res::SelfCtor(..) => "self constructor", Res::PrimTy(..) => "builtin type", Res::Local(..) => "local variable", - Res::Upvar(..) => "closure capture", Res::SelfTy(..) => "self type", Res::ToolMod => "tool module", Res::NonMacroAttr(attr_kind) => attr_kind.descr(), @@ -397,11 +392,6 @@ impl Res { Res::SelfCtor(id) => Res::SelfCtor(id), Res::PrimTy(id) => Res::PrimTy(id), Res::Local(id) => Res::Local(map(id)), - Res::Upvar(id, index, closure) => Res::Upvar( - map(id), - index, - closure - ), Res::SelfTy(a, b) => Res::SelfTy(a, b), Res::ToolMod => Res::ToolMod, Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index fd42c6f469e1e..c84c18ce8a7e3 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -26,7 +26,7 @@ use crate::util::common::time; use std::io; use std::result::Result::Err; -use crate::ty::TyCtxt; +use crate::ty::query::Providers; pub mod blocks; mod collector; @@ -1450,11 +1450,13 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { } } -pub fn def_kind(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option { - if let Some(node_id) = tcx.hir().as_local_node_id(def_id) { - tcx.hir().def_kind(node_id) - } else { - bug!("Calling local def_kind query provider for upstream DefId: {:?}", - def_id) - } +pub fn provide(providers: &mut Providers<'_>) { + providers.def_kind = |tcx, def_id| { + if let Some(node_id) = tcx.hir().as_local_node_id(def_id) { + tcx.hir().def_kind(node_id) + } else { + bug!("Calling local def_kind query provider for upstream DefId: {:?}", + def_id) + } + }; } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f03a8ddc90825..f7daa7a94551f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -63,6 +63,7 @@ pub mod lowering; pub mod map; pub mod pat_util; pub mod print; +pub mod upvars; /// Uniquely identifies a node in the HIR of the current crate. It is /// composed of the `owner`, which is the `DefIndex` of the directly enclosing @@ -1408,7 +1409,6 @@ impl Expr { ExprKind::Path(QPath::Resolved(_, ref path)) => { match path.res { Res::Local(..) - | Res::Upvar(..) | Res::Def(DefKind::Static, _) | Res::Err => true, _ => false, @@ -2493,32 +2493,11 @@ impl ForeignItemKind { /// A variable captured by a closure. #[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] -pub struct Upvar { - /// The variable being captured. - pub res: Res, - +pub struct Upvar { // First span where it is accessed (there can be multiple). pub span: Span } -impl Upvar { - pub fn map_id(self, map: impl FnMut(Id) -> R) -> Upvar { - Upvar { - res: self.res.map_id(map), - span: self.span, - } - } - - pub fn var_id(&self) -> Id { - match self.res { - Res::Local(id) | Res::Upvar(id, ..) => id, - _ => bug!("Upvar::var_id: bad res ({:?})", self.res) - } - } -} - -pub type UpvarMap = NodeMap>>; - pub type CaptureModeMap = NodeMap; // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and @@ -2537,10 +2516,10 @@ pub type TraitMap = NodeMap>; // imported. pub type GlobMap = NodeMap>; - pub fn provide(providers: &mut Providers<'_>) { check_attr::provide(providers); - providers.def_kind = map::def_kind; + map::provide(providers); + upvars::provide(providers); } #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] diff --git a/src/librustc/hir/upvars.rs b/src/librustc/hir/upvars.rs new file mode 100644 index 0000000000000..a053deb558464 --- /dev/null +++ b/src/librustc/hir/upvars.rs @@ -0,0 +1,104 @@ +//! Upvar (closure capture) collection from cross-body HIR uses of `Res::Local`s. + +use crate::hir::{self, HirId}; +use crate::hir::def::Res; +use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use crate::ty::TyCtxt; +use crate::ty::query::Providers; +use syntax_pos::Span; +use rustc_data_structures::fx::{FxIndexMap, FxHashSet}; + +pub fn provide(providers: &mut Providers<'_>) { + providers.upvars = |tcx, def_id| { + if !tcx.is_closure(def_id) { + return None; + } + + let node_id = tcx.hir().as_local_node_id(def_id).unwrap(); + let body = tcx.hir().body(tcx.hir().maybe_body_owned_by(node_id)?); + + let mut local_collector = LocalCollector::default(); + local_collector.visit_body(body); + + let mut capture_collector = CaptureCollector { + tcx, + locals: &local_collector.locals, + upvars: FxIndexMap::default(), + }; + capture_collector.visit_body(body); + + if !capture_collector.upvars.is_empty() { + Some(tcx.arena.alloc(capture_collector.upvars)) + } else { + None + } + }; +} + +#[derive(Default)] +struct LocalCollector { + // FIXME(eddyb) perhaps use `ItemLocalId` instead? + locals: FxHashSet, +} + +impl Visitor<'tcx> for LocalCollector { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::None + } + + fn visit_pat(&mut self, pat: &'tcx hir::Pat) { + if let hir::PatKind::Binding(_, hir_id, ..) = pat.node { + self.locals.insert(hir_id); + } + intravisit::walk_pat(self, pat); + } +} + +struct CaptureCollector<'a, 'tcx> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + locals: &'a FxHashSet, + upvars: FxIndexMap, +} + +impl CaptureCollector<'_, '_> { + fn visit_local_use(&mut self, var_id: HirId, span: Span) { + if !self.locals.contains(&var_id) { + self.upvars.entry(var_id).or_insert(hir::Upvar { span }); + } + } +} + +impl Visitor<'tcx> for CaptureCollector<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::None + } + + fn visit_path(&mut self, path: &'tcx hir::Path, _: hir::HirId) { + if let Res::Local(var_id) = path.res { + self.visit_local_use(var_id, path.span); + } + + intravisit::walk_path(self, path); + } + + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { + if let hir::ExprKind::Closure(..) = expr.node { + let closure_def_id = self.tcx.hir().local_def_id_from_hir_id(expr.hir_id); + if let Some(upvars) = self.tcx.upvars(closure_def_id) { + // Every capture of a closure expression is a local in scope, + // that is moved/copied/borrowed into the closure value, and + // for this analysis they are like any other access to a local. + // + // E.g. in `|b| |c| (a, b, c)`, the upvars of the inner closure + // are `a` and `b`, and while `a` is not directly used in the + // outer closure, it needs to be an upvar there too, so that + // the inner closure can take it (from the outer closure's env). + for (&var_id, upvar) in upvars { + self.visit_local_use(var_id, upvar.span); + } + } + } + + intravisit::walk_expr(self, expr); + } +} diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 14553a972b704..04f5b35a0061a 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -78,7 +78,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } _ if self.in_pat => {}, Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) | - Res::Local(..) | Res::Upvar(..) => {} + Res::Local(..) => {} Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => { let variant_id = self.tcx.parent(ctor_def_id).unwrap(); let enum_id = self.tcx.parent(variant_id).unwrap(); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 35b6b76a39567..34cea2d75eaa8 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -268,6 +268,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> { /// See also `with_infer`, which is used *during* typeck. pub fn new(delegate: &'a mut (dyn Delegate<'tcx>+'a), tcx: TyCtxt<'a, 'tcx, 'tcx>, + body_owner: DefId, param_env: ty::ParamEnv<'tcx>, region_scope_tree: &'a region::ScopeTree, tables: &'a ty::TypeckTables<'tcx>, @@ -276,6 +277,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> { { ExprUseVisitor { mc: mc::MemCategorizationContext::new(tcx, + body_owner, region_scope_tree, tables, rvalue_promotable_map), @@ -288,13 +290,19 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> { impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn with_infer(delegate: &'a mut (dyn Delegate<'tcx>+'a), infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + body_owner: DefId, param_env: ty::ParamEnv<'tcx>, region_scope_tree: &'a region::ScopeTree, tables: &'a ty::TypeckTables<'tcx>) -> Self { ExprUseVisitor { - mc: mc::MemCategorizationContext::with_infer(infcx, region_scope_tree, tables), + mc: mc::MemCategorizationContext::with_infer( + infcx, + body_owner, + region_scope_tree, + tables, + ), delegate, param_env, } @@ -924,16 +932,15 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let closure_def_id = self.tcx().hir().local_def_id_from_hir_id(closure_expr.hir_id); if let Some(upvars) = self.tcx().upvars(closure_def_id) { - for upvar in upvars.iter() { - let var_hir_id = upvar.var_id(); + for (&var_id, upvar) in upvars.iter() { let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, + var_path: ty::UpvarPath { hir_id: var_id }, closure_expr_id: closure_def_id.to_local(), }; let upvar_capture = self.mc.tables.upvar_capture(upvar_id); let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.hir_id, fn_decl_span, - upvar)); + var_id)); match upvar_capture { ty::UpvarCapture::ByValue => { let mode = copy_or_move(&self.mc, @@ -958,13 +965,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn cat_captured_var(&mut self, closure_hir_id: hir::HirId, closure_span: Span, - upvar: &hir::Upvar) + var_id: hir::HirId) -> mc::McResult> { // Create the cmt for the variable being borrowed, from the - // caller's perspective - let var_hir_id = upvar.var_id(); - let var_ty = self.mc.node_ty(var_hir_id)?; - self.mc.cat_res(closure_hir_id, closure_span, var_ty, upvar.res) + // perspective of the creator (parent) of the closure. + let var_ty = self.mc.node_ty(var_id)?; + self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id)) } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 91a19852c6c0e..45b4fb5605695 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -182,7 +182,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> { } fn check_mod_liveness<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor()); + tcx.hir().visit_item_likes_in_module( + module_def_id, + &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(), + ); } pub fn provide(providers: &mut Providers<'_>) { @@ -255,6 +258,7 @@ enum VarKind { struct IrMaps<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, + body_owner: DefId, num_live_nodes: usize, num_vars: usize, live_node_map: HirIdMap, @@ -265,9 +269,10 @@ struct IrMaps<'a, 'tcx: 'a> { } impl<'a, 'tcx> IrMaps<'a, 'tcx> { - fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> IrMaps<'a, 'tcx> { + fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_owner: DefId) -> IrMaps<'a, 'tcx> { IrMaps { tcx, + body_owner, num_live_nodes: 0, num_vars: 0, live_node_map: HirIdMap::default(), @@ -356,7 +361,8 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>, debug!("visit_fn"); // swap in a new set of IR maps for this function body: - let mut fn_maps = IrMaps::new(ir.tcx); + let def_id = ir.tcx.hir().local_def_id_from_hir_id(id); + let mut fn_maps = IrMaps::new(ir.tcx, def_id); // Don't run unused pass for #[derive()] if let FnKind::Method(..) = fk { @@ -468,8 +474,11 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { // live nodes required for uses or definitions of variables: hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res); - if let Res::Local(..) = path.res { - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + if let Res::Local(var_hir_id) = path.res { + let upvars = ir.tcx.upvars(ir.body_owner); + if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hir_id)) { + ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + } } intravisit::walk_expr(ir, expr); } @@ -485,18 +494,23 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { let mut call_caps = Vec::new(); let closure_def_id = ir.tcx.hir().local_def_id_from_hir_id(expr.hir_id); if let Some(upvars) = ir.tcx.upvars(closure_def_id) { - call_caps.extend(upvars.iter().filter_map(|upvar| { - if let Res::Local(rv) = upvar.res { + let parent_upvars = ir.tcx.upvars(ir.body_owner); + call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| { + let has_parent = parent_upvars + .map_or(false, |upvars| upvars.contains_key(&var_id)); + if !has_parent { let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); - Some(CaptureInfo { ln: upvar_ln, var_hid: rv }) + Some(CaptureInfo { ln: upvar_ln, var_hid: var_id }) } else { None } })); } ir.set_captures(expr.hir_id, call_caps); - + let old_body_owner = ir.body_owner; + ir.body_owner = closure_def_id; intravisit::walk_expr(ir, expr); + ir.body_owner = old_body_owner; } // live nodes required for interesting control flow: @@ -1327,8 +1341,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { -> LiveNode { match path.res { Res::Local(hid) => { - let nid = self.ir.tcx.hir().hir_to_node_id(hid); - self.access_var(hir_id, nid, succ, acc, path.span) + let upvars = self.ir.tcx.upvars(self.ir.body_owner); + if !upvars.map_or(false, |upvars| upvars.contains_key(&hid)) { + let nid = self.ir.tcx.hir().hir_to_node_id(hid); + self.access_var(hir_id, nid, succ, acc, path.span) + } else { + succ + } } _ => succ } @@ -1520,13 +1539,16 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match expr.node { hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { if let Res::Local(var_hid) = path.res { - // Assignment to an immutable variable or argument: only legal - // if there is no later assignment. If this local is actually - // mutable, then check for a reassignment to flag the mutability - // as being used. - let ln = self.live_node(expr.hir_id, expr.span); - let var = self.variable(var_hid, expr.span); - self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var); + let upvars = self.ir.tcx.upvars(self.ir.body_owner); + if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hid)) { + // Assignment to an immutable variable or argument: only legal + // if there is no later assignment. If this local is actually + // mutable, then check for a reassignment to flag the mutability + // as being used. + let ln = self.live_node(expr.hir_id, expr.span); + let var = self.variable(var_hid, expr.span); + self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var); + } } } _ => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 8d7c6f18a854f..7011948148d84 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -78,6 +78,7 @@ use syntax_pos::Span; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::indexed_vec::Idx; use std::rc::Rc; use crate::util::nodemap::ItemLocalSet; @@ -288,6 +289,8 @@ impl HirNode for hir::Pat { #[derive(Clone)] pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, + pub body_owner: DefId, + pub upvars: Option<&'tcx FxIndexMap>, pub region_scope_tree: &'a region::ScopeTree, pub tables: &'a ty::TypeckTables<'tcx>, rvalue_promotable_map: Option<&'tcx ItemLocalSet>, @@ -398,12 +401,15 @@ impl MutabilityCategory { impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + body_owner: DefId, region_scope_tree: &'a region::ScopeTree, tables: &'a ty::TypeckTables<'tcx>, rvalue_promotable_map: Option<&'tcx ItemLocalSet>) -> MemCategorizationContext<'a, 'tcx, 'tcx> { MemCategorizationContext { tcx, + body_owner, + upvars: tcx.upvars(body_owner), region_scope_tree, tables, rvalue_promotable_map, @@ -423,6 +429,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { /// - similarly, as the results of upvar analysis are not yet /// known, the results around upvar accesses may be incorrect. pub fn with_infer(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + body_owner: DefId, region_scope_tree: &'a region::ScopeTree, tables: &'a ty::TypeckTables<'tcx>) -> MemCategorizationContext<'a, 'gcx, 'tcx> { @@ -436,6 +443,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { MemCategorizationContext { tcx, + body_owner, + upvars: tcx.upvars(body_owner), region_scope_tree, tables, rvalue_promotable_map, @@ -737,21 +746,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }) } - Res::Upvar(var_id, _, fn_node_id) => { + Res::Local(var_id) => { let var_nid = self.tcx.hir().hir_to_node_id(var_id); - self.cat_upvar(hir_id, span, var_nid, fn_node_id) - } - - Res::Local(vid) => { - let vnid = self.tcx.hir().hir_to_node_id(vid); - Ok(cmt_ { - hir_id, - span, - cat: Categorization::Local(vid), - mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vnid), - ty: expr_ty, - note: NoteNone - }) + if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) { + self.cat_upvar(hir_id, span, var_nid) + } else { + Ok(cmt_ { + hir_id, + span, + cat: Categorization::Local(var_id), + mutbl: MutabilityCategory::from_local(self.tcx, self.tables, var_nid), + ty: expr_ty, + note: NoteNone + }) + } } def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def) @@ -760,15 +768,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Categorize an upvar, complete with invisible derefs of closure // environment and upvar reference as appropriate. - fn cat_upvar(&self, - hir_id: hir::HirId, - span: Span, - var_id: ast::NodeId, - fn_node_id: ast::NodeId) - -> McResult> - { - let fn_hir_id = self.tcx.hir().node_to_hir_id(fn_node_id); - + fn cat_upvar( + &self, + hir_id: hir::HirId, + span: Span, + var_id: ast::NodeId, + ) -> McResult> { // An upvar can have up to 3 components. We translate first to a // `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the // field from the environment. @@ -792,6 +797,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk // FnOnce | copied | upvar -> &'up bk + let closure_expr_def_id = self.body_owner; + let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id( + LocalDefId::from_def_id(closure_expr_def_id), + ); let ty = self.node_ty(fn_hir_id)?; let kind = match ty.sty { ty::Generator(..) => ty::ClosureKind::FnOnce, @@ -813,7 +822,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { _ => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", ty), }; - let closure_expr_def_id = self.tcx.hir().local_def_id(fn_node_id); let var_hir_id = self.tcx.hir().node_to_hir_id(var_id); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index c9835dbd5e78f..45e1d983511c0 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -104,7 +104,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> { }; match res { - Some(Res::Local(hir_id)) | Some(Res::Upvar(hir_id, ..)) => { + Some(Res::Local(hir_id)) => { self.reachable_symbols.insert(hir_id); } Some(res) => { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d4ef134728eaf..6213eda651486 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2562,8 +2562,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { let mut struct_fmt = fmt.debug_struct(&name); if let Some(upvars) = tcx.upvars(def_id) { - for (upvar, place) in upvars.iter().zip(places) { - let var_name = tcx.hir().name_by_hir_id(upvar.var_id()); + for (&var_id, place) in upvars.keys().zip(places) { + let var_name = tcx.hir().name_by_hir_id(var_id); struct_fmt.field(&var_name.as_str(), place); } } @@ -2581,8 +2581,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { let mut struct_fmt = fmt.debug_struct(&name); if let Some(upvars) = tcx.upvars(def_id) { - for (upvar, place) in upvars.iter().zip(places) { - let var_name = tcx.hir().name_by_hir_id(upvar.var_id()); + for (&var_id, place) in upvars.keys().zip(places) { + let var_name = tcx.hir().name_by_hir_id(var_id); struct_fmt.field(&var_name.as_str(), place); } } diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index b8621c8ad30e2..18308f5444221 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -826,7 +826,7 @@ rustc_queries! { desc { "generating a postorder list of CrateNums" } } - query upvars(_: DefId) -> Option<&'tcx [hir::Upvar]> { + query upvars(_: DefId) -> Option<&'tcx FxIndexMap> { eval_always } query maybe_unused_trait_import(_: DefId) -> bool { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index b4823db992054..b2d080a4f965a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1062,11 +1062,6 @@ pub struct GlobalCtxt<'tcx> { pub queries: query::Queries<'tcx>, - // Records the captured variables referenced by every closure - // expression. Do not track deps for this, just recompute it from - // scratch every time. - upvars: FxHashMap>, - maybe_unused_trait_imports: FxHashSet, maybe_unused_extern_crates: Vec<(DefId, Span)>, /// A map of glob use to a set of names it actually imports. Currently only @@ -1297,12 +1292,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }).collect(); (k, exports) }).collect(), - upvars: resolutions.upvars.into_iter().map(|(k, v)| { - let vars: Vec<_> = v.into_iter().map(|e| { - e.map_id(|id| hir.node_to_hir_id(id)) - }).collect(); - (hir.local_def_id(k), vars) - }).collect(), maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports .into_iter() @@ -3023,7 +3012,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { assert_eq!(id, LOCAL_CRATE); tcx.arena.alloc(middle::lang_items::collect(tcx)) }; - providers.upvars = |tcx, id| tcx.gcx.upvars.get(&id).map(|v| &v[..]); providers.maybe_unused_trait_import = |tcx, id| { tcx.maybe_unused_trait_imports.contains(&id) }; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 094e1d05aeb77..e89fb53c23619 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -8,7 +8,7 @@ pub use self::BorrowKind::*; pub use self::IntVarValue::*; pub use self::fold::TypeFoldable; -use crate::hir::{map as hir_map, UpvarMap, GlobMap, TraitMap}; +use crate::hir::{map as hir_map, GlobMap, TraitMap}; use crate::hir::Node; use crate::hir::def::{Res, DefKind, CtorOf, CtorKind, ExportMap}; use crate::hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -51,6 +51,7 @@ use syntax::symbol::{kw, sym, Symbol, LocalInternedString, InternedString}; use syntax_pos::Span; use smallvec; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; @@ -122,7 +123,6 @@ mod sty; #[derive(Clone)] pub struct Resolutions { - pub upvars: UpvarMap, pub trait_map: TraitMap, pub maybe_unused_trait_imports: NodeSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, @@ -808,7 +808,7 @@ pub struct UpvarBorrow<'tcx> { pub region: ty::Region<'tcx>, } -pub type UpvarListMap = FxHashMap>; +pub type UpvarListMap = FxHashMap>; pub type UpvarCaptureMap<'tcx> = FxHashMap>; #[derive(Copy, Clone)] diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 300ea9bb49785..a8a6bca4fd434 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -585,16 +585,16 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) { p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id))); let mut sep = " "; - for (upvar, upvar_ty) in self.tcx().upvars(did) + for (&var_id, upvar_ty) in self.tcx().upvars(did) .as_ref() - .map_or(&[][..], |v| &v[..]) .iter() + .flat_map(|v| v.keys()) .zip(upvar_tys) { p!( write("{}{}:", sep, - self.tcx().hir().name_by_hir_id(upvar.var_id())), + self.tcx().hir().name_by_hir_id(var_id)), print(upvar_ty)); sep = ", "; } @@ -628,16 +628,16 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id))); } let mut sep = " "; - for (upvar, upvar_ty) in self.tcx().upvars(did) + for (&var_id, upvar_ty) in self.tcx().upvars(did) .as_ref() - .map_or(&[][..], |v| &v[..]) .iter() + .flat_map(|v| v.keys()) .zip(upvar_tys) { p!( write("{}{}:", sep, - self.tcx().hir().name_by_hir_id(upvar.var_id())), + self.tcx().hir().name_by_hir_id(var_id)), print(upvar_ty)); sep = ", "; } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index a2bced97102a6..e595b52876f4c 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -45,7 +45,7 @@ use crate::util::profiling::ProfileCategory::*; use rustc_data_structures::svh::Svh; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxIndexMap, FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::StableVec; use rustc_data_structures::sync::Lrc; use rustc_data_structures::fingerprint::Fingerprint; diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index d2d5c4fe85c90..35e6c1c5bf5a7 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -208,6 +208,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id); euv::ExprUseVisitor::new(&mut clcx, bccx.tcx, + def_id, param_env, &bccx.region_scope_tree, bccx.tables, diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 3892a18b1400e..e437c08c956ec 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -44,6 +44,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id); euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, + def_id, param_env, &bccx.region_scope_tree, bccx.tables, diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 5f3bac866d6a7..cd792d31187bd 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["dylib"] [dependencies] ena = "0.13" +indexmap = "1" log = "0.4" jobserver_crate = { version = "0.1.13", package = "jobserver" } lazy_static = "1" diff --git a/src/librustc_data_structures/fx.rs b/src/librustc_data_structures/fx.rs index a2afeffe73050..cf73fe8cf85ce 100644 --- a/src/librustc_data_structures/fx.rs +++ b/src/librustc_data_structures/fx.rs @@ -1 +1,6 @@ +use std::hash::BuildHasherDefault; + pub use rustc_hash::{FxHasher, FxHashMap, FxHashSet}; + +pub type FxIndexMap = indexmap::IndexMap>; +pub type FxIndexSet = indexmap::IndexSet>; diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 2b844aa24d49c..270d952062764 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -323,6 +323,37 @@ impl, CTX> HashStable for Vec { } } +impl HashStable for indexmap::IndexMap + where K: HashStable + Eq + Hash, + V: HashStable, + R: BuildHasher, +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for kv in self { + kv.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for indexmap::IndexSet + where K: HashStable + Eq + Hash, + R: BuildHasher, +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for key in self { + key.hash_stable(ctx, hasher); + } + } +} + impl HashStable for SmallVec<[A; 1]> where A: HashStable { #[inline] fn hash_stable(&self, diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 4a96864dc9d66..9691d0337d7d2 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -178,7 +178,6 @@ impl ExpansionResult { ExpansionResult { defs: Steal::new(resolver.definitions), resolutions: Steal::new(Resolutions { - upvars: resolver.upvars, export_map: resolver.export_map, trait_map: resolver.trait_map, glob_map: resolver.glob_map, @@ -197,7 +196,6 @@ impl ExpansionResult { ExpansionResult { defs: Steal::new(resolver.definitions.clone()), resolutions: Steal::new(Resolutions { - upvars: resolver.upvars.clone(), export_map: resolver.export_map.clone(), trait_map: resolver.trait_map.clone(), glob_map: resolver.glob_map.clone(), diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 5a22c81a5d057..31af20fdb77eb 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -348,9 +348,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // `tcx.upvars(def_id)` returns an `Option`, which is `None` in case // the closure comes from another crate. But in that case we wouldn't // be borrowck'ing it, so we can just unwrap: - let upvar = self.infcx.tcx.upvars(def_id).unwrap()[field.index()]; + let (&var_id, _) = self.infcx.tcx.upvars(def_id).unwrap() + .get_index(field.index()).unwrap(); - self.infcx.tcx.hir().name_by_hir_id(upvar.var_id()).to_string() + self.infcx.tcx.hir().name_by_hir_id(var_id).to_string() } _ => { // Might need a revision when the fields in trait RFC is implemented @@ -645,12 +646,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let hir::ExprKind::Closure( .., args_span, _ ) = expr { - for (v, place) in self.infcx.tcx.upvars(def_id)?.iter().zip(places) { + for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) { match place { Operand::Copy(place) | Operand::Move(place) if target_place == place => { debug!("closure_span: found captured local {:?}", place); - return Some((*args_span, v.span)); + return Some((*args_span, upvar.span)); }, _ => {} } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 82be2405701d5..4ae4d039d6034 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -149,7 +149,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( .upvar_list .get(&def_id) .into_iter() - .flatten() + .flat_map(|v| v.values()) .map(|upvar_id| { let var_hir_id = upvar_id.var_path.hir_id; let var_node_id = tcx.hir().hir_to_node_id(var_hir_id); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 5797f9c347866..123b46cb04820 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -651,10 +651,9 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, .get(&fn_def_id) .into_iter() .flatten() - .map(|upvar_id| { - let var_hir_id = upvar_id.var_path.hir_id; + .map(|(&var_hir_id, &upvar_id)| { let var_node_id = tcx_hir.hir_to_node_id(var_hir_id); - let capture = hir_tables.upvar_capture(*upvar_id); + let capture = hir_tables.upvar_capture(upvar_id); let by_ref = match capture { ty::UpvarCapture::ByValue => false, ty::UpvarCapture::ByRef(..) => true, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index d0ea303a93c69..5a6b6a7483052 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -515,7 +515,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let upvars = cx.tcx.upvars(def_id).iter() .flat_map(|upvars| upvars.iter()) .zip(substs.upvar_tys(def_id, cx.tcx)) - .map(|(upvar, ty)| capture_upvar(cx, expr, upvar, ty)) + .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty)) .collect(); ExprKind::Closure { closure_id: def_id, @@ -960,36 +960,44 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Res::Def(DefKind::Static, id) => ExprKind::StaticRef { id }, - Res::Local(..) | Res::Upvar(..) => convert_var(cx, expr, res), + Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id), _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res), } } -fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, - expr: &'tcx hir::Expr, - res: Res) - -> ExprKind<'tcx> { +fn convert_var( + cx: &mut Cx<'_, '_, 'tcx>, + expr: &'tcx hir::Expr, + var_hir_id: hir::HirId, +) -> ExprKind<'tcx> { + let upvar_index = cx.tables().upvar_list.get(&cx.body_owner) + .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i)); + + debug!("convert_var({:?}): upvar_index={:?}, body_owner={:?}", + var_hir_id, upvar_index, cx.body_owner); + let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - match res { - Res::Local(id) => ExprKind::VarRef { id }, + match upvar_index { + None => ExprKind::VarRef { id: var_hir_id }, - Res::Upvar(var_hir_id, index, closure_expr_id) => { - debug!("convert_var(upvar({:?}, {:?}, {:?}))", - var_hir_id, - index, - closure_expr_id); + Some(upvar_index) => { + let closure_def_id = cx.body_owner; + let upvar_id = ty::UpvarId { + var_path: ty::UpvarPath {hir_id: var_hir_id}, + closure_expr_id: LocalDefId::from_def_id(closure_def_id), + }; let var_ty = cx.tables().node_type(var_hir_id); // FIXME free regions in closures are not right - let closure_ty = cx.tables() - .node_type(cx.tcx.hir().node_to_hir_id(closure_expr_id)); + let closure_ty = cx.tables().node_type( + cx.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id), + ); // FIXME we're just hard-coding the idea that the // signature will be &self or &mut self and hence will // have a bound region with number 0 - let closure_def_id = cx.tcx.hir().local_def_id(closure_expr_id); let region = ty::ReFree(ty::FreeRegion { scope: closure_def_id, bound_region: ty::BoundRegion::BrAnon(0), @@ -1060,15 +1068,11 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // at this point we have `self.n`, which loads up the upvar let field_kind = ExprKind::Field { lhs: self_expr.to_ref(), - name: Field::new(index), + name: Field::new(upvar_index), }; // ...but the upvar might be an `&T` or `&mut T` capture, at which // point we need an implicit deref - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath {hir_id: var_hir_id}, - closure_expr_id: LocalDefId::from_def_id(closure_def_id), - }; match cx.tables().upvar_capture(upvar_id) { ty::UpvarCapture::ByValue => field_kind, ty::UpvarCapture::ByRef(borrow) => { @@ -1087,8 +1091,6 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } } - - _ => span_bug!(expr.span, "type of & not region"), } } @@ -1178,10 +1180,9 @@ fn overloaded_place<'a, 'gcx, 'tcx>( fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_expr: &'tcx hir::Expr, - upvar: &hir::Upvar, + var_hir_id: hir::HirId, upvar_ty: Ty<'tcx>) -> ExprRef<'tcx> { - let var_hir_id = upvar.var_id(); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: cx.tcx.hir().local_def_id_from_hir_id(closure_expr.hir_id).to_local(), @@ -1193,7 +1194,7 @@ fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, temp_lifetime, ty: var_ty, span: closure_expr.span, - kind: convert_var(cx, closure_expr, upvar.res), + kind: convert_var(cx, closure_expr, var_hir_id), }; match upvar_capture { ty::UpvarCapture::ByValue => captured_var.to_ref(), diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 80f64e85f9cf9..f4a23a90dee92 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -38,6 +38,9 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { /// `const`, or the body of a `const fn`. constness: hir::Constness, + /// The `DefId` of the owner of this body. + body_owner: DefId, + /// What kind of body is being compiled. pub body_owner_kind: hir::BodyOwnerKind, @@ -53,6 +56,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { src_id: hir::HirId) -> Cx<'a, 'gcx, 'tcx> { let tcx = infcx.tcx; let src_def_id = tcx.hir().local_def_id_from_hir_id(src_id); + let tables = tcx.typeck_tables_of(src_def_id); let body_owner_kind = tcx.hir().body_owner_kind_by_hir_id(src_id); let constness = match body_owner_kind { @@ -82,8 +86,9 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { param_env: tcx.param_env(src_def_id), identity_substs: InternalSubsts::identity_for_item(tcx.global_tcx(), src_def_id), region_scope_tree: tcx.region_scope_tree(src_def_id), - tables: tcx.typeck_tables_of(src_def_id), + tables, constness, + body_owner: src_def_id, body_owner_kind, check_overflow, control_flow_destroyed: Vec::new(), diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 0edf32d3a306c..215faee953230 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -35,6 +35,7 @@ pub(crate) fn check_match<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) MatchVisitor { tcx, + body_owner: def_id, tables: tcx.body_tables(body_id), region_scope_tree: &tcx.region_scope_tree(def_id), param_env: tcx.param_env(def_id), @@ -48,6 +49,7 @@ fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> Diagn struct MatchVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, + body_owner: DefId, tables: &'a ty::TypeckTables<'tcx>, param_env: ty::ParamEnv<'tcx>, identity_substs: SubstsRef<'tcx>, @@ -632,6 +634,7 @@ fn check_for_mutation_in_guard(cx: &MatchVisitor<'_, '_>, guard: &hir::Guard) { hir::Guard::If(expr) => ExprUseVisitor::new(&mut checker, cx.tcx, + cx.body_owner, cx.param_env, cx.region_scope_tree, cx.tables, diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 851d32203db61..552628ee1ceb7 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -174,8 +174,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, ' if let Some(upvars) = tables.upvar_list.get(&def_id) { // Sometimes the index is beyond the number of upvars (seen // for a generator). - if let Some(upvar_id) = upvars.get(field) { - let var_hir_id = upvar_id.var_path.hir_id; + if let Some((&var_hir_id, _)) = upvars.get_index(field) { let var_node_id = self.ecx.tcx.hir().hir_to_node_id(var_hir_id); if let hir::Node::Binding(pat) = self.ecx.tcx.hir().get(var_node_id) { if let hir::PatKind::Binding(_, _, ident, _) = pat.node { diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 85cd602db591f..869cae3d3a8e4 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -199,8 +199,15 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { let param_env = self.param_env; let region_scope_tree = self.tcx.region_scope_tree(item_def_id); let tables = self.tables; - euv::ExprUseVisitor::new(self, tcx, param_env, ®ion_scope_tree, tables, None) - .consume_body(body); + euv::ExprUseVisitor::new( + self, + tcx, + item_def_id, + param_env, + ®ion_scope_tree, + tables, + None, + ).consume_body(body); let body_promotable = self.check_expr(&body.value); self.in_fn = outer_in_fn; diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 968a45e241e84..8e3359c775288 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -12,6 +12,7 @@ test = false [dependencies] bitflags = "1.0" +indexmap = "1" log = "0.4" syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 59e5fc149fc6e..21e759ccc650e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -29,7 +29,7 @@ use rustc::hir::def::{ }; use rustc::hir::def::Namespace::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; -use rustc::hir::{Upvar, UpvarMap, TraitCandidate, TraitMap, GlobMap}; +use rustc::hir::{TraitCandidate, TraitMap, GlobMap}; use rustc::ty::{self, DefIdTree}; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; use rustc::{bug, span_bug}; @@ -612,7 +612,6 @@ impl<'a> PathSource<'a> { | Res::Def(DefKind::Const, _) | Res::Def(DefKind::Static, _) | Res::Local(..) - | Res::Upvar(..) | Res::Def(DefKind::Fn, _) | Res::Def(DefKind::Method, _) | Res::Def(DefKind::AssocConst, _) @@ -853,7 +852,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { function_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, _: Span, - node_id: NodeId) + _: NodeId) { debug!("(resolving function) entering function"); let (rib_kind, asyncness) = match function_kind { @@ -864,7 +863,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { FnKind::Closure(_) => // Async closures aren't resolved through `visit_fn`-- they're // processed separately - (ClosureRibKind(node_id), &IsAsync::NotAsync), + (NormalRibKind, &IsAsync::NotAsync), }; // Create a value rib for the function. @@ -898,12 +897,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { visit::walk_fn_ret_ty(self, &declaration.output); // Resolve the function body, potentially inside the body of an async closure - if let IsAsync::Async { closure_id, .. } = asyncness { - let rib_kind = ClosureRibKind(*closure_id); - self.ribs[ValueNS].push(Rib::new(rib_kind)); - self.label_ribs.push(Rib::new(rib_kind)); - } - match function_kind { FnKind::ItemFn(.., body) | FnKind::Method(.., body) => { if let IsAsync::Async { ref arguments, .. } = asyncness { @@ -926,12 +919,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { } }; - // Leave the body of the async closure - if asyncness.is_async() { - self.label_ribs.pop(); - self.ribs[ValueNS].pop(); - } - debug!("(resolving function) leaving function"); self.label_ribs.pop(); @@ -1018,17 +1005,13 @@ enum GenericParameters<'a, 'b> { RibKind<'a>), } -/// The rib kind controls the translation of local -/// definitions (`Res::Local`) to upvars (`Res::Upvar`). +/// The rib kind restricts certain accesses, +/// e.g. to a `Res::Local` of an outer item. #[derive(Copy, Clone, Debug)] enum RibKind<'a> { - /// No translation needs to be applied. + /// No restriction needs to be applied. NormalRibKind, - /// We passed through a closure scope at the given `NodeId`. - /// Translate upvars as appropriate. - ClosureRibKind(NodeId /* func id */), - /// We passed through an impl or trait and are now in one of its /// methods or associated types. Allow references to ty params that impl or trait /// binds. Disallow any other upvars (including other ty params that are @@ -1668,8 +1651,6 @@ pub struct Resolver<'a> { /// Resolutions for labels (node IDs of their corresponding blocks or loops). label_res_map: NodeMap, - pub upvars: UpvarMap, - upvars_seen: NodeMap>, pub export_map: ExportMap, pub trait_map: TraitMap, @@ -2032,8 +2013,6 @@ impl<'a> Resolver<'a> { partial_res_map: Default::default(), import_res_map: Default::default(), label_res_map: Default::default(), - upvars: Default::default(), - upvars_seen: Default::default(), export_map: FxHashMap::default(), trait_map: Default::default(), module_map, @@ -2206,7 +2185,7 @@ impl<'a> Resolver<'a> { if let Some(res) = self.ribs[ns][i].bindings.get(&ident).cloned() { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::Res( - self.adjust_local_res(ns, i, res, record_used, path_span) + self.validate_res_from_ribs(ns, i, res, record_used, path_span), )); } @@ -4008,14 +3987,16 @@ impl<'a> Resolver<'a> { diag); } - // Resolve a local definition, potentially adjusting for closures. - fn adjust_local_res(&mut self, - ns: Namespace, - rib_index: usize, - mut res: Res, - record_used: bool, - span: Span) -> Res { - debug!("adjust_local_res"); + // Validate a local resolution (from ribs). + fn validate_res_from_ribs( + &mut self, + ns: Namespace, + rib_index: usize, + res: Res, + record_used: bool, + span: Span, + ) -> Res { + debug!("validate_res_from_ribs({:?})", res); let ribs = &self.ribs[ns][rib_index + 1..]; // An invalid forward use of a type parameter from a previous default. @@ -4037,10 +4018,7 @@ impl<'a> Resolver<'a> { } match res { - Res::Upvar(..) => { - span_bug!(span, "unexpected {:?} in bindings", res) - } - Res::Local(node_id) => { + Res::Local(_) => { use ResolutionError::*; let mut res_err = None; @@ -4050,30 +4028,6 @@ impl<'a> Resolver<'a> { ForwardTyParamBanRibKind | TyParamAsConstParamTy => { // Nothing to do. Continue. } - ClosureRibKind(function_id) => { - let prev_res = res; - - let seen = self.upvars_seen - .entry(function_id) - .or_default(); - if let Some(&index) = seen.get(&node_id) { - res = Res::Upvar(node_id, index, function_id); - continue; - } - let vec = self.upvars - .entry(function_id) - .or_default(); - let depth = vec.len(); - res = Res::Upvar(node_id, depth, function_id); - - if record_used { - vec.push(Upvar { - res: prev_res, - span, - }); - seen.insert(node_id, depth); - } - } ItemRibKind | FnItemRibKind | AssocItemRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we @@ -4103,7 +4057,7 @@ impl<'a> Resolver<'a> { Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => { for rib in ribs { match rib.kind { - NormalRibKind | AssocItemRibKind | ClosureRibKind(..) | + NormalRibKind | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind | ConstantItemRibKind | TyParamAsConstParamTy => { // Nothing to do. Continue. @@ -4483,25 +4437,15 @@ impl<'a> Resolver<'a> { visit::walk_expr(self, expr); self.current_type_ascription.pop(); } - // Resolve the body of async exprs inside the async closure to which they desugar - ExprKind::Async(_, async_closure_id, ref block) => { - let rib_kind = ClosureRibKind(async_closure_id); - self.ribs[ValueNS].push(Rib::new(rib_kind)); - self.label_ribs.push(Rib::new(rib_kind)); - self.visit_block(&block); - self.label_ribs.pop(); - self.ribs[ValueNS].pop(); - } // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to // resolve the arguments within the proper scopes so that usages of them inside the // closure are detected as upvars rather than normal closure arg usages. ExprKind::Closure( - _, IsAsync::Async { closure_id: inner_closure_id, .. }, _, + _, IsAsync::Async { .. }, _, ref fn_decl, ref body, _span, ) => { - let rib_kind = ClosureRibKind(expr.id); + let rib_kind = NormalRibKind; self.ribs[ValueNS].push(Rib::new(rib_kind)); - self.label_ribs.push(Rib::new(rib_kind)); // Resolve arguments: let mut bindings_list = FxHashMap::default(); for argument in &fn_decl.inputs { @@ -4513,18 +4457,12 @@ impl<'a> Resolver<'a> { // Now resolve the inner closure { - let rib_kind = ClosureRibKind(inner_closure_id); - self.ribs[ValueNS].push(Rib::new(rib_kind)); - self.label_ribs.push(Rib::new(rib_kind)); // No need to resolve arguments: the inner closure has none. // Resolve the return type: visit::walk_fn_ret_ty(self, &fn_decl.output); // Resolve the body self.visit_expr(body); - self.label_ribs.pop(); - self.ribs[ValueNS].pop(); } - self.label_ribs.pop(); self.ribs[ValueNS].pop(); } _ => { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 8faa4c7180780..cca5682d90a9b 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -702,7 +702,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let span = self.span_from_span(span); match res { - Res::Upvar(id, ..) | Res::Local(id) => { + Res::Local(id) => { Some(Ref { kind: RefKind::Variable, span, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 61c281d3dd9d2..a6cd157dc03de 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -350,7 +350,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let def_span = match def { Res::Err => None, - Res::Local(id) | Res::Upvar(id, ..) => { + Res::Local(id) => { Some(self.tcx.hir().span_by_hir_id(id)) }, _ => def diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7a6d02cc33b21..82d198f0b78f7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5264,7 +5264,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(ErrorReported) => return (tcx.types.err, res), }; let path_segs = match res { - Res::Local(_) | Res::Upvar(..) => Vec::new(), + Res::Local(_) => vec![], Res::Def(kind, def_id) => AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id), _ => bug!("instantiate_value_path on {:?}", res), @@ -5325,14 +5325,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } })); - match res { - Res::Local(hid) | Res::Upvar(hid, ..) => { - let ty = self.local_ty(span, hid).decl_ty; - let ty = self.normalize_associated_types_in(span, &ty); - self.write_ty(hir_id, ty); - return (ty, res); - } - _ => {} + if let Res::Local(hid) = res { + let ty = self.local_ty(span, hid).decl_ty; + let ty = self.normalize_associated_types_in(span, &ty); + self.write_ty(hir_id, ty); + return (ty, res); } if generics_has_err { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 62c9c7c8b1c37..21d7e483e9d15 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -200,6 +200,7 @@ pub struct RegionCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { // id of innermost fn body id body_id: hir::HirId, + body_owner: DefId, // call_site scope of innermost fn call_site_scope: Option, @@ -236,6 +237,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { region_scope_tree, repeating_scope: initial_repeating_scope, body_id: initial_body_id, + body_owner: subject, call_site_scope: None, subject_def_id: subject, outlives_environment, @@ -308,6 +310,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let body_id = body.id(); self.body_id = body_id.hir_id; + self.body_owner = self.tcx.hir().body_owner_def_id(body_id); let call_site = region::Scope { id: body.value.hir_id.local_id, @@ -466,6 +469,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { // Save state of current function before invoking // `visit_fn_body`. We will restore afterwards. let old_body_id = self.body_id; + let old_body_owner = self.body_owner; let old_call_site_scope = self.call_site_scope; let env_snapshot = self.outlives_environment.push_snapshot_pre_closure(); @@ -477,6 +481,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { .pop_snapshot_post_closure(env_snapshot); self.call_site_scope = old_call_site_scope; self.body_id = old_body_id; + self.body_owner = old_body_owner; } //visit_pat: visit_pat, // (..) see above @@ -829,6 +834,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { { f(mc::MemCategorizationContext::with_infer( &self.infcx, + self.body_owner, &self.region_scope_tree, &self.tables.borrow(), )) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index c3861f964e453..82c173a6f7a57 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -41,6 +41,7 @@ use rustc::hir::def_id::LocalDefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::infer::UpvarRegion; use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; +use rustc_data_structures::fx::FxIndexMap; use syntax::ast; use syntax_pos::Span; @@ -122,18 +123,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(upvars) = self.tcx.upvars(closure_def_id) { - let mut upvar_list: Vec = Vec::with_capacity(upvars.len()); - for upvar in upvars.iter() { + let mut upvar_list: FxIndexMap = + FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default()); + for (&var_hir_id, _) in upvars.iter() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { - hir_id: upvar.var_id(), + hir_id: var_hir_id, }, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; debug!("seed upvar_id {:?}", upvar_id); // Adding the upvar Id to the list of Upvars, which will be added // to the map for the closure at the end of the for loop. - upvar_list.push(upvar_id); + upvar_list.insert(var_hir_id, upvar_id); let capture_kind = match capture_clause { hir::CaptureByValue => ty::UpvarCapture::ByValue, @@ -165,6 +167,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id()); + assert_eq!(body_owner_def_id, closure_def_id); let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id); let mut delegate = InferBorrowKind { fcx: self, @@ -176,6 +179,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { euv::ExprUseVisitor::with_infer( &mut delegate, &self.infcx, + body_owner_def_id, self.param_env, region_scope_tree, &self.tables.borrow(), @@ -249,8 +253,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.upvars(closure_def_id).iter().flat_map(|upvars| { upvars .iter() - .map(|upvar| { - let var_hir_id = upvar.var_id(); + .map(|(&var_hir_id, _)| { let upvar_ty = self.node_ty(var_hir_id); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 9e60bff200e14..a535f776dfe60 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -54,7 +54,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } wbcx.visit_body(body); wbcx.visit_upvar_capture_map(); - wbcx.visit_upvar_list_map(); wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); wbcx.visit_fru_field_types(); @@ -74,6 +73,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ); wbcx.tables.used_trait_imports = used_trait_imports; + wbcx.tables.upvar_list = mem::replace( + &mut self.tables.borrow_mut().upvar_list, + Default::default(), + ); + wbcx.tables.tainted_by_errors = self.is_tainted_by_errors(); debug!( @@ -343,21 +347,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - /// Runs through the function context's upvar list map and adds the same to - /// the TypeckTables. upvarlist is a hashmap of the list of upvars referred - /// to in a closure.. - fn visit_upvar_list_map(&mut self) { - for (closure_def_id, upvar_list) in self.fcx.tables.borrow().upvar_list.iter() { - debug!( - "UpvarIDs captured by closure {:?} are: {:?}", - closure_def_id, upvar_list - ); - self.tables - .upvar_list - .insert(*closure_def_id, upvar_list.to_vec()); - } - } - fn visit_closures(&mut self) { let fcx_tables = self.fcx.tables.borrow(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); diff --git a/src/libserialize/Cargo.toml b/src/libserialize/Cargo.toml index 949af0e2b9746..fa31a68a75b72 100644 --- a/src/libserialize/Cargo.toml +++ b/src/libserialize/Cargo.toml @@ -10,4 +10,5 @@ path = "lib.rs" crate-type = ["dylib", "rlib"] [dependencies] +indexmap = "1" smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index c0a8fa9d0016d..80aeecb84d72b 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -217,6 +217,75 @@ impl Decodable for HashSet } } +impl Encodable for indexmap::IndexMap + where K: Encodable + Hash + Eq, + V: Encodable, + S: BuildHasher, +{ + fn encode(&self, e: &mut E) -> Result<(), E::Error> { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self { + e.emit_map_elt_key(i, |e| key.encode(e))?; + e.emit_map_elt_val(i, |e| val.encode(e))?; + i += 1; + } + Ok(()) + }) + } +} + +impl Decodable for indexmap::IndexMap + where K: Decodable + Hash + Eq, + V: Decodable, + S: BuildHasher + Default, +{ + fn decode(d: &mut D) -> Result, D::Error> { + d.read_map(|d, len| { + let state = Default::default(); + let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state); + for i in 0..len { + let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?; + let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?; + map.insert(key, val); + } + Ok(map) + }) + } +} + +impl Encodable for indexmap::IndexSet + where T: Encodable + Hash + Eq, + S: BuildHasher, +{ + fn encode(&self, s: &mut E) -> Result<(), E::Error> { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self { + s.emit_seq_elt(i, |s| e.encode(s))?; + i += 1; + } + Ok(()) + }) + } +} + +impl Decodable for indexmap::IndexSet + where T: Decodable + Hash + Eq, + S: BuildHasher + Default, +{ + fn decode(d: &mut D) -> Result, D::Error> { + d.read_seq(|d, len| { + let state = Default::default(); + let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state); + for i in 0..len { + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?); + } + Ok(set) + }) + } +} + impl Encodable for Rc<[T]> { fn encode(&self, s: &mut E) -> Result<(), E::Error> { s.emit_seq(self.len(), |s| { diff --git a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr index a6dbcf36077a7..f22b7da811949 100644 --- a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr +++ b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr @@ -4,7 +4,7 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as m LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here LL | ptr = box Foo { x: ptr.x + 1 }; - | --- first borrow occurs due to use of `ptr` in closure + | --- first borrow occurs due to use of `ptr` in closure LL | }; LL | test(&*ptr); | ---- ^^^^^ immutable borrow occurs here diff --git a/src/test/ui/issues/issue-11192.stderr b/src/test/ui/issues/issue-11192.stderr index 2a9d913171c3e..dfe7b3f6b5f9c 100644 --- a/src/test/ui/issues/issue-11192.stderr +++ b/src/test/ui/issues/issue-11192.stderr @@ -5,7 +5,7 @@ LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here LL | println!("access {}", foo.x); LL | ptr = box Foo { x: ptr.x + 1 }; - | --- first borrow occurs due to use of `ptr` in closure + | --- first borrow occurs due to use of `ptr` in closure ... LL | test(&*ptr); | ---- ^^^^^ immutable borrow occurs here diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index 135de0445a799..186f25a3c89db 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -7,11 +7,11 @@ LL | let mut closure1 = || p = &y; = note: defining type: DefId(0:14 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [ i16, extern "rust-call" fn(()), - &'_#1r mut &'_#2r i32, - &'_#3r i32, + &'_#1r i32, + &'_#2r mut &'_#3r i32, ] = note: number of external vids: 4 - = note: where '_#3r: '_#2r + = note: where '_#1r: '_#3r note: External requirements --> $DIR/escape-upvar-nested.rs:20:27 @@ -26,11 +26,11 @@ LL | | }; = note: defining type: DefId(0:13 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, extern "rust-call" fn(()), - &'_#1r mut &'_#2r i32, - &'_#3r i32, + &'_#1r i32, + &'_#2r mut &'_#3r i32, ] = note: number of external vids: 4 - = note: where '_#3r: '_#2r + = note: where '_#1r: '_#3r note: No external requirements --> $DIR/escape-upvar-nested.rs:13:1 diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index 8c37ab7b768c3..0df2c0f69a71b 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -7,11 +7,11 @@ LL | let mut closure = || p = &y; = note: defining type: DefId(0:13 ~ escape_upvar_ref[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, extern "rust-call" fn(()), - &'_#1r mut &'_#2r i32, - &'_#3r i32, + &'_#1r i32, + &'_#2r mut &'_#3r i32, ] = note: number of external vids: 4 - = note: where '_#3r: '_#2r + = note: where '_#1r: '_#3r note: No external requirements --> $DIR/escape-upvar-ref.rs:17:1 diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index ad3ac986c94f6..7922cb14eeca8 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -92,6 +92,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("fuchsia-zircon-sys"), Crate("getopts"), Crate("humantime"), + Crate("indexmap"), Crate("itertools"), Crate("jobserver"), Crate("kernel32-sys"),