Auto merge of #61276 - eddyb:kill-res-upvar, r=petrochenkov
rustc: remove Res::Upvar. By keeping track of the current "`body_owner`" (the `DefId` of the current fn/closure/const/etc.) in several passes, `Res::Upvar` and `hir::Upvar` don't need to contain contextual information about the closure. By leveraging [`indexmap`](https://docs.rs/indexmap), the list of upvars for a given closure can now also be queried, to check whether a local variable is a closure capture, and so `Res::Upvar` can be merged with `Res::Local`. And finally, the `tcx.upvars(...)` query now collects upvars from HIR, without relying on `rustc_resolve`. r? @petrochenkov cc @varkor @davidtwco
This commit is contained in:
commit
4c7bb8b0d9
46 changed files with 458 additions and 292 deletions
|
@ -1183,6 +1183,11 @@ dependencies = [
|
||||||
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "installer"
|
name = "installer"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -2719,6 +2724,7 @@ dependencies = [
|
||||||
"cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"graphviz 0.0.0",
|
"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)",
|
"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)",
|
"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)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -2970,6 +2976,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arena 0.0.0",
|
"arena 0.0.0",
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc 0.0.0",
|
"rustc 0.0.0",
|
||||||
"rustc_data_structures 0.0.0",
|
"rustc_data_structures 0.0.0",
|
||||||
|
@ -3236,6 +3243,7 @@ dependencies = [
|
||||||
name = "serialize"
|
name = "serialize"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
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)",
|
"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 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 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 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 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 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"
|
"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
|
||||||
|
|
|
@ -109,6 +109,7 @@ macro_rules! arena_types {
|
||||||
>,
|
>,
|
||||||
[few] crate_variances: rustc::ty::CrateVariancesMap<'tcx>,
|
[few] crate_variances: rustc::ty::CrateVariancesMap<'tcx>,
|
||||||
[few] inferred_outlives_crate: rustc::ty::CratePredicatesMap<'tcx>,
|
[few] inferred_outlives_crate: rustc::ty::CratePredicatesMap<'tcx>,
|
||||||
|
[] upvars: rustc_data_structures::fx::FxIndexMap<rustc::hir::HirId, rustc::hir::Upvar>,
|
||||||
], $tcx);
|
], $tcx);
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,9 +139,6 @@ pub enum Res<Id = hir::HirId> {
|
||||||
// Value namespace
|
// Value namespace
|
||||||
SelfCtor(DefId /* impl */), // `DefId` refers to the impl
|
SelfCtor(DefId /* impl */), // `DefId` refers to the impl
|
||||||
Local(Id),
|
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
|
// Macro namespace
|
||||||
NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]`
|
NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]`
|
||||||
|
@ -347,7 +344,6 @@ impl<Id> Res<Id> {
|
||||||
Res::Def(_, id) => Some(id),
|
Res::Def(_, id) => Some(id),
|
||||||
|
|
||||||
Res::Local(..) |
|
Res::Local(..) |
|
||||||
Res::Upvar(..) |
|
|
||||||
Res::PrimTy(..) |
|
Res::PrimTy(..) |
|
||||||
Res::SelfTy(..) |
|
Res::SelfTy(..) |
|
||||||
Res::SelfCtor(..) |
|
Res::SelfCtor(..) |
|
||||||
|
@ -374,7 +370,6 @@ impl<Id> Res<Id> {
|
||||||
Res::SelfCtor(..) => "self constructor",
|
Res::SelfCtor(..) => "self constructor",
|
||||||
Res::PrimTy(..) => "builtin type",
|
Res::PrimTy(..) => "builtin type",
|
||||||
Res::Local(..) => "local variable",
|
Res::Local(..) => "local variable",
|
||||||
Res::Upvar(..) => "closure capture",
|
|
||||||
Res::SelfTy(..) => "self type",
|
Res::SelfTy(..) => "self type",
|
||||||
Res::ToolMod => "tool module",
|
Res::ToolMod => "tool module",
|
||||||
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
|
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
|
||||||
|
@ -397,11 +392,6 @@ impl<Id> Res<Id> {
|
||||||
Res::SelfCtor(id) => Res::SelfCtor(id),
|
Res::SelfCtor(id) => Res::SelfCtor(id),
|
||||||
Res::PrimTy(id) => Res::PrimTy(id),
|
Res::PrimTy(id) => Res::PrimTy(id),
|
||||||
Res::Local(id) => Res::Local(map(id)),
|
Res::Local(id) => Res::Local(map(id)),
|
||||||
Res::Upvar(id, index, closure) => Res::Upvar(
|
|
||||||
map(id),
|
|
||||||
index,
|
|
||||||
closure
|
|
||||||
),
|
|
||||||
Res::SelfTy(a, b) => Res::SelfTy(a, b),
|
Res::SelfTy(a, b) => Res::SelfTy(a, b),
|
||||||
Res::ToolMod => Res::ToolMod,
|
Res::ToolMod => Res::ToolMod,
|
||||||
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
|
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
|
||||||
|
|
|
@ -26,7 +26,7 @@ use crate::util::common::time;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::result::Result::Err;
|
use std::result::Result::Err;
|
||||||
use crate::ty::TyCtxt;
|
use crate::ty::query::Providers;
|
||||||
|
|
||||||
pub mod blocks;
|
pub mod blocks;
|
||||||
mod collector;
|
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<DefKind> {
|
pub fn provide(providers: &mut Providers<'_>) {
|
||||||
if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
|
providers.def_kind = |tcx, def_id| {
|
||||||
tcx.hir().def_kind(node_id)
|
if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
|
||||||
} else {
|
tcx.hir().def_kind(node_id)
|
||||||
bug!("Calling local def_kind query provider for upstream DefId: {:?}",
|
} else {
|
||||||
def_id)
|
bug!("Calling local def_kind query provider for upstream DefId: {:?}",
|
||||||
}
|
def_id)
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ pub mod lowering;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod pat_util;
|
pub mod pat_util;
|
||||||
pub mod print;
|
pub mod print;
|
||||||
|
pub mod upvars;
|
||||||
|
|
||||||
/// Uniquely identifies a node in the HIR of the current crate. It is
|
/// 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
|
/// composed of the `owner`, which is the `DefIndex` of the directly enclosing
|
||||||
|
@ -1408,7 +1409,6 @@ impl Expr {
|
||||||
ExprKind::Path(QPath::Resolved(_, ref path)) => {
|
ExprKind::Path(QPath::Resolved(_, ref path)) => {
|
||||||
match path.res {
|
match path.res {
|
||||||
Res::Local(..)
|
Res::Local(..)
|
||||||
| Res::Upvar(..)
|
|
||||||
| Res::Def(DefKind::Static, _)
|
| Res::Def(DefKind::Static, _)
|
||||||
| Res::Err => true,
|
| Res::Err => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -2493,32 +2493,11 @@ impl ForeignItemKind {
|
||||||
|
|
||||||
/// A variable captured by a closure.
|
/// A variable captured by a closure.
|
||||||
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
|
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
|
||||||
pub struct Upvar<Id = HirId> {
|
pub struct Upvar {
|
||||||
/// The variable being captured.
|
|
||||||
pub res: Res<Id>,
|
|
||||||
|
|
||||||
// First span where it is accessed (there can be multiple).
|
// First span where it is accessed (there can be multiple).
|
||||||
pub span: Span
|
pub span: Span
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Id: fmt::Debug + Copy> Upvar<Id> {
|
|
||||||
pub fn map_id<R>(self, map: impl FnMut(Id) -> R) -> Upvar<R> {
|
|
||||||
Upvar {
|
|
||||||
res: self.res.map_id(map),
|
|
||||||
span: self.span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn var_id(&self) -> Id {
|
|
||||||
match self.res {
|
|
||||||
Res::Local(id) | Res::Upvar(id, ..) => id,
|
|
||||||
_ => bug!("Upvar::var_id: bad res ({:?})", self.res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type UpvarMap = NodeMap<Vec<Upvar<ast::NodeId>>>;
|
|
||||||
|
|
||||||
pub type CaptureModeMap = NodeMap<CaptureClause>;
|
pub type CaptureModeMap = NodeMap<CaptureClause>;
|
||||||
|
|
||||||
// The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
|
// The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
|
||||||
|
@ -2537,10 +2516,10 @@ pub type TraitMap = NodeMap<Vec<TraitCandidate>>;
|
||||||
// imported.
|
// imported.
|
||||||
pub type GlobMap = NodeMap<FxHashSet<Name>>;
|
pub type GlobMap = NodeMap<FxHashSet<Name>>;
|
||||||
|
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers<'_>) {
|
pub fn provide(providers: &mut Providers<'_>) {
|
||||||
check_attr::provide(providers);
|
check_attr::provide(providers);
|
||||||
providers.def_kind = map::def_kind;
|
map::provide(providers);
|
||||||
|
upvars::provide(providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
|
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
|
||||||
|
|
104
src/librustc/hir/upvars.rs
Normal file
104
src/librustc/hir/upvars.rs
Normal file
|
@ -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<HirId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<HirId>,
|
||||||
|
upvars: FxIndexMap<HirId, hir::Upvar>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -78,7 +78,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
_ if self.in_pat => {},
|
_ if self.in_pat => {},
|
||||||
Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) |
|
Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) |
|
||||||
Res::Local(..) | Res::Upvar(..) => {}
|
Res::Local(..) => {}
|
||||||
Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => {
|
Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => {
|
||||||
let variant_id = self.tcx.parent(ctor_def_id).unwrap();
|
let variant_id = self.tcx.parent(ctor_def_id).unwrap();
|
||||||
let enum_id = self.tcx.parent(variant_id).unwrap();
|
let enum_id = self.tcx.parent(variant_id).unwrap();
|
||||||
|
|
|
@ -268,6 +268,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> {
|
||||||
/// See also `with_infer`, which is used *during* typeck.
|
/// See also `with_infer`, which is used *during* typeck.
|
||||||
pub fn new(delegate: &'a mut (dyn Delegate<'tcx>+'a),
|
pub fn new(delegate: &'a mut (dyn Delegate<'tcx>+'a),
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
body_owner: DefId,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
region_scope_tree: &'a region::ScopeTree,
|
region_scope_tree: &'a region::ScopeTree,
|
||||||
tables: &'a ty::TypeckTables<'tcx>,
|
tables: &'a ty::TypeckTables<'tcx>,
|
||||||
|
@ -276,6 +277,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> {
|
||||||
{
|
{
|
||||||
ExprUseVisitor {
|
ExprUseVisitor {
|
||||||
mc: mc::MemCategorizationContext::new(tcx,
|
mc: mc::MemCategorizationContext::new(tcx,
|
||||||
|
body_owner,
|
||||||
region_scope_tree,
|
region_scope_tree,
|
||||||
tables,
|
tables,
|
||||||
rvalue_promotable_map),
|
rvalue_promotable_map),
|
||||||
|
@ -288,13 +290,19 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> {
|
||||||
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
pub fn with_infer(delegate: &'a mut (dyn Delegate<'tcx>+'a),
|
pub fn with_infer(delegate: &'a mut (dyn Delegate<'tcx>+'a),
|
||||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
body_owner: DefId,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
region_scope_tree: &'a region::ScopeTree,
|
region_scope_tree: &'a region::ScopeTree,
|
||||||
tables: &'a ty::TypeckTables<'tcx>)
|
tables: &'a ty::TypeckTables<'tcx>)
|
||||||
-> Self
|
-> Self
|
||||||
{
|
{
|
||||||
ExprUseVisitor {
|
ExprUseVisitor {
|
||||||
mc: mc::MemCategorizationContext::with_infer(infcx, region_scope_tree, tables),
|
mc: mc::MemCategorizationContext::with_infer(
|
||||||
|
infcx,
|
||||||
|
body_owner,
|
||||||
|
region_scope_tree,
|
||||||
|
tables,
|
||||||
|
),
|
||||||
delegate,
|
delegate,
|
||||||
param_env,
|
param_env,
|
||||||
}
|
}
|
||||||
|
@ -924,16 +932,15 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let closure_def_id = self.tcx().hir().local_def_id_from_hir_id(closure_expr.hir_id);
|
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) {
|
if let Some(upvars) = self.tcx().upvars(closure_def_id) {
|
||||||
for upvar in upvars.iter() {
|
for (&var_id, upvar) in upvars.iter() {
|
||||||
let var_hir_id = upvar.var_id();
|
|
||||||
let upvar_id = ty::UpvarId {
|
let upvar_id = ty::UpvarId {
|
||||||
var_path: ty::UpvarPath { hir_id: var_hir_id },
|
var_path: ty::UpvarPath { hir_id: var_id },
|
||||||
closure_expr_id: closure_def_id.to_local(),
|
closure_expr_id: closure_def_id.to_local(),
|
||||||
};
|
};
|
||||||
let upvar_capture = self.mc.tables.upvar_capture(upvar_id);
|
let upvar_capture = self.mc.tables.upvar_capture(upvar_id);
|
||||||
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.hir_id,
|
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.hir_id,
|
||||||
fn_decl_span,
|
fn_decl_span,
|
||||||
upvar));
|
var_id));
|
||||||
match upvar_capture {
|
match upvar_capture {
|
||||||
ty::UpvarCapture::ByValue => {
|
ty::UpvarCapture::ByValue => {
|
||||||
let mode = copy_or_move(&self.mc,
|
let mode = copy_or_move(&self.mc,
|
||||||
|
@ -958,13 +965,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
fn cat_captured_var(&mut self,
|
fn cat_captured_var(&mut self,
|
||||||
closure_hir_id: hir::HirId,
|
closure_hir_id: hir::HirId,
|
||||||
closure_span: Span,
|
closure_span: Span,
|
||||||
upvar: &hir::Upvar)
|
var_id: hir::HirId)
|
||||||
-> mc::McResult<mc::cmt_<'tcx>> {
|
-> mc::McResult<mc::cmt_<'tcx>> {
|
||||||
// Create the cmt for the variable being borrowed, from the
|
// Create the cmt for the variable being borrowed, from the
|
||||||
// caller's perspective
|
// perspective of the creator (parent) of the closure.
|
||||||
let var_hir_id = upvar.var_id();
|
let var_ty = self.mc.node_ty(var_id)?;
|
||||||
let var_ty = self.mc.node_ty(var_hir_id)?;
|
self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id))
|
||||||
self.mc.cat_res(closure_hir_id, closure_span, var_ty, upvar.res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
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<'_>) {
|
pub fn provide(providers: &mut Providers<'_>) {
|
||||||
|
@ -255,6 +258,7 @@ enum VarKind {
|
||||||
|
|
||||||
struct IrMaps<'a, 'tcx: 'a> {
|
struct IrMaps<'a, 'tcx: 'a> {
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
body_owner: DefId,
|
||||||
num_live_nodes: usize,
|
num_live_nodes: usize,
|
||||||
num_vars: usize,
|
num_vars: usize,
|
||||||
live_node_map: HirIdMap<LiveNode>,
|
live_node_map: HirIdMap<LiveNode>,
|
||||||
|
@ -265,9 +269,10 @@ struct IrMaps<'a, 'tcx: 'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> IrMaps<'a, 'tcx> {
|
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 {
|
IrMaps {
|
||||||
tcx,
|
tcx,
|
||||||
|
body_owner,
|
||||||
num_live_nodes: 0,
|
num_live_nodes: 0,
|
||||||
num_vars: 0,
|
num_vars: 0,
|
||||||
live_node_map: HirIdMap::default(),
|
live_node_map: HirIdMap::default(),
|
||||||
|
@ -356,7 +361,8 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
|
||||||
debug!("visit_fn");
|
debug!("visit_fn");
|
||||||
|
|
||||||
// swap in a new set of IR maps for this function body:
|
// 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()]
|
// Don't run unused pass for #[derive()]
|
||||||
if let FnKind::Method(..) = fk {
|
if let FnKind::Method(..) = fk {
|
||||||
|
@ -468,8 +474,11 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
|
||||||
// live nodes required for uses or definitions of variables:
|
// live nodes required for uses or definitions of variables:
|
||||||
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
|
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
|
||||||
debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res);
|
debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res);
|
||||||
if let Res::Local(..) = path.res {
|
if let Res::Local(var_hir_id) = path.res {
|
||||||
ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
|
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);
|
intravisit::walk_expr(ir, expr);
|
||||||
}
|
}
|
||||||
|
@ -485,18 +494,23 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
|
||||||
let mut call_caps = Vec::new();
|
let mut call_caps = Vec::new();
|
||||||
let closure_def_id = ir.tcx.hir().local_def_id_from_hir_id(expr.hir_id);
|
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) {
|
if let Some(upvars) = ir.tcx.upvars(closure_def_id) {
|
||||||
call_caps.extend(upvars.iter().filter_map(|upvar| {
|
let parent_upvars = ir.tcx.upvars(ir.body_owner);
|
||||||
if let Res::Local(rv) = upvar.res {
|
call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| {
|
||||||
|
let has_parent = parent_upvars
|
||||||
|
.map_or(false, |upvars| upvars.contains_key(&var_id));
|
||||||
|
if !has_parent {
|
||||||
let upvar_ln = ir.add_live_node(UpvarNode(upvar.span));
|
let upvar_ln = ir.add_live_node(UpvarNode(upvar.span));
|
||||||
Some(CaptureInfo { ln: upvar_ln, var_hid: rv })
|
Some(CaptureInfo { ln: upvar_ln, var_hid: var_id })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
ir.set_captures(expr.hir_id, call_caps);
|
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);
|
intravisit::walk_expr(ir, expr);
|
||||||
|
ir.body_owner = old_body_owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
// live nodes required for interesting control flow:
|
// live nodes required for interesting control flow:
|
||||||
|
@ -1327,8 +1341,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
-> LiveNode {
|
-> LiveNode {
|
||||||
match path.res {
|
match path.res {
|
||||||
Res::Local(hid) => {
|
Res::Local(hid) => {
|
||||||
let nid = self.ir.tcx.hir().hir_to_node_id(hid);
|
let upvars = self.ir.tcx.upvars(self.ir.body_owner);
|
||||||
self.access_var(hir_id, nid, succ, acc, path.span)
|
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
|
_ => succ
|
||||||
}
|
}
|
||||||
|
@ -1520,13 +1539,16 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
|
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
|
||||||
if let Res::Local(var_hid) = path.res {
|
if let Res::Local(var_hid) = path.res {
|
||||||
// Assignment to an immutable variable or argument: only legal
|
let upvars = self.ir.tcx.upvars(self.ir.body_owner);
|
||||||
// if there is no later assignment. If this local is actually
|
if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hid)) {
|
||||||
// mutable, then check for a reassignment to flag the mutability
|
// Assignment to an immutable variable or argument: only legal
|
||||||
// as being used.
|
// if there is no later assignment. If this local is actually
|
||||||
let ln = self.live_node(expr.hir_id, expr.span);
|
// mutable, then check for a reassignment to flag the mutability
|
||||||
let var = self.variable(var_hid, expr.span);
|
// as being used.
|
||||||
self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -78,6 +78,7 @@ use syntax_pos::Span;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use crate::util::nodemap::ItemLocalSet;
|
use crate::util::nodemap::ItemLocalSet;
|
||||||
|
@ -288,6 +289,8 @@ impl HirNode for hir::Pat {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||||
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
pub body_owner: DefId,
|
||||||
|
pub upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
|
||||||
pub region_scope_tree: &'a region::ScopeTree,
|
pub region_scope_tree: &'a region::ScopeTree,
|
||||||
pub tables: &'a ty::TypeckTables<'tcx>,
|
pub tables: &'a ty::TypeckTables<'tcx>,
|
||||||
rvalue_promotable_map: Option<&'tcx ItemLocalSet>,
|
rvalue_promotable_map: Option<&'tcx ItemLocalSet>,
|
||||||
|
@ -398,12 +401,15 @@ impl MutabilityCategory {
|
||||||
|
|
||||||
impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> {
|
impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> {
|
||||||
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
body_owner: DefId,
|
||||||
region_scope_tree: &'a region::ScopeTree,
|
region_scope_tree: &'a region::ScopeTree,
|
||||||
tables: &'a ty::TypeckTables<'tcx>,
|
tables: &'a ty::TypeckTables<'tcx>,
|
||||||
rvalue_promotable_map: Option<&'tcx ItemLocalSet>)
|
rvalue_promotable_map: Option<&'tcx ItemLocalSet>)
|
||||||
-> MemCategorizationContext<'a, 'tcx, 'tcx> {
|
-> MemCategorizationContext<'a, 'tcx, 'tcx> {
|
||||||
MemCategorizationContext {
|
MemCategorizationContext {
|
||||||
tcx,
|
tcx,
|
||||||
|
body_owner,
|
||||||
|
upvars: tcx.upvars(body_owner),
|
||||||
region_scope_tree,
|
region_scope_tree,
|
||||||
tables,
|
tables,
|
||||||
rvalue_promotable_map,
|
rvalue_promotable_map,
|
||||||
|
@ -423,6 +429,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
/// - similarly, as the results of upvar analysis are not yet
|
/// - similarly, as the results of upvar analysis are not yet
|
||||||
/// known, the results around upvar accesses may be incorrect.
|
/// known, the results around upvar accesses may be incorrect.
|
||||||
pub fn with_infer(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
pub fn with_infer(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
body_owner: DefId,
|
||||||
region_scope_tree: &'a region::ScopeTree,
|
region_scope_tree: &'a region::ScopeTree,
|
||||||
tables: &'a ty::TypeckTables<'tcx>)
|
tables: &'a ty::TypeckTables<'tcx>)
|
||||||
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
|
@ -436,6 +443,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
MemCategorizationContext {
|
MemCategorizationContext {
|
||||||
tcx,
|
tcx,
|
||||||
|
body_owner,
|
||||||
|
upvars: tcx.upvars(body_owner),
|
||||||
region_scope_tree,
|
region_scope_tree,
|
||||||
tables,
|
tables,
|
||||||
rvalue_promotable_map,
|
rvalue_promotable_map,
|
||||||
|
@ -737,21 +746,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Res::Upvar(var_id, _, fn_node_id) => {
|
Res::Local(var_id) => {
|
||||||
let var_nid = self.tcx.hir().hir_to_node_id(var_id);
|
let var_nid = self.tcx.hir().hir_to_node_id(var_id);
|
||||||
self.cat_upvar(hir_id, span, var_nid, fn_node_id)
|
if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) {
|
||||||
}
|
self.cat_upvar(hir_id, span, var_nid)
|
||||||
|
} else {
|
||||||
Res::Local(vid) => {
|
Ok(cmt_ {
|
||||||
let vnid = self.tcx.hir().hir_to_node_id(vid);
|
hir_id,
|
||||||
Ok(cmt_ {
|
span,
|
||||||
hir_id,
|
cat: Categorization::Local(var_id),
|
||||||
span,
|
mutbl: MutabilityCategory::from_local(self.tcx, self.tables, var_nid),
|
||||||
cat: Categorization::Local(vid),
|
ty: expr_ty,
|
||||||
mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vnid),
|
note: NoteNone
|
||||||
ty: expr_ty,
|
})
|
||||||
note: NoteNone
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def)
|
def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def)
|
||||||
|
@ -760,15 +768,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// Categorize an upvar, complete with invisible derefs of closure
|
// Categorize an upvar, complete with invisible derefs of closure
|
||||||
// environment and upvar reference as appropriate.
|
// environment and upvar reference as appropriate.
|
||||||
fn cat_upvar(&self,
|
fn cat_upvar(
|
||||||
hir_id: hir::HirId,
|
&self,
|
||||||
span: Span,
|
hir_id: hir::HirId,
|
||||||
var_id: ast::NodeId,
|
span: Span,
|
||||||
fn_node_id: ast::NodeId)
|
var_id: ast::NodeId,
|
||||||
-> McResult<cmt_<'tcx>>
|
) -> McResult<cmt_<'tcx>> {
|
||||||
{
|
|
||||||
let fn_hir_id = self.tcx.hir().node_to_hir_id(fn_node_id);
|
|
||||||
|
|
||||||
// An upvar can have up to 3 components. We translate first to a
|
// 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
|
// `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the
|
||||||
// field from the environment.
|
// field from the environment.
|
||||||
|
@ -792,6 +797,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
// FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
|
// FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
|
||||||
// FnOnce | copied | upvar -> &'up bk
|
// FnOnce | copied | upvar -> &'up bk
|
||||||
|
|
||||||
|
let closure_expr_def_id = self.body_owner;
|
||||||
|
let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(
|
||||||
|
LocalDefId::from_def_id(closure_expr_def_id),
|
||||||
|
);
|
||||||
let ty = self.node_ty(fn_hir_id)?;
|
let ty = self.node_ty(fn_hir_id)?;
|
||||||
let kind = match ty.sty {
|
let kind = match ty.sty {
|
||||||
ty::Generator(..) => ty::ClosureKind::FnOnce,
|
ty::Generator(..) => ty::ClosureKind::FnOnce,
|
||||||
|
@ -813,7 +822,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
_ => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", ty),
|
_ => 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 var_hir_id = self.tcx.hir().node_to_hir_id(var_id);
|
||||||
let upvar_id = ty::UpvarId {
|
let upvar_id = ty::UpvarId {
|
||||||
var_path: ty::UpvarPath { hir_id: var_hir_id },
|
var_path: ty::UpvarPath { hir_id: var_hir_id },
|
||||||
|
|
|
@ -104,7 +104,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Some(Res::Local(hir_id)) | Some(Res::Upvar(hir_id, ..)) => {
|
Some(Res::Local(hir_id)) => {
|
||||||
self.reachable_symbols.insert(hir_id);
|
self.reachable_symbols.insert(hir_id);
|
||||||
}
|
}
|
||||||
Some(res) => {
|
Some(res) => {
|
||||||
|
|
|
@ -2562,8 +2562,8 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
||||||
let mut struct_fmt = fmt.debug_struct(&name);
|
let mut struct_fmt = fmt.debug_struct(&name);
|
||||||
|
|
||||||
if let Some(upvars) = tcx.upvars(def_id) {
|
if let Some(upvars) = tcx.upvars(def_id) {
|
||||||
for (upvar, place) in upvars.iter().zip(places) {
|
for (&var_id, place) in upvars.keys().zip(places) {
|
||||||
let var_name = tcx.hir().name_by_hir_id(upvar.var_id());
|
let var_name = tcx.hir().name_by_hir_id(var_id);
|
||||||
struct_fmt.field(&var_name.as_str(), place);
|
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);
|
let mut struct_fmt = fmt.debug_struct(&name);
|
||||||
|
|
||||||
if let Some(upvars) = tcx.upvars(def_id) {
|
if let Some(upvars) = tcx.upvars(def_id) {
|
||||||
for (upvar, place) in upvars.iter().zip(places) {
|
for (&var_id, place) in upvars.keys().zip(places) {
|
||||||
let var_name = tcx.hir().name_by_hir_id(upvar.var_id());
|
let var_name = tcx.hir().name_by_hir_id(var_id);
|
||||||
struct_fmt.field(&var_name.as_str(), place);
|
struct_fmt.field(&var_name.as_str(), place);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -826,7 +826,7 @@ rustc_queries! {
|
||||||
desc { "generating a postorder list of CrateNums" }
|
desc { "generating a postorder list of CrateNums" }
|
||||||
}
|
}
|
||||||
|
|
||||||
query upvars(_: DefId) -> Option<&'tcx [hir::Upvar]> {
|
query upvars(_: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
|
||||||
eval_always
|
eval_always
|
||||||
}
|
}
|
||||||
query maybe_unused_trait_import(_: DefId) -> bool {
|
query maybe_unused_trait_import(_: DefId) -> bool {
|
||||||
|
|
|
@ -1062,11 +1062,6 @@ pub struct GlobalCtxt<'tcx> {
|
||||||
|
|
||||||
pub queries: query::Queries<'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<DefId, Vec<hir::Upvar>>,
|
|
||||||
|
|
||||||
maybe_unused_trait_imports: FxHashSet<DefId>,
|
maybe_unused_trait_imports: FxHashSet<DefId>,
|
||||||
maybe_unused_extern_crates: Vec<(DefId, Span)>,
|
maybe_unused_extern_crates: Vec<(DefId, Span)>,
|
||||||
/// A map of glob use to a set of names it actually imports. Currently only
|
/// A map of glob use to a set of names it actually imports. Currently only
|
||||||
|
@ -1297,12 +1292,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
}).collect();
|
}).collect();
|
||||||
(k, exports)
|
(k, exports)
|
||||||
}).collect(),
|
}).collect(),
|
||||||
upvars: resolutions.upvars.into_iter().map(|(k, v)| {
|
|
||||||
let vars: Vec<_> = v.into_iter().map(|e| {
|
|
||||||
e.map_id(|id| hir.node_to_hir_id(id))
|
|
||||||
}).collect();
|
|
||||||
(hir.local_def_id(k), vars)
|
|
||||||
}).collect(),
|
|
||||||
maybe_unused_trait_imports:
|
maybe_unused_trait_imports:
|
||||||
resolutions.maybe_unused_trait_imports
|
resolutions.maybe_unused_trait_imports
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -3023,7 +3012,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||||
assert_eq!(id, LOCAL_CRATE);
|
assert_eq!(id, LOCAL_CRATE);
|
||||||
tcx.arena.alloc(middle::lang_items::collect(tcx))
|
tcx.arena.alloc(middle::lang_items::collect(tcx))
|
||||||
};
|
};
|
||||||
providers.upvars = |tcx, id| tcx.gcx.upvars.get(&id).map(|v| &v[..]);
|
|
||||||
providers.maybe_unused_trait_import = |tcx, id| {
|
providers.maybe_unused_trait_import = |tcx, id| {
|
||||||
tcx.maybe_unused_trait_imports.contains(&id)
|
tcx.maybe_unused_trait_imports.contains(&id)
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub use self::BorrowKind::*;
|
||||||
pub use self::IntVarValue::*;
|
pub use self::IntVarValue::*;
|
||||||
pub use self::fold::TypeFoldable;
|
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::Node;
|
||||||
use crate::hir::def::{Res, DefKind, CtorOf, CtorKind, ExportMap};
|
use crate::hir::def::{Res, DefKind, CtorOf, CtorKind, ExportMap};
|
||||||
use crate::hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
use crate::hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||||
|
@ -51,6 +51,7 @@ use syntax::symbol::{kw, sym, Symbol, LocalInternedString, InternedString};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
use smallvec;
|
use smallvec;
|
||||||
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||||
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
||||||
HashStable};
|
HashStable};
|
||||||
|
@ -122,7 +123,6 @@ mod sty;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Resolutions {
|
pub struct Resolutions {
|
||||||
pub upvars: UpvarMap,
|
|
||||||
pub trait_map: TraitMap,
|
pub trait_map: TraitMap,
|
||||||
pub maybe_unused_trait_imports: NodeSet,
|
pub maybe_unused_trait_imports: NodeSet,
|
||||||
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
|
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
|
||||||
|
@ -808,7 +808,7 @@ pub struct UpvarBorrow<'tcx> {
|
||||||
pub region: ty::Region<'tcx>,
|
pub region: ty::Region<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type UpvarListMap = FxHashMap<DefId, Vec<UpvarId>>;
|
pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
|
||||||
pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
|
pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
|
|
@ -585,16 +585,16 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
|
||||||
if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) {
|
if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) {
|
||||||
p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id)));
|
p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id)));
|
||||||
let mut sep = " ";
|
let mut sep = " ";
|
||||||
for (upvar, upvar_ty) in self.tcx().upvars(did)
|
for (&var_id, upvar_ty) in self.tcx().upvars(did)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(&[][..], |v| &v[..])
|
|
||||||
.iter()
|
.iter()
|
||||||
|
.flat_map(|v| v.keys())
|
||||||
.zip(upvar_tys)
|
.zip(upvar_tys)
|
||||||
{
|
{
|
||||||
p!(
|
p!(
|
||||||
write("{}{}:",
|
write("{}{}:",
|
||||||
sep,
|
sep,
|
||||||
self.tcx().hir().name_by_hir_id(upvar.var_id())),
|
self.tcx().hir().name_by_hir_id(var_id)),
|
||||||
print(upvar_ty));
|
print(upvar_ty));
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
|
@ -628,16 +628,16 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
|
||||||
p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id)));
|
p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id)));
|
||||||
}
|
}
|
||||||
let mut sep = " ";
|
let mut sep = " ";
|
||||||
for (upvar, upvar_ty) in self.tcx().upvars(did)
|
for (&var_id, upvar_ty) in self.tcx().upvars(did)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(&[][..], |v| &v[..])
|
|
||||||
.iter()
|
.iter()
|
||||||
|
.flat_map(|v| v.keys())
|
||||||
.zip(upvar_tys)
|
.zip(upvar_tys)
|
||||||
{
|
{
|
||||||
p!(
|
p!(
|
||||||
write("{}{}:",
|
write("{}{}:",
|
||||||
sep,
|
sep,
|
||||||
self.tcx().hir().name_by_hir_id(upvar.var_id())),
|
self.tcx().hir().name_by_hir_id(var_id)),
|
||||||
print(upvar_ty));
|
print(upvar_ty));
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ use crate::util::profiling::ProfileCategory::*;
|
||||||
use rustc_data_structures::svh::Svh;
|
use rustc_data_structures::svh::Svh;
|
||||||
use rustc_data_structures::bit_set::BitSet;
|
use rustc_data_structures::bit_set::BitSet;
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
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::stable_hasher::StableVec;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
|
|
|
@ -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);
|
let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
|
||||||
euv::ExprUseVisitor::new(&mut clcx,
|
euv::ExprUseVisitor::new(&mut clcx,
|
||||||
bccx.tcx,
|
bccx.tcx,
|
||||||
|
def_id,
|
||||||
param_env,
|
param_env,
|
||||||
&bccx.region_scope_tree,
|
&bccx.region_scope_tree,
|
||||||
bccx.tables,
|
bccx.tables,
|
||||||
|
|
|
@ -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);
|
let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
|
||||||
euv::ExprUseVisitor::new(&mut glcx,
|
euv::ExprUseVisitor::new(&mut glcx,
|
||||||
bccx.tcx,
|
bccx.tcx,
|
||||||
|
def_id,
|
||||||
param_env,
|
param_env,
|
||||||
&bccx.region_scope_tree,
|
&bccx.region_scope_tree,
|
||||||
bccx.tables,
|
bccx.tables,
|
||||||
|
|
|
@ -11,6 +11,7 @@ crate-type = ["dylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ena = "0.13"
|
ena = "0.13"
|
||||||
|
indexmap = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
jobserver_crate = { version = "0.1.13", package = "jobserver" }
|
jobserver_crate = { version = "0.1.13", package = "jobserver" }
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
|
|
|
@ -1 +1,6 @@
|
||||||
|
use std::hash::BuildHasherDefault;
|
||||||
|
|
||||||
pub use rustc_hash::{FxHasher, FxHashMap, FxHashSet};
|
pub use rustc_hash::{FxHasher, FxHashMap, FxHashSet};
|
||||||
|
|
||||||
|
pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||||
|
pub type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
||||||
|
|
|
@ -323,6 +323,37 @@ impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<K, V, R, CTX> HashStable<CTX> for indexmap::IndexMap<K, V, R>
|
||||||
|
where K: HashStable<CTX> + Eq + Hash,
|
||||||
|
V: HashStable<CTX>,
|
||||||
|
R: BuildHasher,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn hash_stable<W: StableHasherResult>(&self,
|
||||||
|
ctx: &mut CTX,
|
||||||
|
hasher: &mut StableHasher<W>) {
|
||||||
|
self.len().hash_stable(ctx, hasher);
|
||||||
|
for kv in self {
|
||||||
|
kv.hash_stable(ctx, hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, R, CTX> HashStable<CTX> for indexmap::IndexSet<K, R>
|
||||||
|
where K: HashStable<CTX> + Eq + Hash,
|
||||||
|
R: BuildHasher,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn hash_stable<W: StableHasherResult>(&self,
|
||||||
|
ctx: &mut CTX,
|
||||||
|
hasher: &mut StableHasher<W>) {
|
||||||
|
self.len().hash_stable(ctx, hasher);
|
||||||
|
for key in self {
|
||||||
|
key.hash_stable(ctx, hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A, CTX> HashStable<CTX> for SmallVec<[A; 1]> where A: HashStable<CTX> {
|
impl<A, CTX> HashStable<CTX> for SmallVec<[A; 1]> where A: HashStable<CTX> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash_stable<W: StableHasherResult>(&self,
|
fn hash_stable<W: StableHasherResult>(&self,
|
||||||
|
|
|
@ -178,7 +178,6 @@ impl ExpansionResult {
|
||||||
ExpansionResult {
|
ExpansionResult {
|
||||||
defs: Steal::new(resolver.definitions),
|
defs: Steal::new(resolver.definitions),
|
||||||
resolutions: Steal::new(Resolutions {
|
resolutions: Steal::new(Resolutions {
|
||||||
upvars: resolver.upvars,
|
|
||||||
export_map: resolver.export_map,
|
export_map: resolver.export_map,
|
||||||
trait_map: resolver.trait_map,
|
trait_map: resolver.trait_map,
|
||||||
glob_map: resolver.glob_map,
|
glob_map: resolver.glob_map,
|
||||||
|
@ -197,7 +196,6 @@ impl ExpansionResult {
|
||||||
ExpansionResult {
|
ExpansionResult {
|
||||||
defs: Steal::new(resolver.definitions.clone()),
|
defs: Steal::new(resolver.definitions.clone()),
|
||||||
resolutions: Steal::new(Resolutions {
|
resolutions: Steal::new(Resolutions {
|
||||||
upvars: resolver.upvars.clone(),
|
|
||||||
export_map: resolver.export_map.clone(),
|
export_map: resolver.export_map.clone(),
|
||||||
trait_map: resolver.trait_map.clone(),
|
trait_map: resolver.trait_map.clone(),
|
||||||
glob_map: resolver.glob_map.clone(),
|
glob_map: resolver.glob_map.clone(),
|
||||||
|
|
|
@ -348,9 +348,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
// `tcx.upvars(def_id)` returns an `Option`, which is `None` in case
|
// `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
|
// the closure comes from another crate. But in that case we wouldn't
|
||||||
// be borrowck'ing it, so we can just unwrap:
|
// 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
|
// 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(
|
if let hir::ExprKind::Closure(
|
||||||
.., args_span, _
|
.., args_span, _
|
||||||
) = expr {
|
) = 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 {
|
match place {
|
||||||
Operand::Copy(place) |
|
Operand::Copy(place) |
|
||||||
Operand::Move(place) if target_place == place => {
|
Operand::Move(place) if target_place == place => {
|
||||||
debug!("closure_span: found captured local {:?}", place);
|
debug!("closure_span: found captured local {:?}", place);
|
||||||
return Some((*args_span, v.span));
|
return Some((*args_span, upvar.span));
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,7 +149,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||||
.upvar_list
|
.upvar_list
|
||||||
.get(&def_id)
|
.get(&def_id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flat_map(|v| v.values())
|
||||||
.map(|upvar_id| {
|
.map(|upvar_id| {
|
||||||
let var_hir_id = upvar_id.var_path.hir_id;
|
let var_hir_id = upvar_id.var_path.hir_id;
|
||||||
let var_node_id = tcx.hir().hir_to_node_id(var_hir_id);
|
let var_node_id = tcx.hir().hir_to_node_id(var_hir_id);
|
||||||
|
|
|
@ -651,10 +651,9 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
|
||||||
.get(&fn_def_id)
|
.get(&fn_def_id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.map(|upvar_id| {
|
.map(|(&var_hir_id, &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);
|
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 {
|
let by_ref = match capture {
|
||||||
ty::UpvarCapture::ByValue => false,
|
ty::UpvarCapture::ByValue => false,
|
||||||
ty::UpvarCapture::ByRef(..) => true,
|
ty::UpvarCapture::ByRef(..) => true,
|
||||||
|
|
|
@ -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()
|
let upvars = cx.tcx.upvars(def_id).iter()
|
||||||
.flat_map(|upvars| upvars.iter())
|
.flat_map(|upvars| upvars.iter())
|
||||||
.zip(substs.upvar_tys(def_id, cx.tcx))
|
.zip(substs.upvar_tys(def_id, cx.tcx))
|
||||||
.map(|(upvar, ty)| capture_upvar(cx, expr, upvar, ty))
|
.map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty))
|
||||||
.collect();
|
.collect();
|
||||||
ExprKind::Closure {
|
ExprKind::Closure {
|
||||||
closure_id: def_id,
|
closure_id: def_id,
|
||||||
|
@ -960,36 +960,44 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
|
|
||||||
Res::Def(DefKind::Static, id) => ExprKind::StaticRef { id },
|
Res::Def(DefKind::Static, id) => ExprKind::StaticRef { id },
|
||||||
|
|
||||||
Res::Local(..) | Res::Upvar(..) => convert_var(cx, expr, res),
|
Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id),
|
||||||
|
|
||||||
_ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
|
_ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
fn convert_var(
|
||||||
expr: &'tcx hir::Expr,
|
cx: &mut Cx<'_, '_, 'tcx>,
|
||||||
res: Res)
|
expr: &'tcx hir::Expr,
|
||||||
-> ExprKind<'tcx> {
|
var_hir_id: hir::HirId,
|
||||||
|
) -> ExprKind<'tcx> {
|
||||||
|
let upvar_index = cx.tables().upvar_list.get(&cx.body_owner)
|
||||||
|
.and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i));
|
||||||
|
|
||||||
|
debug!("convert_var({:?}): upvar_index={:?}, body_owner={:?}",
|
||||||
|
var_hir_id, upvar_index, cx.body_owner);
|
||||||
|
|
||||||
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||||
|
|
||||||
match res {
|
match upvar_index {
|
||||||
Res::Local(id) => ExprKind::VarRef { id },
|
None => ExprKind::VarRef { id: var_hir_id },
|
||||||
|
|
||||||
Res::Upvar(var_hir_id, index, closure_expr_id) => {
|
Some(upvar_index) => {
|
||||||
debug!("convert_var(upvar({:?}, {:?}, {:?}))",
|
let closure_def_id = cx.body_owner;
|
||||||
var_hir_id,
|
let upvar_id = ty::UpvarId {
|
||||||
index,
|
var_path: ty::UpvarPath {hir_id: var_hir_id},
|
||||||
closure_expr_id);
|
closure_expr_id: LocalDefId::from_def_id(closure_def_id),
|
||||||
|
};
|
||||||
let var_ty = cx.tables().node_type(var_hir_id);
|
let var_ty = cx.tables().node_type(var_hir_id);
|
||||||
|
|
||||||
// FIXME free regions in closures are not right
|
// FIXME free regions in closures are not right
|
||||||
let closure_ty = cx.tables()
|
let closure_ty = cx.tables().node_type(
|
||||||
.node_type(cx.tcx.hir().node_to_hir_id(closure_expr_id));
|
cx.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id),
|
||||||
|
);
|
||||||
|
|
||||||
// FIXME we're just hard-coding the idea that the
|
// FIXME we're just hard-coding the idea that the
|
||||||
// signature will be &self or &mut self and hence will
|
// signature will be &self or &mut self and hence will
|
||||||
// have a bound region with number 0
|
// 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 {
|
let region = ty::ReFree(ty::FreeRegion {
|
||||||
scope: closure_def_id,
|
scope: closure_def_id,
|
||||||
bound_region: ty::BoundRegion::BrAnon(0),
|
bound_region: ty::BoundRegion::BrAnon(0),
|
||||||
|
@ -1060,15 +1068,11 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
// at this point we have `self.n`, which loads up the upvar
|
// at this point we have `self.n`, which loads up the upvar
|
||||||
let field_kind = ExprKind::Field {
|
let field_kind = ExprKind::Field {
|
||||||
lhs: self_expr.to_ref(),
|
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
|
// ...but the upvar might be an `&T` or `&mut T` capture, at which
|
||||||
// point we need an implicit deref
|
// 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) {
|
match cx.tables().upvar_capture(upvar_id) {
|
||||||
ty::UpvarCapture::ByValue => field_kind,
|
ty::UpvarCapture::ByValue => field_kind,
|
||||||
ty::UpvarCapture::ByRef(borrow) => {
|
ty::UpvarCapture::ByRef(borrow) => {
|
||||||
|
@ -1087,8 +1091,6 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => span_bug!(expr.span, "type of & not region"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1178,10 +1180,9 @@ fn overloaded_place<'a, 'gcx, 'tcx>(
|
||||||
|
|
||||||
fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
closure_expr: &'tcx hir::Expr,
|
closure_expr: &'tcx hir::Expr,
|
||||||
upvar: &hir::Upvar,
|
var_hir_id: hir::HirId,
|
||||||
upvar_ty: Ty<'tcx>)
|
upvar_ty: Ty<'tcx>)
|
||||||
-> ExprRef<'tcx> {
|
-> ExprRef<'tcx> {
|
||||||
let var_hir_id = upvar.var_id();
|
|
||||||
let upvar_id = ty::UpvarId {
|
let upvar_id = ty::UpvarId {
|
||||||
var_path: ty::UpvarPath { hir_id: var_hir_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(),
|
closure_expr_id: cx.tcx.hir().local_def_id_from_hir_id(closure_expr.hir_id).to_local(),
|
||||||
|
@ -1193,7 +1194,7 @@ fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
temp_lifetime,
|
temp_lifetime,
|
||||||
ty: var_ty,
|
ty: var_ty,
|
||||||
span: closure_expr.span,
|
span: closure_expr.span,
|
||||||
kind: convert_var(cx, closure_expr, upvar.res),
|
kind: convert_var(cx, closure_expr, var_hir_id),
|
||||||
};
|
};
|
||||||
match upvar_capture {
|
match upvar_capture {
|
||||||
ty::UpvarCapture::ByValue => captured_var.to_ref(),
|
ty::UpvarCapture::ByValue => captured_var.to_ref(),
|
||||||
|
|
|
@ -38,6 +38,9 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||||
/// `const`, or the body of a `const fn`.
|
/// `const`, or the body of a `const fn`.
|
||||||
constness: hir::Constness,
|
constness: hir::Constness,
|
||||||
|
|
||||||
|
/// The `DefId` of the owner of this body.
|
||||||
|
body_owner: DefId,
|
||||||
|
|
||||||
/// What kind of body is being compiled.
|
/// What kind of body is being compiled.
|
||||||
pub body_owner_kind: hir::BodyOwnerKind,
|
pub body_owner_kind: hir::BodyOwnerKind,
|
||||||
|
|
||||||
|
@ -53,6 +56,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
src_id: hir::HirId) -> Cx<'a, 'gcx, 'tcx> {
|
src_id: hir::HirId) -> Cx<'a, 'gcx, 'tcx> {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let src_def_id = tcx.hir().local_def_id_from_hir_id(src_id);
|
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 body_owner_kind = tcx.hir().body_owner_kind_by_hir_id(src_id);
|
||||||
|
|
||||||
let constness = match body_owner_kind {
|
let constness = match body_owner_kind {
|
||||||
|
@ -82,8 +86,9 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||||
param_env: tcx.param_env(src_def_id),
|
param_env: tcx.param_env(src_def_id),
|
||||||
identity_substs: InternalSubsts::identity_for_item(tcx.global_tcx(), 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),
|
region_scope_tree: tcx.region_scope_tree(src_def_id),
|
||||||
tables: tcx.typeck_tables_of(src_def_id),
|
tables,
|
||||||
constness,
|
constness,
|
||||||
|
body_owner: src_def_id,
|
||||||
body_owner_kind,
|
body_owner_kind,
|
||||||
check_overflow,
|
check_overflow,
|
||||||
control_flow_destroyed: Vec::new(),
|
control_flow_destroyed: Vec::new(),
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub(crate) fn check_match<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
|
||||||
|
|
||||||
MatchVisitor {
|
MatchVisitor {
|
||||||
tcx,
|
tcx,
|
||||||
|
body_owner: def_id,
|
||||||
tables: tcx.body_tables(body_id),
|
tables: tcx.body_tables(body_id),
|
||||||
region_scope_tree: &tcx.region_scope_tree(def_id),
|
region_scope_tree: &tcx.region_scope_tree(def_id),
|
||||||
param_env: tcx.param_env(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> {
|
struct MatchVisitor<'a, 'tcx: 'a> {
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
body_owner: DefId,
|
||||||
tables: &'a ty::TypeckTables<'tcx>,
|
tables: &'a ty::TypeckTables<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
identity_substs: SubstsRef<'tcx>,
|
identity_substs: SubstsRef<'tcx>,
|
||||||
|
@ -632,6 +634,7 @@ fn check_for_mutation_in_guard(cx: &MatchVisitor<'_, '_>, guard: &hir::Guard) {
|
||||||
hir::Guard::If(expr) =>
|
hir::Guard::If(expr) =>
|
||||||
ExprUseVisitor::new(&mut checker,
|
ExprUseVisitor::new(&mut checker,
|
||||||
cx.tcx,
|
cx.tcx,
|
||||||
|
cx.body_owner,
|
||||||
cx.param_env,
|
cx.param_env,
|
||||||
cx.region_scope_tree,
|
cx.region_scope_tree,
|
||||||
cx.tables,
|
cx.tables,
|
||||||
|
|
|
@ -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) {
|
if let Some(upvars) = tables.upvar_list.get(&def_id) {
|
||||||
// Sometimes the index is beyond the number of upvars (seen
|
// Sometimes the index is beyond the number of upvars (seen
|
||||||
// for a generator).
|
// for a generator).
|
||||||
if let Some(upvar_id) = upvars.get(field) {
|
if let Some((&var_hir_id, _)) = upvars.get_index(field) {
|
||||||
let var_hir_id = upvar_id.var_path.hir_id;
|
|
||||||
let var_node_id = self.ecx.tcx.hir().hir_to_node_id(var_hir_id);
|
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::Node::Binding(pat) = self.ecx.tcx.hir().get(var_node_id) {
|
||||||
if let hir::PatKind::Binding(_, _, ident, _) = pat.node {
|
if let hir::PatKind::Binding(_, _, ident, _) = pat.node {
|
||||||
|
|
|
@ -199,8 +199,15 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
||||||
let param_env = self.param_env;
|
let param_env = self.param_env;
|
||||||
let region_scope_tree = self.tcx.region_scope_tree(item_def_id);
|
let region_scope_tree = self.tcx.region_scope_tree(item_def_id);
|
||||||
let tables = self.tables;
|
let tables = self.tables;
|
||||||
euv::ExprUseVisitor::new(self, tcx, param_env, ®ion_scope_tree, tables, None)
|
euv::ExprUseVisitor::new(
|
||||||
.consume_body(body);
|
self,
|
||||||
|
tcx,
|
||||||
|
item_def_id,
|
||||||
|
param_env,
|
||||||
|
®ion_scope_tree,
|
||||||
|
tables,
|
||||||
|
None,
|
||||||
|
).consume_body(body);
|
||||||
|
|
||||||
let body_promotable = self.check_expr(&body.value);
|
let body_promotable = self.check_expr(&body.value);
|
||||||
self.in_fn = outer_in_fn;
|
self.in_fn = outer_in_fn;
|
||||||
|
|
|
@ -12,6 +12,7 @@ test = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
|
indexmap = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
syntax = { path = "../libsyntax" }
|
syntax = { path = "../libsyntax" }
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
|
|
|
@ -29,7 +29,7 @@ use rustc::hir::def::{
|
||||||
};
|
};
|
||||||
use rustc::hir::def::Namespace::*;
|
use rustc::hir::def::Namespace::*;
|
||||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
|
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::ty::{self, DefIdTree};
|
||||||
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
|
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
|
||||||
use rustc::{bug, span_bug};
|
use rustc::{bug, span_bug};
|
||||||
|
@ -612,7 +612,6 @@ impl<'a> PathSource<'a> {
|
||||||
| Res::Def(DefKind::Const, _)
|
| Res::Def(DefKind::Const, _)
|
||||||
| Res::Def(DefKind::Static, _)
|
| Res::Def(DefKind::Static, _)
|
||||||
| Res::Local(..)
|
| Res::Local(..)
|
||||||
| Res::Upvar(..)
|
|
||||||
| Res::Def(DefKind::Fn, _)
|
| Res::Def(DefKind::Fn, _)
|
||||||
| Res::Def(DefKind::Method, _)
|
| Res::Def(DefKind::Method, _)
|
||||||
| Res::Def(DefKind::AssocConst, _)
|
| Res::Def(DefKind::AssocConst, _)
|
||||||
|
@ -853,7 +852,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||||
function_kind: FnKind<'tcx>,
|
function_kind: FnKind<'tcx>,
|
||||||
declaration: &'tcx FnDecl,
|
declaration: &'tcx FnDecl,
|
||||||
_: Span,
|
_: Span,
|
||||||
node_id: NodeId)
|
_: NodeId)
|
||||||
{
|
{
|
||||||
debug!("(resolving function) entering function");
|
debug!("(resolving function) entering function");
|
||||||
let (rib_kind, asyncness) = match function_kind {
|
let (rib_kind, asyncness) = match function_kind {
|
||||||
|
@ -864,7 +863,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||||
FnKind::Closure(_) =>
|
FnKind::Closure(_) =>
|
||||||
// Async closures aren't resolved through `visit_fn`-- they're
|
// Async closures aren't resolved through `visit_fn`-- they're
|
||||||
// processed separately
|
// processed separately
|
||||||
(ClosureRibKind(node_id), &IsAsync::NotAsync),
|
(NormalRibKind, &IsAsync::NotAsync),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a value rib for the function.
|
// Create a value rib for the function.
|
||||||
|
@ -898,12 +897,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||||
visit::walk_fn_ret_ty(self, &declaration.output);
|
visit::walk_fn_ret_ty(self, &declaration.output);
|
||||||
|
|
||||||
// Resolve the function body, potentially inside the body of an async closure
|
// Resolve the function body, potentially inside the body of an async closure
|
||||||
if let IsAsync::Async { closure_id, .. } = asyncness {
|
|
||||||
let rib_kind = ClosureRibKind(*closure_id);
|
|
||||||
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
|
||||||
self.label_ribs.push(Rib::new(rib_kind));
|
|
||||||
}
|
|
||||||
|
|
||||||
match function_kind {
|
match function_kind {
|
||||||
FnKind::ItemFn(.., body) | FnKind::Method(.., body) => {
|
FnKind::ItemFn(.., body) | FnKind::Method(.., body) => {
|
||||||
if let IsAsync::Async { ref arguments, .. } = asyncness {
|
if let IsAsync::Async { ref arguments, .. } = asyncness {
|
||||||
|
@ -926,12 +919,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Leave the body of the async closure
|
|
||||||
if asyncness.is_async() {
|
|
||||||
self.label_ribs.pop();
|
|
||||||
self.ribs[ValueNS].pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("(resolving function) leaving function");
|
debug!("(resolving function) leaving function");
|
||||||
|
|
||||||
self.label_ribs.pop();
|
self.label_ribs.pop();
|
||||||
|
@ -1018,17 +1005,13 @@ enum GenericParameters<'a, 'b> {
|
||||||
RibKind<'a>),
|
RibKind<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The rib kind controls the translation of local
|
/// The rib kind restricts certain accesses,
|
||||||
/// definitions (`Res::Local`) to upvars (`Res::Upvar`).
|
/// e.g. to a `Res::Local` of an outer item.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum RibKind<'a> {
|
enum RibKind<'a> {
|
||||||
/// No translation needs to be applied.
|
/// No restriction needs to be applied.
|
||||||
NormalRibKind,
|
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
|
/// 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
|
/// methods or associated types. Allow references to ty params that impl or trait
|
||||||
/// binds. Disallow any other upvars (including other ty params that are
|
/// binds. Disallow any other upvars (including other ty params that are
|
||||||
|
@ -1668,8 +1651,6 @@ pub struct Resolver<'a> {
|
||||||
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
|
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
|
||||||
label_res_map: NodeMap<NodeId>,
|
label_res_map: NodeMap<NodeId>,
|
||||||
|
|
||||||
pub upvars: UpvarMap,
|
|
||||||
upvars_seen: NodeMap<NodeMap<usize>>,
|
|
||||||
pub export_map: ExportMap<NodeId>,
|
pub export_map: ExportMap<NodeId>,
|
||||||
pub trait_map: TraitMap,
|
pub trait_map: TraitMap,
|
||||||
|
|
||||||
|
@ -2032,8 +2013,6 @@ impl<'a> Resolver<'a> {
|
||||||
partial_res_map: Default::default(),
|
partial_res_map: Default::default(),
|
||||||
import_res_map: Default::default(),
|
import_res_map: Default::default(),
|
||||||
label_res_map: Default::default(),
|
label_res_map: Default::default(),
|
||||||
upvars: Default::default(),
|
|
||||||
upvars_seen: Default::default(),
|
|
||||||
export_map: FxHashMap::default(),
|
export_map: FxHashMap::default(),
|
||||||
trait_map: Default::default(),
|
trait_map: Default::default(),
|
||||||
module_map,
|
module_map,
|
||||||
|
@ -2206,7 +2185,7 @@ impl<'a> Resolver<'a> {
|
||||||
if let Some(res) = self.ribs[ns][i].bindings.get(&ident).cloned() {
|
if let Some(res) = self.ribs[ns][i].bindings.get(&ident).cloned() {
|
||||||
// The ident resolves to a type parameter or local variable.
|
// The ident resolves to a type parameter or local variable.
|
||||||
return Some(LexicalScopeBinding::Res(
|
return Some(LexicalScopeBinding::Res(
|
||||||
self.adjust_local_res(ns, i, res, record_used, path_span)
|
self.validate_res_from_ribs(ns, i, res, record_used, path_span),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4008,14 +3987,16 @@ impl<'a> Resolver<'a> {
|
||||||
diag);
|
diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve a local definition, potentially adjusting for closures.
|
// Validate a local resolution (from ribs).
|
||||||
fn adjust_local_res(&mut self,
|
fn validate_res_from_ribs(
|
||||||
ns: Namespace,
|
&mut self,
|
||||||
rib_index: usize,
|
ns: Namespace,
|
||||||
mut res: Res,
|
rib_index: usize,
|
||||||
record_used: bool,
|
res: Res,
|
||||||
span: Span) -> Res {
|
record_used: bool,
|
||||||
debug!("adjust_local_res");
|
span: Span,
|
||||||
|
) -> Res {
|
||||||
|
debug!("validate_res_from_ribs({:?})", res);
|
||||||
let ribs = &self.ribs[ns][rib_index + 1..];
|
let ribs = &self.ribs[ns][rib_index + 1..];
|
||||||
|
|
||||||
// An invalid forward use of a type parameter from a previous default.
|
// An invalid forward use of a type parameter from a previous default.
|
||||||
|
@ -4037,10 +4018,7 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Res::Upvar(..) => {
|
Res::Local(_) => {
|
||||||
span_bug!(span, "unexpected {:?} in bindings", res)
|
|
||||||
}
|
|
||||||
Res::Local(node_id) => {
|
|
||||||
use ResolutionError::*;
|
use ResolutionError::*;
|
||||||
let mut res_err = None;
|
let mut res_err = None;
|
||||||
|
|
||||||
|
@ -4050,30 +4028,6 @@ impl<'a> Resolver<'a> {
|
||||||
ForwardTyParamBanRibKind | TyParamAsConstParamTy => {
|
ForwardTyParamBanRibKind | TyParamAsConstParamTy => {
|
||||||
// Nothing to do. Continue.
|
// Nothing to do. Continue.
|
||||||
}
|
}
|
||||||
ClosureRibKind(function_id) => {
|
|
||||||
let prev_res = res;
|
|
||||||
|
|
||||||
let seen = self.upvars_seen
|
|
||||||
.entry(function_id)
|
|
||||||
.or_default();
|
|
||||||
if let Some(&index) = seen.get(&node_id) {
|
|
||||||
res = Res::Upvar(node_id, index, function_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let vec = self.upvars
|
|
||||||
.entry(function_id)
|
|
||||||
.or_default();
|
|
||||||
let depth = vec.len();
|
|
||||||
res = Res::Upvar(node_id, depth, function_id);
|
|
||||||
|
|
||||||
if record_used {
|
|
||||||
vec.push(Upvar {
|
|
||||||
res: prev_res,
|
|
||||||
span,
|
|
||||||
});
|
|
||||||
seen.insert(node_id, depth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ItemRibKind | FnItemRibKind | AssocItemRibKind => {
|
ItemRibKind | FnItemRibKind | AssocItemRibKind => {
|
||||||
// This was an attempt to access an upvar inside a
|
// This was an attempt to access an upvar inside a
|
||||||
// named function item. This is not allowed, so we
|
// named function item. This is not allowed, so we
|
||||||
|
@ -4103,7 +4057,7 @@ impl<'a> Resolver<'a> {
|
||||||
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
|
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
|
||||||
for rib in ribs {
|
for rib in ribs {
|
||||||
match rib.kind {
|
match rib.kind {
|
||||||
NormalRibKind | AssocItemRibKind | ClosureRibKind(..) |
|
NormalRibKind | AssocItemRibKind |
|
||||||
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
|
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
|
||||||
ConstantItemRibKind | TyParamAsConstParamTy => {
|
ConstantItemRibKind | TyParamAsConstParamTy => {
|
||||||
// Nothing to do. Continue.
|
// Nothing to do. Continue.
|
||||||
|
@ -4483,25 +4437,15 @@ impl<'a> Resolver<'a> {
|
||||||
visit::walk_expr(self, expr);
|
visit::walk_expr(self, expr);
|
||||||
self.current_type_ascription.pop();
|
self.current_type_ascription.pop();
|
||||||
}
|
}
|
||||||
// Resolve the body of async exprs inside the async closure to which they desugar
|
|
||||||
ExprKind::Async(_, async_closure_id, ref block) => {
|
|
||||||
let rib_kind = ClosureRibKind(async_closure_id);
|
|
||||||
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
|
||||||
self.label_ribs.push(Rib::new(rib_kind));
|
|
||||||
self.visit_block(&block);
|
|
||||||
self.label_ribs.pop();
|
|
||||||
self.ribs[ValueNS].pop();
|
|
||||||
}
|
|
||||||
// `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
|
// `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
|
// 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.
|
// closure are detected as upvars rather than normal closure arg usages.
|
||||||
ExprKind::Closure(
|
ExprKind::Closure(
|
||||||
_, IsAsync::Async { closure_id: inner_closure_id, .. }, _,
|
_, IsAsync::Async { .. }, _,
|
||||||
ref fn_decl, ref body, _span,
|
ref fn_decl, ref body, _span,
|
||||||
) => {
|
) => {
|
||||||
let rib_kind = ClosureRibKind(expr.id);
|
let rib_kind = NormalRibKind;
|
||||||
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||||
self.label_ribs.push(Rib::new(rib_kind));
|
|
||||||
// Resolve arguments:
|
// Resolve arguments:
|
||||||
let mut bindings_list = FxHashMap::default();
|
let mut bindings_list = FxHashMap::default();
|
||||||
for argument in &fn_decl.inputs {
|
for argument in &fn_decl.inputs {
|
||||||
|
@ -4513,18 +4457,12 @@ impl<'a> Resolver<'a> {
|
||||||
|
|
||||||
// Now resolve the inner closure
|
// Now resolve the inner closure
|
||||||
{
|
{
|
||||||
let rib_kind = ClosureRibKind(inner_closure_id);
|
|
||||||
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
|
||||||
self.label_ribs.push(Rib::new(rib_kind));
|
|
||||||
// No need to resolve arguments: the inner closure has none.
|
// No need to resolve arguments: the inner closure has none.
|
||||||
// Resolve the return type:
|
// Resolve the return type:
|
||||||
visit::walk_fn_ret_ty(self, &fn_decl.output);
|
visit::walk_fn_ret_ty(self, &fn_decl.output);
|
||||||
// Resolve the body
|
// Resolve the body
|
||||||
self.visit_expr(body);
|
self.visit_expr(body);
|
||||||
self.label_ribs.pop();
|
|
||||||
self.ribs[ValueNS].pop();
|
|
||||||
}
|
}
|
||||||
self.label_ribs.pop();
|
|
||||||
self.ribs[ValueNS].pop();
|
self.ribs[ValueNS].pop();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -702,7 +702,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
||||||
let span = self.span_from_span(span);
|
let span = self.span_from_span(span);
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Res::Upvar(id, ..) | Res::Local(id) => {
|
Res::Local(id) => {
|
||||||
Some(Ref {
|
Some(Ref {
|
||||||
kind: RefKind::Variable,
|
kind: RefKind::Variable,
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -350,7 +350,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let def_span = match def {
|
let def_span = match def {
|
||||||
Res::Err => None,
|
Res::Err => None,
|
||||||
Res::Local(id) | Res::Upvar(id, ..) => {
|
Res::Local(id) => {
|
||||||
Some(self.tcx.hir().span_by_hir_id(id))
|
Some(self.tcx.hir().span_by_hir_id(id))
|
||||||
},
|
},
|
||||||
_ => def
|
_ => def
|
||||||
|
|
|
@ -5264,7 +5264,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
Err(ErrorReported) => return (tcx.types.err, res),
|
Err(ErrorReported) => return (tcx.types.err, res),
|
||||||
};
|
};
|
||||||
let path_segs = match res {
|
let path_segs = match res {
|
||||||
Res::Local(_) | Res::Upvar(..) => Vec::new(),
|
Res::Local(_) => vec![],
|
||||||
Res::Def(kind, def_id) =>
|
Res::Def(kind, def_id) =>
|
||||||
AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id),
|
AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id),
|
||||||
_ => bug!("instantiate_value_path on {:?}", res),
|
_ => bug!("instantiate_value_path on {:?}", res),
|
||||||
|
@ -5325,14 +5325,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
match res {
|
if let Res::Local(hid) = res {
|
||||||
Res::Local(hid) | Res::Upvar(hid, ..) => {
|
let ty = self.local_ty(span, hid).decl_ty;
|
||||||
let ty = self.local_ty(span, hid).decl_ty;
|
let ty = self.normalize_associated_types_in(span, &ty);
|
||||||
let ty = self.normalize_associated_types_in(span, &ty);
|
self.write_ty(hir_id, ty);
|
||||||
self.write_ty(hir_id, ty);
|
return (ty, res);
|
||||||
return (ty, res);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if generics_has_err {
|
if generics_has_err {
|
||||||
|
|
|
@ -200,6 +200,7 @@ pub struct RegionCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||||
|
|
||||||
// id of innermost fn body id
|
// id of innermost fn body id
|
||||||
body_id: hir::HirId,
|
body_id: hir::HirId,
|
||||||
|
body_owner: DefId,
|
||||||
|
|
||||||
// call_site scope of innermost fn
|
// call_site scope of innermost fn
|
||||||
call_site_scope: Option<region::Scope>,
|
call_site_scope: Option<region::Scope>,
|
||||||
|
@ -236,6 +237,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
region_scope_tree,
|
region_scope_tree,
|
||||||
repeating_scope: initial_repeating_scope,
|
repeating_scope: initial_repeating_scope,
|
||||||
body_id: initial_body_id,
|
body_id: initial_body_id,
|
||||||
|
body_owner: subject,
|
||||||
call_site_scope: None,
|
call_site_scope: None,
|
||||||
subject_def_id: subject,
|
subject_def_id: subject,
|
||||||
outlives_environment,
|
outlives_environment,
|
||||||
|
@ -308,6 +310,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let body_id = body.id();
|
let body_id = body.id();
|
||||||
self.body_id = body_id.hir_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 {
|
let call_site = region::Scope {
|
||||||
id: body.value.hir_id.local_id,
|
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
|
// Save state of current function before invoking
|
||||||
// `visit_fn_body`. We will restore afterwards.
|
// `visit_fn_body`. We will restore afterwards.
|
||||||
let old_body_id = self.body_id;
|
let old_body_id = self.body_id;
|
||||||
|
let old_body_owner = self.body_owner;
|
||||||
let old_call_site_scope = self.call_site_scope;
|
let old_call_site_scope = self.call_site_scope;
|
||||||
let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
|
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);
|
.pop_snapshot_post_closure(env_snapshot);
|
||||||
self.call_site_scope = old_call_site_scope;
|
self.call_site_scope = old_call_site_scope;
|
||||||
self.body_id = old_body_id;
|
self.body_id = old_body_id;
|
||||||
|
self.body_owner = old_body_owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
//visit_pat: visit_pat, // (..) see above
|
//visit_pat: visit_pat, // (..) see above
|
||||||
|
@ -829,6 +834,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
{
|
{
|
||||||
f(mc::MemCategorizationContext::with_infer(
|
f(mc::MemCategorizationContext::with_infer(
|
||||||
&self.infcx,
|
&self.infcx,
|
||||||
|
self.body_owner,
|
||||||
&self.region_scope_tree,
|
&self.region_scope_tree,
|
||||||
&self.tables.borrow(),
|
&self.tables.borrow(),
|
||||||
))
|
))
|
||||||
|
|
|
@ -41,6 +41,7 @@ use rustc::hir::def_id::LocalDefId;
|
||||||
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
|
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||||
use rustc::infer::UpvarRegion;
|
use rustc::infer::UpvarRegion;
|
||||||
use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts};
|
use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts};
|
||||||
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::Span;
|
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) {
|
if let Some(upvars) = self.tcx.upvars(closure_def_id) {
|
||||||
let mut upvar_list: Vec<ty::UpvarId> = Vec::with_capacity(upvars.len());
|
let mut upvar_list: FxIndexMap<hir::HirId, ty::UpvarId> =
|
||||||
for upvar in upvars.iter() {
|
FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default());
|
||||||
|
for (&var_hir_id, _) in upvars.iter() {
|
||||||
let upvar_id = ty::UpvarId {
|
let upvar_id = ty::UpvarId {
|
||||||
var_path: ty::UpvarPath {
|
var_path: ty::UpvarPath {
|
||||||
hir_id: upvar.var_id(),
|
hir_id: var_hir_id,
|
||||||
},
|
},
|
||||||
closure_expr_id: LocalDefId::from_def_id(closure_def_id),
|
closure_expr_id: LocalDefId::from_def_id(closure_def_id),
|
||||||
};
|
};
|
||||||
debug!("seed upvar_id {:?}", upvar_id);
|
debug!("seed upvar_id {:?}", upvar_id);
|
||||||
// Adding the upvar Id to the list of Upvars, which will be added
|
// 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.
|
// 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 {
|
let capture_kind = match capture_clause {
|
||||||
hir::CaptureByValue => ty::UpvarCapture::ByValue,
|
hir::CaptureByValue => ty::UpvarCapture::ByValue,
|
||||||
|
@ -165,6 +167,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id());
|
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 region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id);
|
||||||
let mut delegate = InferBorrowKind {
|
let mut delegate = InferBorrowKind {
|
||||||
fcx: self,
|
fcx: self,
|
||||||
|
@ -176,6 +179,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
euv::ExprUseVisitor::with_infer(
|
euv::ExprUseVisitor::with_infer(
|
||||||
&mut delegate,
|
&mut delegate,
|
||||||
&self.infcx,
|
&self.infcx,
|
||||||
|
body_owner_def_id,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
region_scope_tree,
|
region_scope_tree,
|
||||||
&self.tables.borrow(),
|
&self.tables.borrow(),
|
||||||
|
@ -249,8 +253,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
tcx.upvars(closure_def_id).iter().flat_map(|upvars| {
|
tcx.upvars(closure_def_id).iter().flat_map(|upvars| {
|
||||||
upvars
|
upvars
|
||||||
.iter()
|
.iter()
|
||||||
.map(|upvar| {
|
.map(|(&var_hir_id, _)| {
|
||||||
let var_hir_id = upvar.var_id();
|
|
||||||
let upvar_ty = self.node_ty(var_hir_id);
|
let upvar_ty = self.node_ty(var_hir_id);
|
||||||
let upvar_id = ty::UpvarId {
|
let upvar_id = ty::UpvarId {
|
||||||
var_path: ty::UpvarPath { hir_id: var_hir_id },
|
var_path: ty::UpvarPath { hir_id: var_hir_id },
|
||||||
|
|
|
@ -54,7 +54,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
wbcx.visit_body(body);
|
wbcx.visit_body(body);
|
||||||
wbcx.visit_upvar_capture_map();
|
wbcx.visit_upvar_capture_map();
|
||||||
wbcx.visit_upvar_list_map();
|
|
||||||
wbcx.visit_closures();
|
wbcx.visit_closures();
|
||||||
wbcx.visit_liberated_fn_sigs();
|
wbcx.visit_liberated_fn_sigs();
|
||||||
wbcx.visit_fru_field_types();
|
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.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();
|
wbcx.tables.tainted_by_errors = self.is_tainted_by_errors();
|
||||||
|
|
||||||
debug!(
|
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) {
|
fn visit_closures(&mut self) {
|
||||||
let fcx_tables = self.fcx.tables.borrow();
|
let fcx_tables = self.fcx.tables.borrow();
|
||||||
debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
|
debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
|
||||||
|
|
|
@ -10,4 +10,5 @@ path = "lib.rs"
|
||||||
crate-type = ["dylib", "rlib"]
|
crate-type = ["dylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
indexmap = "1"
|
||||||
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
||||||
|
|
|
@ -217,6 +217,75 @@ impl<T, S> Decodable for HashSet<T, S>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<K, V, S> Encodable for indexmap::IndexMap<K, V, S>
|
||||||
|
where K: Encodable + Hash + Eq,
|
||||||
|
V: Encodable,
|
||||||
|
S: BuildHasher,
|
||||||
|
{
|
||||||
|
fn encode<E: Encoder>(&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<K, V, S> Decodable for indexmap::IndexMap<K, V, S>
|
||||||
|
where K: Decodable + Hash + Eq,
|
||||||
|
V: Decodable,
|
||||||
|
S: BuildHasher + Default,
|
||||||
|
{
|
||||||
|
fn decode<D: Decoder>(d: &mut D) -> Result<indexmap::IndexMap<K, V, S>, 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<T, S> Encodable for indexmap::IndexSet<T, S>
|
||||||
|
where T: Encodable + Hash + Eq,
|
||||||
|
S: BuildHasher,
|
||||||
|
{
|
||||||
|
fn encode<E: Encoder>(&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<T, S> Decodable for indexmap::IndexSet<T, S>
|
||||||
|
where T: Decodable + Hash + Eq,
|
||||||
|
S: BuildHasher + Default,
|
||||||
|
{
|
||||||
|
fn decode<D: Decoder>(d: &mut D) -> Result<indexmap::IndexSet<T, S>, 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<T: Encodable> Encodable for Rc<[T]> {
|
impl<T: Encodable> Encodable for Rc<[T]> {
|
||||||
fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
|
fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
|
||||||
s.emit_seq(self.len(), |s| {
|
s.emit_seq(self.len(), |s| {
|
||||||
|
|
|
@ -4,7 +4,7 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as m
|
||||||
LL | let mut test = |foo: &Foo| {
|
LL | let mut test = |foo: &Foo| {
|
||||||
| ----------- mutable borrow occurs here
|
| ----------- mutable borrow occurs here
|
||||||
LL | ptr = box Foo { x: ptr.x + 1 };
|
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 | };
|
||||||
LL | test(&*ptr);
|
LL | test(&*ptr);
|
||||||
| ---- ^^^^^ immutable borrow occurs here
|
| ---- ^^^^^ immutable borrow occurs here
|
||||||
|
|
|
@ -5,7 +5,7 @@ LL | let mut test = |foo: &Foo| {
|
||||||
| ----------- mutable borrow occurs here
|
| ----------- mutable borrow occurs here
|
||||||
LL | println!("access {}", foo.x);
|
LL | println!("access {}", foo.x);
|
||||||
LL | ptr = box Foo { x: ptr.x + 1 };
|
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);
|
LL | test(&*ptr);
|
||||||
| ---- ^^^^^ immutable borrow occurs here
|
| ---- ^^^^^ immutable borrow occurs here
|
||||||
|
|
|
@ -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 [
|
= note: defining type: DefId(0:14 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [
|
||||||
i16,
|
i16,
|
||||||
extern "rust-call" fn(()),
|
extern "rust-call" fn(()),
|
||||||
&'_#1r mut &'_#2r i32,
|
&'_#1r i32,
|
||||||
&'_#3r i32,
|
&'_#2r mut &'_#3r i32,
|
||||||
]
|
]
|
||||||
= note: number of external vids: 4
|
= note: number of external vids: 4
|
||||||
= note: where '_#3r: '_#2r
|
= note: where '_#1r: '_#3r
|
||||||
|
|
||||||
note: External requirements
|
note: External requirements
|
||||||
--> $DIR/escape-upvar-nested.rs:20:27
|
--> $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 [
|
= note: defining type: DefId(0:13 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]) with closure substs [
|
||||||
i16,
|
i16,
|
||||||
extern "rust-call" fn(()),
|
extern "rust-call" fn(()),
|
||||||
&'_#1r mut &'_#2r i32,
|
&'_#1r i32,
|
||||||
&'_#3r i32,
|
&'_#2r mut &'_#3r i32,
|
||||||
]
|
]
|
||||||
= note: number of external vids: 4
|
= note: number of external vids: 4
|
||||||
= note: where '_#3r: '_#2r
|
= note: where '_#1r: '_#3r
|
||||||
|
|
||||||
note: No external requirements
|
note: No external requirements
|
||||||
--> $DIR/escape-upvar-nested.rs:13:1
|
--> $DIR/escape-upvar-nested.rs:13:1
|
||||||
|
|
|
@ -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 [
|
= note: defining type: DefId(0:13 ~ escape_upvar_ref[317d]::test[0]::{{closure}}[0]) with closure substs [
|
||||||
i16,
|
i16,
|
||||||
extern "rust-call" fn(()),
|
extern "rust-call" fn(()),
|
||||||
&'_#1r mut &'_#2r i32,
|
&'_#1r i32,
|
||||||
&'_#3r i32,
|
&'_#2r mut &'_#3r i32,
|
||||||
]
|
]
|
||||||
= note: number of external vids: 4
|
= note: number of external vids: 4
|
||||||
= note: where '_#3r: '_#2r
|
= note: where '_#1r: '_#3r
|
||||||
|
|
||||||
note: No external requirements
|
note: No external requirements
|
||||||
--> $DIR/escape-upvar-ref.rs:17:1
|
--> $DIR/escape-upvar-ref.rs:17:1
|
||||||
|
|
|
@ -92,6 +92,7 @@ const WHITELIST: &[Crate<'_>] = &[
|
||||||
Crate("fuchsia-zircon-sys"),
|
Crate("fuchsia-zircon-sys"),
|
||||||
Crate("getopts"),
|
Crate("getopts"),
|
||||||
Crate("humantime"),
|
Crate("humantime"),
|
||||||
|
Crate("indexmap"),
|
||||||
Crate("itertools"),
|
Crate("itertools"),
|
||||||
Crate("jobserver"),
|
Crate("jobserver"),
|
||||||
Crate("kernel32-sys"),
|
Crate("kernel32-sys"),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue