Skip to content

Commit 5feb4d0

Browse files
committed
Refactor code to keep most drop range analysis in drop_ranges.rs
1 parent 904c270 commit 5feb4d0

File tree

2 files changed

+283
-282
lines changed

2 files changed

+283
-282
lines changed

compiler/rustc_typeck/src/check/generator_interior.rs

Lines changed: 8 additions & 280 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@
33
//! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the
44
//! types computed here.
55
6-
use crate::expr_use_visitor::{self, ExprUseVisitor};
7-
8-
use self::drop_ranges::DropRanges;
9-
6+
use self::drop_ranges::{DropRangeVisitor, DropRanges, ExprUseDelegate};
107
use super::FnCtxt;
11-
use hir::{HirIdMap, Node};
8+
use crate::expr_use_visitor::ExprUseVisitor;
129
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
1310
use rustc_errors::pluralize;
1411
use rustc_hir as hir;
@@ -17,8 +14,6 @@ use rustc_hir::def_id::DefId;
1714
use rustc_hir::hir_id::HirIdSet;
1815
use rustc_hir::intravisit::{self, Visitor};
1916
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
20-
use rustc_middle::hir::map::Map;
21-
use rustc_middle::hir::place::{Place, PlaceBase};
2217
use rustc_middle::middle::region::{self, YieldData};
2318
use rustc_middle::ty::{self, Ty, TyCtxt};
2419
use rustc_span::symbol::sym;
@@ -194,11 +189,7 @@ pub fn resolve_interior<'a, 'tcx>(
194189
let body = fcx.tcx.hir().body(body_id);
195190

196191
let mut visitor = {
197-
let mut expr_use_visitor = ExprUseDelegate {
198-
hir: fcx.tcx.hir(),
199-
consumed_places: <_>::default(),
200-
borrowed_places: <_>::default(),
201-
};
192+
let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx.hir());
202193

203194
// Run ExprUseVisitor to find where values are consumed.
204195
ExprUseVisitor::new(
@@ -211,14 +202,14 @@ pub fn resolve_interior<'a, 'tcx>(
211202
.consume_body(body);
212203

213204
let region_scope_tree = fcx.tcx.region_scope_tree(def_id);
214-
215-
let mut drop_range_visitor = DropRangeVisitor::from(
205+
let mut drop_range_visitor = DropRangeVisitor::from_uses(
216206
expr_use_visitor,
217207
region_scope_tree.body_expr_count(body.id()).unwrap_or(0),
218208
);
219209
intravisit::walk_body(&mut drop_range_visitor, body);
220210

221-
drop_range_visitor.drop_ranges.propagate_to_fixpoint();
211+
let mut drop_ranges = drop_range_visitor.into_drop_ranges();
212+
drop_ranges.propagate_to_fixpoint();
222213

223214
InteriorVisitor {
224215
fcx,
@@ -230,7 +221,7 @@ pub fn resolve_interior<'a, 'tcx>(
230221
guard_bindings: <_>::default(),
231222
guard_bindings_set: <_>::default(),
232223
linted_values: <_>::default(),
233-
drop_ranges: drop_range_visitor.drop_ranges,
224+
drop_ranges: drop_ranges,
234225
}
235226
};
236227
intravisit::walk_body(&mut visitor, body);
@@ -377,7 +368,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
377368
self.expr_count += 1;
378369

379370
// Record the rest of the call expression normally.
380-
for arg in args.iter() {
371+
for arg in *args {
381372
self.visit_expr(arg);
382373
}
383374
}
@@ -664,266 +655,3 @@ fn check_must_not_suspend_def(
664655
}
665656
false
666657
}
667-
668-
// The following structs and impls are used for drop range analysis.
669-
//
670-
// Drop range analysis finds the portions of the tree where a value is guaranteed to be dropped
671-
// (i.e. moved, uninitialized, etc.). This is used to exclude the types of those values from the
672-
// generator type. See `InteriorVisitor::record` for where the results of this analysis are used.
673-
//
674-
// There are three phases to this analysis:
675-
// 1. Use `ExprUseVisitor` to identify the interesting values that are consumed and borrowed.
676-
// 2. Use `DropRangeVisitor` to find where the interesting values are dropped or reinitialized,
677-
// and also build a control flow graph.
678-
// 3. Use `DropRanges::propagate_to_fixpoint` to flow the dropped/reinitialized information through
679-
// the CFG and find the exact points where we know a value is definitely dropped.
680-
//
681-
// The end result is a data structure that maps the post-order index of each node in the HIR tree
682-
// to a set of values that are known to be dropped at that location.
683-
684-
/// Works with ExprUseVisitor to find interesting values for the drop range analysis.
685-
///
686-
/// Interesting values are those that are either dropped or borrowed. For dropped values, we also
687-
/// record the parent expression, which is the point where the drop actually takes place.
688-
struct ExprUseDelegate<'tcx> {
689-
hir: Map<'tcx>,
690-
/// Maps a HirId to a set of HirIds that are dropped by that node.
691-
consumed_places: HirIdMap<HirIdSet>,
692-
borrowed_places: HirIdSet,
693-
}
694-
695-
impl<'tcx> ExprUseDelegate<'tcx> {
696-
fn mark_consumed(&mut self, consumer: HirId, target: HirId) {
697-
if !self.consumed_places.contains_key(&consumer) {
698-
self.consumed_places.insert(consumer, <_>::default());
699-
}
700-
self.consumed_places.get_mut(&consumer).map(|places| places.insert(target));
701-
}
702-
}
703-
704-
impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
705-
fn consume(
706-
&mut self,
707-
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
708-
diag_expr_id: hir::HirId,
709-
) {
710-
let parent = match self.hir.find_parent_node(place_with_id.hir_id) {
711-
Some(parent) => parent,
712-
None => place_with_id.hir_id,
713-
};
714-
debug!(
715-
"consume {:?}; diag_expr_id={:?}, using parent {:?}",
716-
place_with_id, diag_expr_id, parent
717-
);
718-
self.mark_consumed(parent, place_with_id.hir_id);
719-
place_hir_id(&place_with_id.place).map(|place| self.mark_consumed(parent, place));
720-
}
721-
722-
fn borrow(
723-
&mut self,
724-
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
725-
_diag_expr_id: hir::HirId,
726-
_bk: rustc_middle::ty::BorrowKind,
727-
) {
728-
place_hir_id(&place_with_id.place).map(|place| self.borrowed_places.insert(place));
729-
}
730-
731-
fn mutate(
732-
&mut self,
733-
_assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
734-
_diag_expr_id: hir::HirId,
735-
) {
736-
}
737-
738-
fn fake_read(
739-
&mut self,
740-
_place: expr_use_visitor::Place<'tcx>,
741-
_cause: rustc_middle::mir::FakeReadCause,
742-
_diag_expr_id: hir::HirId,
743-
) {
744-
}
745-
}
746-
747-
/// Gives the hir_id associated with a place if one exists. This is the hir_id that we want to
748-
/// track for a value in the drop range analysis.
749-
fn place_hir_id(place: &Place<'_>) -> Option<HirId> {
750-
match place.base {
751-
PlaceBase::Rvalue | PlaceBase::StaticItem => None,
752-
PlaceBase::Local(hir_id)
753-
| PlaceBase::Upvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id }, .. }) => Some(hir_id),
754-
}
755-
}
756-
757-
/// This struct is used to gather the information for `DropRanges` to determine the regions of the
758-
/// HIR tree for which a value is dropped.
759-
///
760-
/// We are interested in points where a variables is dropped or initialized, and the control flow
761-
/// of the code. We identify locations in code by their post-order traversal index, so it is
762-
/// important for this traversal to match that in `RegionResolutionVisitor` and `InteriorVisitor`.
763-
struct DropRangeVisitor<'tcx> {
764-
hir: Map<'tcx>,
765-
/// Maps a HirId to a set of HirIds that are dropped by that node.
766-
consumed_places: HirIdMap<HirIdSet>,
767-
borrowed_places: HirIdSet,
768-
drop_ranges: DropRanges,
769-
expr_count: usize,
770-
}
771-
772-
impl<'tcx> DropRangeVisitor<'tcx> {
773-
fn from(uses: ExprUseDelegate<'tcx>, num_exprs: usize) -> Self {
774-
debug!("consumed_places: {:?}", uses.consumed_places);
775-
let drop_ranges = DropRanges::new(
776-
uses.consumed_places.iter().flat_map(|(_, places)| places.iter().copied()),
777-
&uses.hir,
778-
num_exprs,
779-
);
780-
Self {
781-
hir: uses.hir,
782-
consumed_places: uses.consumed_places,
783-
borrowed_places: uses.borrowed_places,
784-
drop_ranges,
785-
expr_count: 0,
786-
}
787-
}
788-
789-
fn record_drop(&mut self, hir_id: HirId) {
790-
if self.borrowed_places.contains(&hir_id) {
791-
debug!("not marking {:?} as dropped because it is borrowed at some point", hir_id);
792-
} else {
793-
debug!("marking {:?} as dropped at {}", hir_id, self.expr_count);
794-
let count = self.expr_count;
795-
self.drop_ranges.drop_at(hir_id, count);
796-
}
797-
}
798-
799-
/// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
800-
/// expressions. This method consumes a little deeper into the expression when needed.
801-
fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
802-
debug!("consuming expr {:?}, count={}", expr.hir_id, self.expr_count);
803-
let places = self
804-
.consumed_places
805-
.get(&expr.hir_id)
806-
.map_or(vec![], |places| places.iter().cloned().collect());
807-
for place in places {
808-
for_each_consumable(place, self.hir.find(place), |hir_id| self.record_drop(hir_id));
809-
}
810-
}
811-
812-
fn reinit_expr(&mut self, expr: &hir::Expr<'_>) {
813-
if let ExprKind::Path(hir::QPath::Resolved(
814-
_,
815-
hir::Path { res: hir::def::Res::Local(hir_id), .. },
816-
)) = expr.kind
817-
{
818-
let location = self.expr_count;
819-
debug!("reinitializing {:?} at {}", hir_id, location);
820-
self.drop_ranges.reinit_at(*hir_id, location);
821-
} else {
822-
debug!("reinitializing {:?} is not supported", expr);
823-
}
824-
}
825-
}
826-
827-
/// Applies `f` to consumable portion of a HIR node.
828-
///
829-
/// The `node` parameter should be the result of calling `Map::find(place)`.
830-
fn for_each_consumable(place: HirId, node: Option<Node<'_>>, mut f: impl FnMut(HirId)) {
831-
f(place);
832-
if let Some(Node::Expr(expr)) = node {
833-
match expr.kind {
834-
hir::ExprKind::Path(hir::QPath::Resolved(
835-
_,
836-
hir::Path { res: hir::def::Res::Local(hir_id), .. },
837-
)) => {
838-
f(*hir_id);
839-
}
840-
_ => (),
841-
}
842-
}
843-
}
844-
845-
impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
846-
type Map = intravisit::ErasedMap<'tcx>;
847-
848-
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
849-
NestedVisitorMap::None
850-
}
851-
852-
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
853-
let mut reinit = None;
854-
match expr.kind {
855-
ExprKind::If(test, if_true, if_false) => {
856-
self.visit_expr(test);
857-
858-
let fork = self.expr_count;
859-
860-
self.drop_ranges.add_control_edge(fork, self.expr_count + 1);
861-
self.visit_expr(if_true);
862-
let true_end = self.expr_count;
863-
864-
self.drop_ranges.add_control_edge(fork, self.expr_count + 1);
865-
if let Some(if_false) = if_false {
866-
self.visit_expr(if_false);
867-
}
868-
869-
self.drop_ranges.add_control_edge(true_end, self.expr_count + 1);
870-
}
871-
ExprKind::Assign(lhs, rhs, _) => {
872-
self.visit_expr(lhs);
873-
self.visit_expr(rhs);
874-
875-
reinit = Some(lhs);
876-
}
877-
ExprKind::Loop(body, ..) => {
878-
let loop_begin = self.expr_count + 1;
879-
self.visit_block(body);
880-
self.drop_ranges.add_control_edge(self.expr_count, loop_begin);
881-
}
882-
ExprKind::Match(scrutinee, arms, ..) => {
883-
self.visit_expr(scrutinee);
884-
885-
let fork = self.expr_count;
886-
let arm_end_ids = arms
887-
.iter()
888-
.map(|Arm { pat, body, guard, .. }| {
889-
self.drop_ranges.add_control_edge(fork, self.expr_count + 1);
890-
self.visit_pat(pat);
891-
match guard {
892-
Some(Guard::If(expr)) => self.visit_expr(expr),
893-
Some(Guard::IfLet(pat, expr)) => {
894-
self.visit_pat(pat);
895-
self.visit_expr(expr);
896-
}
897-
None => (),
898-
}
899-
self.visit_expr(body);
900-
self.expr_count
901-
})
902-
.collect::<Vec<_>>();
903-
arm_end_ids.into_iter().for_each(|arm_end| {
904-
self.drop_ranges.add_control_edge(arm_end, self.expr_count + 1)
905-
});
906-
}
907-
ExprKind::Break(hir::Destination { target_id: Ok(target), .. }, ..)
908-
| ExprKind::Continue(hir::Destination { target_id: Ok(target), .. }, ..) => {
909-
self.drop_ranges.add_control_edge_hir_id(self.expr_count, target);
910-
}
911-
912-
_ => intravisit::walk_expr(self, expr),
913-
}
914-
915-
self.expr_count += 1;
916-
self.drop_ranges.add_node_mapping(expr.hir_id, self.expr_count);
917-
self.consume_expr(expr);
918-
if let Some(expr) = reinit {
919-
self.reinit_expr(expr);
920-
}
921-
}
922-
923-
fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
924-
intravisit::walk_pat(self, pat);
925-
926-
// Increment expr_count here to match what InteriorVisitor expects.
927-
self.expr_count += 1;
928-
}
929-
}

0 commit comments

Comments
 (0)