Skip to content

Commit a54eefb

Browse files
jenniferwillslogmosierroxelo
committed
Replace closures_captures and upvar_capture with closure_min_captures
make changes to liveness to use closure_min_captures use different span borrow check uses new structures rename to CapturedPlace stop using upvar_capture in regionck remove the bridge cleanup from rebase + remove the upvar_capture reference from mutability_errors.rs remove line from livenes test make our unused var checking more consistent update tests adding more warnings to the tests move is_ancestor_or_same_capture to rustc_middle/ty update names to reflect the closures add FIXME check that all captures are immutable borrows before returning add surrounding if statement like the original move var out of the loop and rename Co-authored-by: Logan Mosier <[email protected]> Co-authored-by: Roxane Fruytier <[email protected]>
1 parent 8fd946c commit a54eefb

File tree

14 files changed

+478
-244
lines changed

14 files changed

+478
-244
lines changed

compiler/rustc_middle/src/ty/context.rs

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ use rustc_attr as attr;
3030
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
3131
use rustc_data_structures::profiling::SelfProfilerRef;
3232
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
33-
use rustc_data_structures::stable_hasher::{
34-
hash_stable_hashmap, HashStable, StableHasher, StableVec,
35-
};
33+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableVec};
3634
use rustc_data_structures::steal::Steal;
3735
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
3836
use rustc_errors::ErrorReported;
@@ -382,9 +380,6 @@ pub struct TypeckResults<'tcx> {
382380
/// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
383381
pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
384382

385-
/// Borrows
386-
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
387-
388383
/// Records the reasons that we picked the kind of each closure;
389384
/// not all closures are present in the map.
390385
closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
@@ -420,12 +415,6 @@ pub struct TypeckResults<'tcx> {
420415
/// by this function.
421416
pub concrete_opaque_types: FxHashMap<DefId, ResolvedOpaqueTy<'tcx>>,
422417

423-
/// Given the closure ID this map provides the list of UpvarIDs used by it.
424-
/// The upvarID contains the HIR node ID and it also contains the full path
425-
/// leading to the member of the struct or tuple that is used instead of the
426-
/// entire variable.
427-
pub closure_captures: ty::UpvarListMap,
428-
429418
/// Tracks the minimum captures required for a closure;
430419
/// see `MinCaptureInformationMap` for more details.
431420
pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
@@ -454,15 +443,13 @@ impl<'tcx> TypeckResults<'tcx> {
454443
adjustments: Default::default(),
455444
pat_binding_modes: Default::default(),
456445
pat_adjustments: Default::default(),
457-
upvar_capture_map: Default::default(),
458446
closure_kind_origins: Default::default(),
459447
liberated_fn_sigs: Default::default(),
460448
fru_field_types: Default::default(),
461449
coercion_casts: Default::default(),
462450
used_trait_imports: Lrc::new(Default::default()),
463451
tainted_by_errors: None,
464452
concrete_opaque_types: Default::default(),
465-
closure_captures: Default::default(),
466453
closure_min_captures: Default::default(),
467454
generator_interior_types: ty::Binder::dummy(Default::default()),
468455
treat_byte_string_as_slice: Default::default(),
@@ -646,10 +633,6 @@ impl<'tcx> TypeckResults<'tcx> {
646633
.flatten()
647634
}
648635

649-
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
650-
self.upvar_capture_map[&upvar_id]
651-
}
652-
653636
pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
654637
LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
655638
}
@@ -693,7 +676,7 @@ impl<'tcx> TypeckResults<'tcx> {
693676
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
694677
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
695678
let ty::TypeckResults {
696-
hir_owner,
679+
hir_owner: _,
697680
ref type_dependent_defs,
698681
ref field_indices,
699682
ref user_provided_types,
@@ -703,17 +686,13 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
703686
ref adjustments,
704687
ref pat_binding_modes,
705688
ref pat_adjustments,
706-
ref upvar_capture_map,
707689
ref closure_kind_origins,
708690
ref liberated_fn_sigs,
709691
ref fru_field_types,
710-
711692
ref coercion_casts,
712-
713693
ref used_trait_imports,
714694
tainted_by_errors,
715695
ref concrete_opaque_types,
716-
ref closure_captures,
717696
ref closure_min_captures,
718697
ref generator_interior_types,
719698
ref treat_byte_string_as_slice,
@@ -729,17 +708,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
729708
adjustments.hash_stable(hcx, hasher);
730709
pat_binding_modes.hash_stable(hcx, hasher);
731710
pat_adjustments.hash_stable(hcx, hasher);
732-
hash_stable_hashmap(hcx, hasher, upvar_capture_map, |up_var_id, hcx| {
733-
let ty::UpvarId { var_path, closure_expr_id } = *up_var_id;
734-
735-
assert_eq!(var_path.hir_id.owner, hir_owner);
736-
737-
(
738-
hcx.local_def_path_hash(var_path.hir_id.owner),
739-
var_path.hir_id.local_id,
740-
hcx.local_def_path_hash(closure_expr_id),
741-
)
742-
});
743711

744712
closure_kind_origins.hash_stable(hcx, hasher);
745713
liberated_fn_sigs.hash_stable(hcx, hasher);
@@ -748,7 +716,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
748716
used_trait_imports.hash_stable(hcx, hasher);
749717
tainted_by_errors.hash_stable(hcx, hasher);
750718
concrete_opaque_types.hash_stable(hcx, hasher);
751-
closure_captures.hash_stable(hcx, hasher);
752719
closure_min_captures.hash_stable(hcx, hasher);
753720
generator_interior_types.hash_stable(hcx, hasher);
754721
treat_byte_string_as_slice.hash_stable(hcx, hasher);

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,9 +678,59 @@ impl CapturedPlace<'tcx> {
678678
pub fn get_root_variable(&self) -> hir::HirId {
679679
match self.place.base {
680680
HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
681-
base => bug!("Expected upvar, found={:?}", base),
681+
base => bug!("expected upvar, found={:?}", base),
682682
}
683683
}
684+
685+
/// Returns the `LocalDefId` of the closure that captureed this Place
686+
pub fn get_closure_local_def_id(&self) -> LocalDefId {
687+
match self.place.base {
688+
HirPlaceBase::Upvar(upvar_id) => upvar_id.closure_expr_id,
689+
base => bug!("expected upvar, found={:?}", base),
690+
}
691+
}
692+
693+
/// Return span pointing to use that resulted in selecting the current capture kind
694+
pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span {
695+
if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
696+
tcx.hir().span(capture_kind_expr_id)
697+
} else if let Some(path_expr_id) = self.info.path_expr_id {
698+
tcx.hir().span(path_expr_id)
699+
} else {
700+
// Fallback on upvars mentioned if neither path or capture expr id is captured
701+
702+
// Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
703+
tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
704+
[&self.get_root_variable()]
705+
.span
706+
}
707+
}
708+
}
709+
710+
/// Return true if the `proj_possible_ancestor` represents an ancestor path
711+
/// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`,
712+
/// assuming they both start off of the same root variable.
713+
///
714+
/// **Note:** It's the caller's responsibility to ensure that both lists of projections
715+
/// start off of the same root variable.
716+
///
717+
/// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of
718+
/// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`.
719+
/// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`.
720+
/// 2. Since we only look at the projections here function will return `bar.x` as an a valid
721+
/// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
722+
/// list are being applied to the same root variable.
723+
pub fn is_ancestor_or_same_capture(
724+
proj_possible_ancestor: &[HirProjectionKind],
725+
proj_capture: &[HirProjectionKind],
726+
) -> bool {
727+
// We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
728+
// Therefore we can't just check if all projections are same in the zipped iterator below.
729+
if proj_possible_ancestor.len() > proj_capture.len() {
730+
return false;
731+
}
732+
733+
proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b)
684734
}
685735

686736
pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {

compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -388,10 +388,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
388388
// so it's safe to call `expect_local`.
389389
//
390390
// We know the field exists so it's safe to call operator[] and `unwrap` here.
391-
let (&var_id, _) =
392-
self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id]
393-
.get_index(field.index())
394-
.unwrap();
391+
let var_id = self
392+
.infcx
393+
.tcx
394+
.typeck(def_id.expect_local())
395+
.closure_min_captures_flattened(def_id)
396+
.nth(field.index())
397+
.unwrap()
398+
.get_root_variable();
395399

396400
self.infcx.tcx.hir().name(var_id).to_string()
397401
}
@@ -966,35 +970,35 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
966970
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
967971
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
968972
if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
969-
for (upvar_hir_id, place) in
970-
self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id]
971-
.keys()
972-
.zip(places)
973+
for (captured_place, place) in self
974+
.infcx
975+
.tcx
976+
.typeck(def_id.expect_local())
977+
.closure_min_captures_flattened(def_id)
978+
.zip(places)
973979
{
974-
let span = self.infcx.tcx.upvars_mentioned(local_did)?[upvar_hir_id].span;
980+
let upvar_hir_id = captured_place.get_root_variable();
981+
//FIXME(project-rfc-2229#8): Use better span from captured_place
982+
let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span;
975983
match place {
976984
Operand::Copy(place) | Operand::Move(place)
977985
if target_place == place.as_ref() =>
978986
{
979987
debug!("closure_span: found captured local {:?}", place);
980988
let body = self.infcx.tcx.hir().body(*body_id);
981989
let generator_kind = body.generator_kind();
982-
let upvar_id = ty::UpvarId {
983-
var_path: ty::UpvarPath { hir_id: *upvar_hir_id },
984-
closure_expr_id: local_did,
985-
};
986990

987991
// If we have a more specific span available, point to that.
988992
// We do this even though this span might be part of a borrow error
989993
// message rather than a move error message. Our goal is to point
990994
// to a span that shows why the upvar is used in the closure,
991995
// so a move-related span is as good as any (and potentially better,
992996
// if the overall error is due to a move of the upvar).
993-
let usage_span =
994-
match self.infcx.tcx.typeck(local_did).upvar_capture(upvar_id) {
995-
ty::UpvarCapture::ByValue(Some(span)) => span,
996-
_ => span,
997-
};
997+
998+
let usage_span = match captured_place.info.capture_kind {
999+
ty::UpvarCapture::ByValue(Some(span)) => span,
1000+
_ => span,
1001+
};
9981002
return Some((*args_span, generator_kind, usage_span));
9991003
}
10001004
_ => {}

compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -510,24 +510,54 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
510510
the_place_err: PlaceRef<'tcx>,
511511
err: &mut DiagnosticBuilder<'_>,
512512
) {
513-
let id = id.expect_local();
514-
let tables = tcx.typeck(id);
515-
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
516-
if let Some((span, place)) = tables.closure_kind_origins().get(hir_id) {
517-
let reason = if let PlaceBase::Upvar(upvar_id) = place.base {
518-
let upvar = ty::place_to_string_for_capture(tcx, place);
519-
match tables.upvar_capture(upvar_id) {
520-
ty::UpvarCapture::ByRef(ty::UpvarBorrow {
521-
kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
522-
..
523-
}) => {
524-
format!("mutable borrow of `{}`", upvar)
525-
}
526-
ty::UpvarCapture::ByValue(_) => {
527-
format!("possible mutation of `{}`", upvar)
513+
let closure_local_def_id = id.expect_local();
514+
let tables = tcx.typeck(closure_local_def_id);
515+
let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_local_def_id);
516+
if let Some((span, closure_kind_origin)) =
517+
&tables.closure_kind_origins().get(closure_hir_id)
518+
{
519+
let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
520+
let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
521+
let root_hir_id = upvar_id.var_path.hir_id;
522+
// we have a origin for this closure kind starting at this root variable so it's safe to unwrap here
523+
let captured_places = tables.closure_min_captures[id].get(&root_hir_id).unwrap();
524+
525+
let origin_projection = closure_kind_origin
526+
.projections
527+
.iter()
528+
.map(|proj| proj.kind)
529+
.collect::<Vec<_>>();
530+
let mut capture_reason = String::new();
531+
for captured_place in captured_places {
532+
let captured_place_kinds = captured_place
533+
.place
534+
.projections
535+
.iter()
536+
.map(|proj| proj.kind)
537+
.collect::<Vec<_>>();
538+
if rustc_middle::ty::is_ancestor_or_same_capture(
539+
&captured_place_kinds,
540+
&origin_projection,
541+
) {
542+
match captured_place.info.capture_kind {
543+
ty::UpvarCapture::ByRef(ty::UpvarBorrow {
544+
kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
545+
..
546+
}) => {
547+
capture_reason = format!("mutable borrow of `{}`", upvar);
548+
}
549+
ty::UpvarCapture::ByValue(_) => {
550+
capture_reason = format!("possible mutation of `{}`", upvar);
551+
}
552+
_ => bug!("upvar `{}` borrowed, but not mutably", upvar),
553+
}
554+
break;
528555
}
529-
val => bug!("upvar `{}` borrowed, but not mutably: {:?}", upvar, val),
530556
}
557+
if capture_reason.is_empty() {
558+
bug!("upvar `{}` borrowed, but cannot find reason", upvar);
559+
}
560+
capture_reason
531561
} else {
532562
bug!("not an upvar")
533563
};

compiler/rustc_mir/src/interpret/validity.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ macro_rules! throw_validation_failure {
7777
///
7878
macro_rules! try_validation {
7979
($e:expr, $where:expr,
80-
$( $( $p:pat )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)?
80+
$( $( $p:pat )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)?
8181
) => {{
8282
match $e {
8383
Ok(x) => x,
@@ -244,17 +244,20 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
244244
// generators and closures.
245245
ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
246246
let mut name = None;
247-
if let Some(def_id) = def_id.as_local() {
248-
let tables = self.ecx.tcx.typeck(def_id);
249-
if let Some(upvars) = tables.closure_captures.get(&def_id.to_def_id()) {
247+
// FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar
248+
// https://github.com/rust-lang/project-rfc-2229/issues/46
249+
if let Some(local_def_id) = def_id.as_local() {
250+
let tables = self.ecx.tcx.typeck(local_def_id);
251+
if let Some(captured_place) =
252+
tables.closure_min_captures_flattened(*def_id).nth(field)
253+
{
250254
// Sometimes the index is beyond the number of upvars (seen
251255
// for a generator).
252-
if let Some((&var_hir_id, _)) = upvars.get_index(field) {
253-
let node = self.ecx.tcx.hir().get(var_hir_id);
254-
if let hir::Node::Binding(pat) = node {
255-
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
256-
name = Some(ident.name);
257-
}
256+
let var_hir_id = captured_place.get_root_variable();
257+
let node = self.ecx.tcx.hir().get(var_hir_id);
258+
if let hir::Node::Binding(pat) = node {
259+
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
260+
name = Some(ident.name);
258261
}
259262
}
260263
}

compiler/rustc_mir_build/src/build/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
821821
let hir_typeck_results = self.hir.typeck_results();
822822

823823
// In analyze_closure() in upvar.rs we gathered a list of upvars used by a
824-
// indexed closure and we stored in a map called closure_captures in TypeckResults
824+
// indexed closure and we stored in a map called closure_min_captures in TypeckResults
825825
// with the closure's DefId. Here, we run through that vec of UpvarIds for
826826
// the given closure and use the necessary information to create upvar
827827
// debuginfo and to fill `self.upvar_mutbls`.

0 commit comments

Comments
 (0)