From 26e61dd8265d5680f7ac40f34b0bd1c9c28baaf0 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 4 May 2019 05:06:52 +0300 Subject: [PATCH 01/11] rustc: replace Res in hir::Upvar with only Local/Upvar data. --- src/librustc/hir/mod.rs | 18 ++++++++---------- src/librustc/middle/expr_use_visitor.rs | 12 +++++++----- src/librustc/middle/liveness.rs | 4 ++-- src/librustc/mir/mod.rs | 4 ++-- src/librustc/ty/print/pretty.rs | 4 ++-- .../borrow_check/error_reporting.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 11 +++++++---- src/librustc_resolve/lib.rs | 18 +++++++++++------- src/librustc_typeck/check/upvar.rs | 9 ++++----- 9 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f03a8ddc90825..bdae04ae47840 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2495,26 +2495,24 @@ impl ForeignItemKind { #[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] pub struct Upvar { /// The variable being captured. - pub res: Res, + pub var_id: Id, + + /// The parent closure, if this is not a direct capture, + /// and the index within that closure's capture list. + pub parent: Option<(ast::NodeId, usize)>, // 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 { + pub fn map_id(self, map: impl FnOnce(Id) -> R) -> Upvar { Upvar { - res: self.res.map_id(map), + var_id: map(self.var_id), + parent: self.parent, 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>>; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 35b6b76a39567..fd9233acbaea7 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -925,9 +925,8 @@ 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(); let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, + var_path: ty::UpvarPath { hir_id: upvar.var_id }, closure_expr_id: closure_def_id.to_local(), }; let upvar_capture = self.mc.tables.upvar_capture(upvar_id); @@ -962,9 +961,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { -> 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) + let var_ty = self.mc.node_ty(upvar.var_id)?; + let res = upvar.parent.map_or( + Res::Local(upvar.var_id), + |(closure_node_id, i)| Res::Upvar(upvar.var_id, i, closure_node_id), + ); + self.mc.cat_res(closure_hir_id, closure_span, var_ty, res) } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 91a19852c6c0e..e19d713d56105 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -486,9 +486,9 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { 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 { + if upvar.parent.is_none() { 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: upvar.var_id }) } else { None } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d4ef134728eaf..1f29b370d2729 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2563,7 +2563,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { 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()); + let var_name = tcx.hir().name_by_hir_id(upvar.var_id); struct_fmt.field(&var_name.as_str(), place); } } @@ -2582,7 +2582,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { 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()); + let var_name = tcx.hir().name_by_hir_id(upvar.var_id); struct_fmt.field(&var_name.as_str(), place); } } diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 300ea9bb49785..03c7226c1afe5 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -594,7 +594,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: p!( write("{}{}:", sep, - self.tcx().hir().name_by_hir_id(upvar.var_id())), + self.tcx().hir().name_by_hir_id(upvar.var_id)), print(upvar_ty)); sep = ", "; } @@ -637,7 +637,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: p!( write("{}{}:", sep, - self.tcx().hir().name_by_hir_id(upvar.var_id())), + self.tcx().hir().name_by_hir_id(upvar.var_id)), print(upvar_ty)); sep = ", "; } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 5a22c81a5d057..74601cc389184 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -350,7 +350,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // be borrowck'ing it, so we can just unwrap: let upvar = self.infcx.tcx.upvars(def_id).unwrap()[field.index()]; - self.infcx.tcx.hir().name_by_hir_id(upvar.var_id()).to_string() + self.infcx.tcx.hir().name_by_hir_id(upvar.var_id).to_string() } _ => { // Might need a revision when the fields in trait RFC is implemented diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index d0ea303a93c69..354aec442ed89 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -1181,19 +1181,22 @@ fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, upvar: &hir::Upvar, 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 }, + var_path: ty::UpvarPath { hir_id: upvar.var_id }, closure_expr_id: cx.tcx.hir().local_def_id_from_hir_id(closure_expr.hir_id).to_local(), }; let upvar_capture = cx.tables().upvar_capture(upvar_id); let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); - let var_ty = cx.tables().node_type(var_hir_id); + let var_ty = cx.tables().node_type(upvar.var_id); + let upvar_res = upvar.parent.map_or( + Res::Local(upvar.var_id), + |(closure_node_id, i)| Res::Upvar(upvar.var_id, i, closure_node_id), + ); let captured_var = Expr { temp_lifetime, ty: var_ty, span: closure_expr.span, - kind: convert_var(cx, closure_expr, upvar.res), + kind: convert_var(cx, closure_expr, upvar_res), }; match upvar_capture { ty::UpvarCapture::ByValue => captured_var.to_ref(), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 59e5fc149fc6e..67ed6a773056b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4040,7 +4040,7 @@ impl<'a> Resolver<'a> { Res::Upvar(..) => { span_bug!(span, "unexpected {:?} in bindings", res) } - Res::Local(node_id) => { + Res::Local(var_id) => { use ResolutionError::*; let mut res_err = None; @@ -4051,27 +4051,31 @@ impl<'a> Resolver<'a> { // Nothing to do. Continue. } ClosureRibKind(function_id) => { - let prev_res = res; + let parent = match res { + Res::Upvar(_, i, closure) => Some((closure, i)), + _ => None, + }; 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); + if let Some(&index) = seen.get(&var_id) { + res = Res::Upvar(var_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); + res = Res::Upvar(var_id, depth, function_id); if record_used { vec.push(Upvar { - res: prev_res, + var_id, + parent, span, }); - seen.insert(node_id, depth); + seen.insert(var_id, depth); } } ItemRibKind | FnItemRibKind | AssocItemRibKind => { diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index c3861f964e453..a4f9ede37c9db 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -126,7 +126,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for upvar in upvars.iter() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { - hir_id: upvar.var_id(), + hir_id: upvar.var_id, }, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; @@ -250,17 +250,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { upvars .iter() .map(|upvar| { - let var_hir_id = upvar.var_id(); - let upvar_ty = self.node_ty(var_hir_id); + let upvar_ty = self.node_ty(upvar.var_id); let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, + var_path: ty::UpvarPath { hir_id: upvar.var_id }, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; let capture = self.tables.borrow().upvar_capture(upvar_id); debug!( "var_id={:?} upvar_ty={:?} capture={:?}", - var_hir_id, upvar_ty, capture + upvar.var_id, upvar_ty, capture ); match capture { From 4b9670a2459fe2b3a8d647d3edefe9fa92299a5a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 4 May 2019 05:05:38 +0300 Subject: [PATCH 02/11] rustc: remove the index field from Res::Upvar. --- src/librustc/hir/def.rs | 7 +------ src/librustc/hir/mod.rs | 5 ++--- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 6 ++++-- src/librustc_mir/hair/cx/mod.rs | 16 +++++++++++++++- src/librustc_resolve/lib.rs | 13 ++++++------- 7 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 03f24dbb29025..f342b230a7176 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -140,7 +140,6 @@ pub enum Res { 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 @@ -397,11 +396,7 @@ 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::Upvar(id, closure) => Res::Upvar(map(id), 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/mod.rs b/src/librustc/hir/mod.rs index bdae04ae47840..547a7a7930c87 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2497,9 +2497,8 @@ pub struct Upvar { /// The variable being captured. pub var_id: Id, - /// The parent closure, if this is not a direct capture, - /// and the index within that closure's capture list. - pub parent: Option<(ast::NodeId, usize)>, + /// The parent closure, if this is not a direct capture. + pub parent: Option, // First span where it is accessed (there can be multiple). pub span: Span diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index fd9233acbaea7..b10acc987a214 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -964,7 +964,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let var_ty = self.mc.node_ty(upvar.var_id)?; let res = upvar.parent.map_or( Res::Local(upvar.var_id), - |(closure_node_id, i)| Res::Upvar(upvar.var_id, i, closure_node_id), + |closure_node_id| Res::Upvar(upvar.var_id, closure_node_id), ); self.mc.cat_res(closure_hir_id, closure_span, var_ty, res) } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 8d7c6f18a854f..c58ce76277323 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -737,7 +737,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }) } - Res::Upvar(var_id, _, fn_node_id) => { + Res::Upvar(var_id, fn_node_id) => { let var_nid = self.tcx.hir().hir_to_node_id(var_id); self.cat_upvar(hir_id, span, var_nid, fn_node_id) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 354aec442ed89..870de08264d74 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -975,7 +975,9 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, match res { Res::Local(id) => ExprKind::VarRef { id }, - Res::Upvar(var_hir_id, index, closure_expr_id) => { + Res::Upvar(var_hir_id, closure_expr_id) => { + let index = cx.upvar_indices[&var_hir_id]; + debug!("convert_var(upvar({:?}, {:?}, {:?}))", var_hir_id, index, @@ -1190,7 +1192,7 @@ fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let var_ty = cx.tables().node_type(upvar.var_id); let upvar_res = upvar.parent.map_or( Res::Local(upvar.var_id), - |(closure_node_id, i)| Res::Upvar(upvar.var_id, i, closure_node_id), + |closure_node_id| Res::Upvar(upvar.var_id, closure_node_id), ); let captured_var = Expr { temp_lifetime, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 80f64e85f9cf9..74382bb1fe25d 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -5,6 +5,7 @@ use crate::hair::*; use crate::hair::util::UserAnnotatedTyHelpers; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::DefId; use rustc::hir::Node; @@ -46,6 +47,9 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { /// See field with the same name on `mir::Body`. control_flow_destroyed: Vec<(Span, String)>, + + /// Reverse map, from upvar variable `HirId`s to their indices. + upvar_indices: FxHashMap, } impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { @@ -53,6 +57,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 { @@ -75,6 +80,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { // Constants always need overflow checks. check_overflow |= constness == hir::Constness::Const; + // Compute reverse mapping, of uvpars to their indices. + let mut upvar_indices = FxHashMap::default(); + if let Some(upvars) = tables.upvar_list.get(&src_def_id) { + upvar_indices.extend( + upvars.iter().enumerate().map(|(i, upvar_id)| (upvar_id.var_path.hir_id, i)), + ); + } + Cx { tcx, infcx, @@ -82,11 +95,12 @@ 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_kind, check_overflow, control_flow_destroyed: Vec::new(), + upvar_indices, } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 67ed6a773056b..490d5ae83b8b1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1669,7 +1669,7 @@ pub struct Resolver<'a> { label_res_map: NodeMap, pub upvars: UpvarMap, - upvars_seen: NodeMap>, + upvars_seen: NodeMap, pub export_map: ExportMap, pub trait_map: TraitMap, @@ -4052,22 +4052,21 @@ impl<'a> Resolver<'a> { } ClosureRibKind(function_id) => { let parent = match res { - Res::Upvar(_, i, closure) => Some((closure, i)), + Res::Upvar(_, closure) => Some(closure), _ => None, }; let seen = self.upvars_seen .entry(function_id) .or_default(); - if let Some(&index) = seen.get(&var_id) { - res = Res::Upvar(var_id, index, function_id); + if seen.contains(&var_id) { + res = Res::Upvar(var_id, function_id); continue; } let vec = self.upvars .entry(function_id) .or_default(); - let depth = vec.len(); - res = Res::Upvar(var_id, depth, function_id); + res = Res::Upvar(var_id, function_id); if record_used { vec.push(Upvar { @@ -4075,7 +4074,7 @@ impl<'a> Resolver<'a> { parent, span, }); - seen.insert(var_id, depth); + seen.insert(var_id); } } ItemRibKind | FnItemRibKind | AssocItemRibKind => { From 9fe0052e542747ead0d8861349326d54f0c0903d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 7 May 2019 04:40:36 +0300 Subject: [PATCH 03/11] rustc: remove the closure ID from hir::Upvar's parent field. --- src/librustc/hir/mod.rs | 6 +- src/librustc/middle/expr_use_visitor.rs | 16 ++++-- src/librustc/middle/liveness.rs | 2 +- src/librustc/middle/mem_categorization.rs | 25 +++++---- src/librustc_mir/hair/cx/expr.rs | 67 +++++++++++++---------- src/librustc_mir/hair/cx/mod.rs | 4 ++ src/librustc_resolve/lib.rs | 8 +-- 7 files changed, 72 insertions(+), 56 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 547a7a7930c87..66535079e1ddb 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2497,8 +2497,8 @@ pub struct Upvar { /// The variable being captured. pub var_id: Id, - /// The parent closure, if this is not a direct capture. - pub parent: Option, + /// Whether this is not a direct capture (comes from parent closure). + pub has_parent: bool, // First span where it is accessed (there can be multiple). pub span: Span @@ -2508,7 +2508,7 @@ impl Upvar { pub fn map_id(self, map: impl FnOnce(Id) -> R) -> Upvar { Upvar { var_id: map(self.var_id), - parent: self.parent, + has_parent: self.has_parent, span: self.span, } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index b10acc987a214..034f60875e7bf 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -961,12 +961,16 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { -> mc::McResult> { // Create the cmt for the variable being borrowed, from the // caller's perspective - let var_ty = self.mc.node_ty(upvar.var_id)?; - let res = upvar.parent.map_or( - Res::Local(upvar.var_id), - |closure_node_id| Res::Upvar(upvar.var_id, closure_node_id), - ); - self.mc.cat_res(closure_hir_id, closure_span, var_ty, res) + if upvar.has_parent { + let closure_def_id = self.tcx().hir().local_def_id_from_hir_id(closure_hir_id); + let parent_def_id = self.tcx().parent(closure_def_id).unwrap(); + assert!(self.tcx().is_closure(parent_def_id)); + let var_nid = self.tcx().hir().hir_to_node_id(upvar.var_id); + self.mc.cat_upvar(closure_hir_id, closure_span, var_nid, parent_def_id) + } else { + let var_ty = self.mc.node_ty(upvar.var_id)?; + self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(upvar.var_id)) + } } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index e19d713d56105..22930cc198946 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -486,7 +486,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { 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 upvar.parent.is_none() { + if !upvar.has_parent { let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); Some(CaptureInfo { ln: upvar_ln, var_hid: upvar.var_id }) } else { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c58ce76277323..7ce729bb71544 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -737,9 +737,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }) } - Res::Upvar(var_id, fn_node_id) => { + Res::Upvar(var_id, closure_node_id) => { let var_nid = self.tcx.hir().hir_to_node_id(var_id); - self.cat_upvar(hir_id, span, var_nid, fn_node_id) + let closure_expr_def_id = self.tcx.hir().local_def_id(closure_node_id); + self.cat_upvar(hir_id, span, var_nid, closure_expr_def_id) } Res::Local(vid) => { @@ -760,15 +761,13 @@ 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); - + pub fn cat_upvar( + &self, + hir_id: hir::HirId, + span: Span, + var_id: ast::NodeId, + closure_expr_def_id: DefId, + ) -> 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 +791,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk // FnOnce | copied | upvar -> &'up bk + 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 +815,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_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 870de08264d74..4d32f1eec44fc 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -6,7 +6,7 @@ use crate::hair::util::UserAnnotatedTyHelpers; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue}; -use rustc::ty::{self, AdtKind, Ty}; +use rustc::ty::{self, AdtKind, DefIdTree, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability, PointerCast}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::hir; @@ -960,38 +960,50 @@ 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), + Res::Upvar(var_hir_id, closure_node_id) => { + let closure_def_id = cx.tcx.hir().local_def_id(closure_node_id); + assert_eq!(cx.body_owner, closure_def_id); + assert!(cx.upvar_indices.contains_key(&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> { - let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); +fn convert_var( + cx: &mut Cx<'_, '_, 'tcx>, + expr: &'tcx hir::Expr, + var_hir_id: hir::HirId, +) -> ExprKind<'tcx> { + let upvar_index = cx.upvar_indices.get(&var_hir_id).cloned(); - match res { - Res::Local(id) => ExprKind::VarRef { id }, + 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); - Res::Upvar(var_hir_id, closure_expr_id) => { - let index = cx.upvar_indices[&var_hir_id]; + match upvar_index { + None => ExprKind::VarRef { id: var_hir_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), @@ -1062,15 +1074,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) => { @@ -1089,8 +1097,6 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } } - - _ => span_bug!(expr.span, "type of & not region"), } } @@ -1190,15 +1196,16 @@ fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let upvar_capture = cx.tables().upvar_capture(upvar_id); let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); let var_ty = cx.tables().node_type(upvar.var_id); - let upvar_res = upvar.parent.map_or( - Res::Local(upvar.var_id), - |closure_node_id| Res::Upvar(upvar.var_id, closure_node_id), - ); + if upvar.has_parent { + let closure_def_id = upvar_id.closure_expr_id.to_def_id(); + assert_eq!(cx.body_owner, cx.tcx.parent(closure_def_id).unwrap()); + } + assert_eq!(upvar.has_parent, cx.upvar_indices.contains_key(&upvar.var_id)); let captured_var = Expr { temp_lifetime, ty: var_ty, span: closure_expr.span, - kind: convert_var(cx, closure_expr, upvar_res), + kind: convert_var(cx, closure_expr, upvar.var_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 74382bb1fe25d..251bc24bbd239 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -39,6 +39,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, @@ -97,6 +100,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { region_scope_tree: tcx.region_scope_tree(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_resolve/lib.rs b/src/librustc_resolve/lib.rs index 490d5ae83b8b1..790c435663087 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4051,9 +4051,9 @@ impl<'a> Resolver<'a> { // Nothing to do. Continue. } ClosureRibKind(function_id) => { - let parent = match res { - Res::Upvar(_, closure) => Some(closure), - _ => None, + let has_parent = match res { + Res::Upvar(..) => true, + _ => false, }; let seen = self.upvars_seen @@ -4071,7 +4071,7 @@ impl<'a> Resolver<'a> { if record_used { vec.push(Upvar { var_id, - parent, + has_parent, span, }); seen.insert(var_id); From 961fe5479f3e981aafb4f8f957faea52ec295365 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 14 May 2019 19:42:57 +0300 Subject: [PATCH 04/11] rustc: use indexmap instead of a plain vector for upvars. --- Cargo.lock | 9 +++ src/librustc/hir/mod.rs | 18 +---- src/librustc/middle/expr_use_visitor.rs | 12 ++-- src/librustc/middle/liveness.rs | 4 +- src/librustc/mir/mod.rs | 8 +-- src/librustc/query/mod.rs | 2 +- src/librustc/ty/context.rs | 13 ++-- src/librustc/ty/mod.rs | 3 +- src/librustc/ty/print/pretty.rs | 12 ++-- src/librustc/ty/query/mod.rs | 2 +- src/librustc_data_structures/Cargo.toml | 1 + src/librustc_data_structures/fx.rs | 5 ++ src/librustc_data_structures/stable_hasher.rs | 31 +++++++++ .../borrow_check/error_reporting.rs | 9 +-- src/librustc_mir/borrow_check/mod.rs | 2 +- src/librustc_mir/build/mod.rs | 5 +- src/librustc_mir/hair/cx/expr.rs | 20 ++++-- src/librustc_mir/hair/cx/mod.rs | 13 ---- src/librustc_mir/interpret/validity.rs | 3 +- src/librustc_resolve/Cargo.toml | 1 + src/librustc_resolve/lib.rs | 30 +++----- src/librustc_typeck/check/upvar.rs | 18 ++--- src/librustc_typeck/check/writeback.rs | 21 ++---- src/libserialize/Cargo.toml | 1 + src/libserialize/collection_impls.rs | 69 +++++++++++++++++++ src/tools/tidy/src/deps.rs | 1 + 26 files changed, 198 insertions(+), 115 deletions(-) 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/hir/mod.rs b/src/librustc/hir/mod.rs index 66535079e1ddb..7ec24647b4d8c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -30,6 +30,7 @@ use syntax::util::parser::ExprPrecedence; use crate::ty::AdtKind; use crate::ty::query::Providers; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_data_structures::thin_vec::ThinVec; use rustc_macros::HashStable; @@ -2493,10 +2494,7 @@ impl ForeignItemKind { /// A variable captured by a closure. #[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] -pub struct Upvar { - /// The variable being captured. - pub var_id: Id, - +pub struct Upvar { /// Whether this is not a direct capture (comes from parent closure). pub has_parent: bool, @@ -2504,17 +2502,7 @@ pub struct Upvar { pub span: Span } -impl Upvar { - pub fn map_id(self, map: impl FnOnce(Id) -> R) -> Upvar { - Upvar { - var_id: map(self.var_id), - has_parent: self.has_parent, - span: self.span, - } - } -} - -pub type UpvarMap = NodeMap>>; +pub type UpvarMap = NodeMap>; pub type CaptureModeMap = NodeMap; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 034f60875e7bf..11faaa4df18ed 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -924,14 +924,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() { + for (&var_id, upvar) in upvars.iter() { let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: upvar.var_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, + var_id, upvar)); match upvar_capture { ty::UpvarCapture::ByValue => { @@ -957,6 +958,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn cat_captured_var(&mut self, closure_hir_id: hir::HirId, closure_span: Span, + var_id: hir::HirId, upvar: &hir::Upvar) -> mc::McResult> { // Create the cmt for the variable being borrowed, from the @@ -965,11 +967,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let closure_def_id = self.tcx().hir().local_def_id_from_hir_id(closure_hir_id); let parent_def_id = self.tcx().parent(closure_def_id).unwrap(); assert!(self.tcx().is_closure(parent_def_id)); - let var_nid = self.tcx().hir().hir_to_node_id(upvar.var_id); + let var_nid = self.tcx().hir().hir_to_node_id(var_id); self.mc.cat_upvar(closure_hir_id, closure_span, var_nid, parent_def_id) } else { - let var_ty = self.mc.node_ty(upvar.var_id)?; - self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(upvar.var_id)) + 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 22930cc198946..873c2dd480569 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -485,10 +485,10 @@ 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| { + call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| { if !upvar.has_parent { let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); - Some(CaptureInfo { ln: upvar_ln, var_hid: upvar.var_id }) + Some(CaptureInfo { ln: upvar_ln, var_hid: var_id }) } else { None } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 1f29b370d2729..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..f8f869b984295 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -54,6 +54,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableHasher, StableHasherResult, StableVec}; use arena::SyncDroplessArena; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal}; use std::any::Any; @@ -1065,7 +1066,7 @@ pub struct GlobalCtxt<'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>, + upvars: FxHashMap>, maybe_unused_trait_imports: FxHashSet, maybe_unused_extern_crates: Vec<(DefId, Span)>, @@ -1297,11 +1298,11 @@ 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)) + upvars: resolutions.upvars.into_iter().map(|(k, upvars)| { + let upvars: FxIndexMap<_, _> = upvars.into_iter().map(|(var_id, upvar)| { + (hir.node_to_hir_id(var_id), upvar) }).collect(); - (hir.local_def_id(k), vars) + (hir.local_def_id(k), upvars) }).collect(), maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports @@ -3023,7 +3024,7 @@ 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.upvars = |tcx, id| tcx.gcx.upvars.get(&id); 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..c0f582d5d132b 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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}; @@ -808,7 +809,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 03c7226c1afe5..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_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_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 74601cc389184..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 4d32f1eec44fc..dc9451fefb802 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, upvar), ty)| capture_upvar(cx, expr, var_hir_id, upvar, ty)) .collect(); ExprKind::Closure { closure_id: def_id, @@ -964,7 +964,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Res::Upvar(var_hir_id, closure_node_id) => { let closure_def_id = cx.tcx.hir().local_def_id(closure_node_id); assert_eq!(cx.body_owner, closure_def_id); - assert!(cx.upvar_indices.contains_key(&var_hir_id)); + assert!(cx.tables().upvar_list[&cx.body_owner].contains_key(&var_hir_id)); convert_var(cx, expr, var_hir_id) } @@ -978,7 +978,8 @@ fn convert_var( expr: &'tcx hir::Expr, var_hir_id: hir::HirId, ) -> ExprKind<'tcx> { - let upvar_index = cx.upvar_indices.get(&var_hir_id).cloned(); + 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); @@ -1186,26 +1187,31 @@ fn overloaded_place<'a, 'gcx, 'tcx>( fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_expr: &'tcx hir::Expr, + var_hir_id: hir::HirId, upvar: &hir::Upvar, upvar_ty: Ty<'tcx>) -> ExprRef<'tcx> { let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: upvar.var_id }, + 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(), }; let upvar_capture = cx.tables().upvar_capture(upvar_id); let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); - let var_ty = cx.tables().node_type(upvar.var_id); + let var_ty = cx.tables().node_type(var_hir_id); if upvar.has_parent { let closure_def_id = upvar_id.closure_expr_id.to_def_id(); assert_eq!(cx.body_owner, cx.tcx.parent(closure_def_id).unwrap()); } - assert_eq!(upvar.has_parent, cx.upvar_indices.contains_key(&upvar.var_id)); + assert_eq!( + upvar.has_parent, + cx.tables().upvar_list.get(&cx.body_owner) + .map_or(false, |upvars| upvars.contains_key(&var_hir_id)), + ); let captured_var = Expr { temp_lifetime, ty: var_ty, span: closure_expr.span, - kind: convert_var(cx, closure_expr, upvar.var_id), + 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 251bc24bbd239..f4a23a90dee92 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -5,7 +5,6 @@ use crate::hair::*; use crate::hair::util::UserAnnotatedTyHelpers; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::DefId; use rustc::hir::Node; @@ -50,9 +49,6 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { /// See field with the same name on `mir::Body`. control_flow_destroyed: Vec<(Span, String)>, - - /// Reverse map, from upvar variable `HirId`s to their indices. - upvar_indices: FxHashMap, } impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { @@ -83,14 +79,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { // Constants always need overflow checks. check_overflow |= constness == hir::Constness::Const; - // Compute reverse mapping, of uvpars to their indices. - let mut upvar_indices = FxHashMap::default(); - if let Some(upvars) = tables.upvar_list.get(&src_def_id) { - upvar_indices.extend( - upvars.iter().enumerate().map(|(i, upvar_id)| (upvar_id.var_path.hir_id, i)), - ); - } - Cx { tcx, infcx, @@ -104,7 +92,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { body_owner_kind, check_overflow, control_flow_destroyed: Vec::new(), - upvar_indices, } } 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_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 790c435663087..beb3698947462 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1669,7 +1669,6 @@ pub struct Resolver<'a> { label_res_map: NodeMap, pub upvars: UpvarMap, - upvars_seen: NodeMap, pub export_map: ExportMap, pub trait_map: TraitMap, @@ -2033,7 +2032,6 @@ impl<'a> Resolver<'a> { 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, @@ -4055,26 +4053,18 @@ impl<'a> Resolver<'a> { Res::Upvar(..) => true, _ => false, }; - - let seen = self.upvars_seen - .entry(function_id) - .or_default(); - if seen.contains(&var_id) { - res = Res::Upvar(var_id, function_id); - continue; - } - let vec = self.upvars - .entry(function_id) - .or_default(); res = Res::Upvar(var_id, function_id); - if record_used { - vec.push(Upvar { - var_id, - has_parent, - span, - }); - seen.insert(var_id); + match self.upvars.entry(function_id).or_default().entry(var_id) { + indexmap::map::Entry::Occupied(_) => continue, + indexmap::map::Entry::Vacant(entry) => { + if record_used { + entry.insert(Upvar { + has_parent, + span, + }); + } + } } } ItemRibKind | FnItemRibKind | AssocItemRibKind => { diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index a4f9ede37c9db..8ceca20eb07ca 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, @@ -249,17 +251,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.upvars(closure_def_id).iter().flat_map(|upvars| { upvars .iter() - .map(|upvar| { - let upvar_ty = self.node_ty(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: upvar.var_id }, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; let capture = self.tables.borrow().upvar_capture(upvar_id); debug!( "var_id={:?} upvar_ty={:?} capture={:?}", - upvar.var_id, upvar_ty, capture + var_hir_id, upvar_ty, capture ); match capture { 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/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"), From 1768030791649c4baaa3413512061e20377936ad Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 22 May 2019 17:02:40 +0300 Subject: [PATCH 05/11] rustc: track the body owner DefId in MC and EUV. --- src/librustc/middle/expr_use_visitor.rs | 15 +++++++++++---- src/librustc/middle/mem_categorization.rs | 13 ++++++++++--- src/librustc_borrowck/borrowck/check_loans.rs | 1 + .../borrowck/gather_loans/mod.rs | 1 + src/librustc_mir/hair/pattern/check_match.rs | 3 +++ src/librustc_passes/rvalue_promotion.rs | 11 +++++++++-- src/librustc_typeck/check/regionck.rs | 6 ++++++ src/librustc_typeck/check/upvar.rs | 2 ++ 8 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 11faaa4df18ed..2d94874105a48 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, } @@ -965,10 +973,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // caller's perspective if upvar.has_parent { let closure_def_id = self.tcx().hir().local_def_id_from_hir_id(closure_hir_id); - let parent_def_id = self.tcx().parent(closure_def_id).unwrap(); - assert!(self.tcx().is_closure(parent_def_id)); + assert_eq!(self.mc.body_owner, self.tcx().parent(closure_def_id).unwrap()); let var_nid = self.tcx().hir().hir_to_node_id(var_id); - self.mc.cat_upvar(closure_hir_id, closure_span, var_nid, parent_def_id) + self.mc.cat_upvar(closure_hir_id, closure_span, var_nid) } else { 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/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7ce729bb71544..2022169dbf1b9 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -288,6 +288,7 @@ 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 region_scope_tree: &'a region::ScopeTree, pub tables: &'a ty::TypeckTables<'tcx>, rvalue_promotable_map: Option<&'tcx ItemLocalSet>, @@ -398,12 +399,14 @@ 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, region_scope_tree, tables, rvalue_promotable_map, @@ -423,6 +426,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 +440,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { MemCategorizationContext { tcx, + body_owner, region_scope_tree, tables, rvalue_promotable_map, @@ -739,8 +744,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Res::Upvar(var_id, closure_node_id) => { let var_nid = self.tcx.hir().hir_to_node_id(var_id); - let closure_expr_def_id = self.tcx.hir().local_def_id(closure_node_id); - self.cat_upvar(hir_id, span, var_nid, closure_expr_def_id) + let closure_def_id = self.tcx.hir().local_def_id(closure_node_id); + assert_eq!(self.body_owner, closure_def_id); + + self.cat_upvar(hir_id, span, var_nid) } Res::Local(vid) => { @@ -766,7 +773,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir_id: hir::HirId, span: Span, var_id: ast::NodeId, - closure_expr_def_id: DefId, ) -> 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 @@ -791,6 +797,7 @@ 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), ); 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_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_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_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 8ceca20eb07ca..82c173a6f7a57 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -167,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, @@ -178,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(), From b13d0407d48e3380ec29d6c37fda0ecc488c79c2 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 20 May 2019 21:51:55 +0300 Subject: [PATCH 06/11] rustc: remove closure ID from Res::Upvar. --- src/librustc/hir/def.rs | 5 ++--- src/librustc/middle/expr_use_visitor.rs | 14 ++++++-------- src/librustc/middle/mem_categorization.rs | 21 ++++++++++++--------- src/librustc_mir/hair/cx/expr.rs | 14 +++++++++----- src/librustc_resolve/lib.rs | 2 +- 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index f342b230a7176..2486f21ce4239 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -139,8 +139,7 @@ pub enum Res { // Value namespace SelfCtor(DefId /* impl */), // `DefId` refers to the impl Local(Id), - Upvar(Id, // `HirId` of closed over local - ast::NodeId), // expr node that creates the closure + Upvar(Id), // Macro namespace NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]` @@ -396,7 +395,7 @@ impl Res { Res::SelfCtor(id) => Res::SelfCtor(id), Res::PrimTy(id) => Res::PrimTy(id), Res::Local(id) => Res::Local(map(id)), - Res::Upvar(id, closure) => Res::Upvar(map(id), closure), + Res::Upvar(id) => Res::Upvar(map(id)), 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/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 2d94874105a48..36b6ddf3432f8 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -971,15 +971,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { -> mc::McResult> { // Create the cmt for the variable being borrowed, from the // caller's perspective - if upvar.has_parent { - let closure_def_id = self.tcx().hir().local_def_id_from_hir_id(closure_hir_id); - assert_eq!(self.mc.body_owner, self.tcx().parent(closure_def_id).unwrap()); - let var_nid = self.tcx().hir().hir_to_node_id(var_id); - self.mc.cat_upvar(closure_hir_id, closure_span, var_nid) + let res = if upvar.has_parent { + Res::Upvar(var_id) } else { - let var_ty = self.mc.node_ty(var_id)?; - self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id)) - } + Res::Local(var_id) + }; + let var_ty = self.mc.node_ty(var_id)?; + self.mc.cat_res(closure_hir_id, closure_span, var_ty, res) } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 2022169dbf1b9..17ec2de2f3abf 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; @@ -289,6 +290,7 @@ impl HirNode for hir::Pat { 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>, @@ -407,6 +409,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> { MemCategorizationContext { tcx, body_owner, + upvars: tcx.upvars(body_owner), region_scope_tree, tables, rvalue_promotable_map, @@ -441,6 +444,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { MemCategorizationContext { tcx, body_owner, + upvars: tcx.upvars(body_owner), region_scope_tree, tables, rvalue_promotable_map, @@ -742,21 +746,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }) } - Res::Upvar(var_id, closure_node_id) => { + Res::Upvar(var_id) => { + assert!(self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id))); let var_nid = self.tcx.hir().hir_to_node_id(var_id); - let closure_def_id = self.tcx.hir().local_def_id(closure_node_id); - assert_eq!(self.body_owner, closure_def_id); - self.cat_upvar(hir_id, span, var_nid) } - Res::Local(vid) => { - let vnid = self.tcx.hir().hir_to_node_id(vid); + Res::Local(var_id) => { + assert!(!self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id))); + let var_nid = self.tcx.hir().hir_to_node_id(var_id); Ok(cmt_ { hir_id, span, - cat: Categorization::Local(vid), - mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vnid), + cat: Categorization::Local(var_id), + mutbl: MutabilityCategory::from_local(self.tcx, self.tables, var_nid), ty: expr_ty, note: NoteNone }) @@ -768,7 +771,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Categorize an upvar, complete with invisible derefs of closure // environment and upvar reference as appropriate. - pub fn cat_upvar( + fn cat_upvar( &self, hir_id: hir::HirId, span: Span, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index dc9451fefb802..cb110061c0b87 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -960,11 +960,15 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Res::Def(DefKind::Static, id) => ExprKind::StaticRef { id }, - Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id), - Res::Upvar(var_hir_id, closure_node_id) => { - let closure_def_id = cx.tcx.hir().local_def_id(closure_node_id); - assert_eq!(cx.body_owner, closure_def_id); - assert!(cx.tables().upvar_list[&cx.body_owner].contains_key(&var_hir_id)); + Res::Local(var_hir_id) => { + assert!(!cx.tables().upvar_list.get(&cx.body_owner) + .map_or(false, |upvars| upvars.contains_key(&var_hir_id))); + + convert_var(cx, expr, var_hir_id) + } + Res::Upvar(var_hir_id) => { + assert!(cx.tables().upvar_list.get(&cx.body_owner) + .map_or(false, |upvars| upvars.contains_key(&var_hir_id))); convert_var(cx, expr, var_hir_id) } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index beb3698947462..d5c85bde52ddd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4053,7 +4053,7 @@ impl<'a> Resolver<'a> { Res::Upvar(..) => true, _ => false, }; - res = Res::Upvar(var_id, function_id); + res = Res::Upvar(var_id); match self.upvars.entry(function_id).or_default().entry(var_id) { indexmap::map::Entry::Occupied(_) => continue, From a0ca2a2deb8f46fab5add2e35d51a64e712890fb Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 27 May 2019 20:33:59 +0300 Subject: [PATCH 07/11] rustc: track the body owner in liveness. --- src/librustc/middle/liveness.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 873c2dd480569..c128d4ab8bc3a 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -99,7 +99,7 @@ use self::VarKind::*; use crate::hir::def::*; use crate::hir::Node; -use crate::ty::{self, TyCtxt}; +use crate::ty::{self, DefIdTree, TyCtxt}; use crate::ty::query::Providers; use crate::lint; use crate::util::nodemap::{HirIdMap, HirIdSet}; @@ -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 { @@ -485,8 +491,15 @@ 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) { + let parent_upvars = ir.tcx.upvars(ir.body_owner); call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| { - if !upvar.has_parent { + if upvar.has_parent { + assert_eq!(ir.body_owner, ir.tcx.parent(closure_def_id).unwrap()); + } + let has_parent = parent_upvars + .map_or(false, |upvars| upvars.contains_key(&var_id)); + assert_eq!(upvar.has_parent, has_parent); + if !has_parent { let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); Some(CaptureInfo { ln: upvar_ln, var_hid: var_id }) } else { @@ -495,8 +508,10 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { })); } 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: From 340b91e2ffdd884be5c260144305b518e5a22a9b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 28 May 2019 17:12:24 +0300 Subject: [PATCH 08/11] rustc: remove `has_parent` from `hir::Upvar`. --- src/librustc/hir/mod.rs | 3 --- src/librustc/middle/expr_use_visitor.rs | 8 +++----- src/librustc/middle/liveness.rs | 6 +----- src/librustc_mir/hair/cx/expr.rs | 14 ++------------ src/librustc_resolve/lib.rs | 10 +--------- 5 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 7ec24647b4d8c..38ef4d3dbd626 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2495,9 +2495,6 @@ impl ForeignItemKind { /// A variable captured by a closure. #[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] pub struct Upvar { - /// Whether this is not a direct capture (comes from parent closure). - pub has_parent: bool, - // First span where it is accessed (there can be multiple). pub span: Span } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 36b6ddf3432f8..477f5ceff6198 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -940,8 +940,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { 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, - var_id, - upvar)); + var_id)); match upvar_capture { ty::UpvarCapture::ByValue => { let mode = copy_or_move(&self.mc, @@ -966,12 +965,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn cat_captured_var(&mut self, closure_hir_id: hir::HirId, closure_span: Span, - var_id: hir::HirId, - upvar: &hir::Upvar) + var_id: hir::HirId) -> mc::McResult> { // Create the cmt for the variable being borrowed, from the // caller's perspective - let res = if upvar.has_parent { + let res = if self.mc.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) { Res::Upvar(var_id) } else { Res::Local(var_id) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index c128d4ab8bc3a..be2f533ced0a8 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -99,7 +99,7 @@ use self::VarKind::*; use crate::hir::def::*; use crate::hir::Node; -use crate::ty::{self, DefIdTree, TyCtxt}; +use crate::ty::{self, TyCtxt}; use crate::ty::query::Providers; use crate::lint; use crate::util::nodemap::{HirIdMap, HirIdSet}; @@ -493,12 +493,8 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { if let Some(upvars) = ir.tcx.upvars(closure_def_id) { let parent_upvars = ir.tcx.upvars(ir.body_owner); call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| { - if upvar.has_parent { - assert_eq!(ir.body_owner, ir.tcx.parent(closure_def_id).unwrap()); - } let has_parent = parent_upvars .map_or(false, |upvars| upvars.contains_key(&var_id)); - assert_eq!(upvar.has_parent, has_parent); if !has_parent { let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); Some(CaptureInfo { ln: upvar_ln, var_hid: var_id }) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index cb110061c0b87..181313f94361a 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -6,7 +6,7 @@ use crate::hair::util::UserAnnotatedTyHelpers; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue}; -use rustc::ty::{self, AdtKind, DefIdTree, Ty}; +use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability, PointerCast}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::hir; @@ -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(|((&var_hir_id, upvar), ty)| capture_upvar(cx, expr, var_hir_id, upvar, ty)) + .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty)) .collect(); ExprKind::Closure { closure_id: def_id, @@ -1192,7 +1192,6 @@ fn overloaded_place<'a, 'gcx, 'tcx>( fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_expr: &'tcx hir::Expr, var_hir_id: hir::HirId, - upvar: &hir::Upvar, upvar_ty: Ty<'tcx>) -> ExprRef<'tcx> { let upvar_id = ty::UpvarId { @@ -1202,15 +1201,6 @@ fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let upvar_capture = cx.tables().upvar_capture(upvar_id); let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); let var_ty = cx.tables().node_type(var_hir_id); - if upvar.has_parent { - let closure_def_id = upvar_id.closure_expr_id.to_def_id(); - assert_eq!(cx.body_owner, cx.tcx.parent(closure_def_id).unwrap()); - } - assert_eq!( - upvar.has_parent, - cx.tables().upvar_list.get(&cx.body_owner) - .map_or(false, |upvars| upvars.contains_key(&var_hir_id)), - ); let captured_var = Expr { temp_lifetime, ty: var_ty, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d5c85bde52ddd..c8ec7367edccd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4049,20 +4049,12 @@ impl<'a> Resolver<'a> { // Nothing to do. Continue. } ClosureRibKind(function_id) => { - let has_parent = match res { - Res::Upvar(..) => true, - _ => false, - }; res = Res::Upvar(var_id); - match self.upvars.entry(function_id).or_default().entry(var_id) { indexmap::map::Entry::Occupied(_) => continue, indexmap::map::Entry::Vacant(entry) => { if record_used { - entry.insert(Upvar { - has_parent, - span, - }); + entry.insert(Upvar { span }); } } } From ed1bbbb5458b9ee2fbcf7a41b9aeb3203ebca807 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 28 May 2019 18:06:01 +0300 Subject: [PATCH 09/11] rustc: remove Res::Upvar. --- src/librustc/hir/def.rs | 4 --- src/librustc/hir/mod.rs | 1 - src/librustc/middle/dead.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 9 ++---- src/librustc/middle/liveness.rs | 33 ++++++++++++++------- src/librustc/middle/mem_categorization.rs | 27 ++++++++--------- src/librustc/middle/reachable.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 13 +-------- src/librustc_resolve/lib.rs | 35 +++++++++-------------- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/mod.rs | 15 ++++------ 12 files changed, 61 insertions(+), 84 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 2486f21ce4239..131a910bebb1a 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -139,7 +139,6 @@ pub enum Res { // Value namespace SelfCtor(DefId /* impl */), // `DefId` refers to the impl Local(Id), - Upvar(Id), // Macro namespace NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]` @@ -345,7 +344,6 @@ impl Res { Res::Def(_, id) => Some(id), Res::Local(..) | - Res::Upvar(..) | Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) | @@ -372,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(), @@ -395,7 +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) => Res::Upvar(map(id)), 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/mod.rs b/src/librustc/hir/mod.rs index 38ef4d3dbd626..fa62ab15a9762 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1409,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, 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 477f5ceff6198..34cea2d75eaa8 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -968,14 +968,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { var_id: hir::HirId) -> mc::McResult> { // Create the cmt for the variable being borrowed, from the - // caller's perspective - let res = if self.mc.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) { - Res::Upvar(var_id) - } else { - Res::Local(var_id) - }; + // 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) + 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 be2f533ced0a8..45b4fb5605695 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -474,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); } @@ -1338,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 } @@ -1531,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 17ec2de2f3abf..7011948148d84 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -746,23 +746,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }) } - Res::Upvar(var_id) => { - assert!(self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id))); - let var_nid = self.tcx.hir().hir_to_node_id(var_id); - self.cat_upvar(hir_id, span, var_nid) - } - Res::Local(var_id) => { - assert!(!self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id))); let var_nid = self.tcx.hir().hir_to_node_id(var_id); - 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 - }) + 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) 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/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 181313f94361a..5a6b6a7483052 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -960,18 +960,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Res::Def(DefKind::Static, id) => ExprKind::StaticRef { id }, - Res::Local(var_hir_id) => { - assert!(!cx.tables().upvar_list.get(&cx.body_owner) - .map_or(false, |upvars| upvars.contains_key(&var_hir_id))); - - convert_var(cx, expr, var_hir_id) - } - Res::Upvar(var_hir_id) => { - assert!(cx.tables().upvar_list.get(&cx.body_owner) - .map_or(false, |upvars| upvars.contains_key(&var_hir_id))); - - convert_var(cx, expr, var_hir_id) - } + Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id), _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res), } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c8ec7367edccd..ff54643989ba0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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, _) @@ -2204,7 +2203,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), )); } @@ -4006,14 +4005,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), potentially recording closure upvars. + 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. @@ -4035,9 +4036,6 @@ impl<'a> Resolver<'a> { } match res { - Res::Upvar(..) => { - span_bug!(span, "unexpected {:?} in bindings", res) - } Res::Local(var_id) => { use ResolutionError::*; let mut res_err = None; @@ -4049,14 +4047,9 @@ impl<'a> Resolver<'a> { // Nothing to do. Continue. } ClosureRibKind(function_id) => { - res = Res::Upvar(var_id); - match self.upvars.entry(function_id).or_default().entry(var_id) { - indexmap::map::Entry::Occupied(_) => continue, - indexmap::map::Entry::Vacant(entry) => { - if record_used { - entry.insert(Upvar { span }); - } - } + if record_used { + self.upvars.entry(function_id).or_default() + .entry(var_id).or_insert(Upvar { span }); } } ItemRibKind | FnItemRibKind | AssocItemRibKind => { 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 { From 648b4d884d663b9afad7188120e13fc285d61516 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 28 May 2019 23:50:30 +0300 Subject: [PATCH 10/11] rustc_resolve: never push `ClosureRibKind` to `label_ribs`. --- src/librustc_resolve/lib.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ff54643989ba0..7ab3de0475e73 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -870,7 +870,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { self.ribs[ValueNS].push(Rib::new(rib_kind)); // Create a label rib for the function. - self.label_ribs.push(Rib::new(rib_kind)); + match rib_kind { + ClosureRibKind(_) => {} + _ => self.label_ribs.push(Rib::new(rib_kind)), + } // Add each argument to the rib. let mut bindings_list = FxHashMap::default(); @@ -900,7 +903,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { 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 { @@ -927,13 +929,17 @@ 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(); + match rib_kind { + ClosureRibKind(_) => {} + _ => { + self.label_ribs.pop(); + } + } self.ribs[ValueNS].pop(); } @@ -2500,6 +2506,9 @@ impl<'a> Resolver<'a> { for rib in self.label_ribs.iter().rev() { match rib.kind { NormalRibKind => {} + ClosureRibKind(_) => { + span_bug!(ident.span, "rustc_resolve: `ClosureRibKind` in `label_ribs`"); + } // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. MacroDefinition(def) => { @@ -4465,9 +4474,7 @@ impl<'a> Resolver<'a> { 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 @@ -4479,7 +4486,6 @@ impl<'a> Resolver<'a> { ) => { let rib_kind = ClosureRibKind(expr.id); 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 { @@ -4493,16 +4499,13 @@ impl<'a> Resolver<'a> { { 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(); } _ => { From f7a4c9d7b55950c6b8451b42f203df2c009fc653 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 28 May 2019 23:31:01 +0300 Subject: [PATCH 11/11] rustc: collect upvars from HIR, instead of during name resolution. --- src/librustc/arena.rs | 1 + src/librustc/hir/map/mod.rs | 18 +-- src/librustc/hir/mod.rs | 8 +- src/librustc/hir/upvars.rs | 104 ++++++++++++++++++ src/librustc/ty/context.rs | 13 --- src/librustc/ty/mod.rs | 3 +- src/librustc_interface/passes.rs | 2 - src/librustc_resolve/lib.rs | 69 +++--------- .../borrowck-closures-use-after-free.stderr | 2 +- src/test/ui/issues/issue-11192.stderr | 2 +- .../escape-upvar-nested.stderr | 12 +- .../escape-upvar-ref.stderr | 6 +- 12 files changed, 143 insertions(+), 97 deletions(-) create mode 100644 src/librustc/hir/upvars.rs 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/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 fa62ab15a9762..f7daa7a94551f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -30,7 +30,6 @@ use syntax::util::parser::ExprPrecedence; use crate::ty::AdtKind; use crate::ty::query::Providers; -use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_data_structures::thin_vec::ThinVec; use rustc_macros::HashStable; @@ -64,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 @@ -2498,8 +2498,6 @@ pub struct Upvar { pub span: Span } -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 @@ -2518,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/ty/context.rs b/src/librustc/ty/context.rs index f8f869b984295..b2d080a4f965a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -54,7 +54,6 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableHasher, StableHasherResult, StableVec}; use arena::SyncDroplessArena; -use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal}; use std::any::Any; @@ -1063,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 @@ -1298,12 +1292,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }).collect(); (k, exports) }).collect(), - upvars: resolutions.upvars.into_iter().map(|(k, upvars)| { - let upvars: FxIndexMap<_, _> = upvars.into_iter().map(|(var_id, upvar)| { - (hir.node_to_hir_id(var_id), upvar) - }).collect(); - (hir.local_def_id(k), upvars) - }).collect(), maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports .into_iter() @@ -3024,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); 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 c0f582d5d132b..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}; @@ -123,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)>, 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_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7ab3de0475e73..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}; @@ -852,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 { @@ -863,17 +863,14 @@ 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. self.ribs[ValueNS].push(Rib::new(rib_kind)); // Create a label rib for the function. - match rib_kind { - ClosureRibKind(_) => {} - _ => self.label_ribs.push(Rib::new(rib_kind)), - } + self.label_ribs.push(Rib::new(rib_kind)); // Add each argument to the rib. let mut bindings_list = FxHashMap::default(); @@ -900,11 +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)); - } - match function_kind { FnKind::ItemFn(.., body) | FnKind::Method(.., body) => { if let IsAsync::Async { ref arguments, .. } = asyncness { @@ -927,19 +919,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { } }; - // Leave the body of the async closure - if asyncness.is_async() { - self.ribs[ValueNS].pop(); - } - debug!("(resolving function) leaving function"); - match rib_kind { - ClosureRibKind(_) => {} - _ => { - self.label_ribs.pop(); - } - } + self.label_ribs.pop(); self.ribs[ValueNS].pop(); } @@ -1023,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 @@ -1673,7 +1651,6 @@ pub struct Resolver<'a> { /// Resolutions for labels (node IDs of their corresponding blocks or loops). label_res_map: NodeMap, - pub upvars: UpvarMap, pub export_map: ExportMap, pub trait_map: TraitMap, @@ -2036,7 +2013,6 @@ impl<'a> Resolver<'a> { partial_res_map: Default::default(), import_res_map: Default::default(), label_res_map: Default::default(), - upvars: Default::default(), export_map: FxHashMap::default(), trait_map: Default::default(), module_map, @@ -2506,9 +2482,6 @@ impl<'a> Resolver<'a> { for rib in self.label_ribs.iter().rev() { match rib.kind { NormalRibKind => {} - ClosureRibKind(_) => { - span_bug!(ident.span, "rustc_resolve: `ClosureRibKind` in `label_ribs`"); - } // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. MacroDefinition(def) => { @@ -4014,7 +3987,7 @@ impl<'a> Resolver<'a> { diag); } - // Validate a local resolution (from ribs), potentially recording closure upvars. + // Validate a local resolution (from ribs). fn validate_res_from_ribs( &mut self, ns: Namespace, @@ -4045,7 +4018,7 @@ impl<'a> Resolver<'a> { } match res { - Res::Local(var_id) => { + Res::Local(_) => { use ResolutionError::*; let mut res_err = None; @@ -4055,12 +4028,6 @@ impl<'a> Resolver<'a> { ForwardTyParamBanRibKind | TyParamAsConstParamTy => { // Nothing to do. Continue. } - ClosureRibKind(function_id) => { - if record_used { - self.upvars.entry(function_id).or_default() - .entry(var_id).or_insert(Upvar { span }); - } - } ItemRibKind | FnItemRibKind | AssocItemRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we @@ -4090,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. @@ -4470,21 +4437,14 @@ 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.visit_block(&block); - 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)); // Resolve arguments: let mut bindings_list = FxHashMap::default(); @@ -4497,14 +4457,11 @@ impl<'a> Resolver<'a> { // Now resolve the inner closure { - let rib_kind = ClosureRibKind(inner_closure_id); - self.ribs[ValueNS].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.ribs[ValueNS].pop(); } self.ribs[ValueNS].pop(); } 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