Pass InferCtxt to DropRangeVisitor so we can resolve vars
This commit is contained in:
parent
66ccf36f16
commit
1e7f6a7e0d
4 changed files with 201 additions and 23 deletions
|
@ -9,9 +9,10 @@ use hir::{
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_middle::{
|
use rustc_middle::{
|
||||||
hir::map::Map,
|
hir::map::Map,
|
||||||
ty::{TyCtxt, TypeckResults},
|
ty::{TyCtxt, TypeVisitable, TypeckResults},
|
||||||
};
|
};
|
||||||
use std::mem::swap;
|
use std::mem::swap;
|
||||||
|
|
||||||
|
@ -21,20 +22,23 @@ use std::mem::swap;
|
||||||
/// The resulting structure still needs to be iterated to a fixed point, which
|
/// The resulting structure still needs to be iterated to a fixed point, which
|
||||||
/// can be done with propagate_to_fixpoint in cfg_propagate.
|
/// can be done with propagate_to_fixpoint in cfg_propagate.
|
||||||
pub(super) fn build_control_flow_graph<'tcx>(
|
pub(super) fn build_control_flow_graph<'tcx>(
|
||||||
hir: Map<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
typeck_results: &TypeckResults<'tcx>,
|
typeck_results: &TypeckResults<'tcx>,
|
||||||
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
|
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
|
||||||
body: &'tcx Body<'tcx>,
|
body: &'tcx Body<'tcx>,
|
||||||
num_exprs: usize,
|
num_exprs: usize,
|
||||||
) -> (DropRangesBuilder, FxHashSet<HirId>) {
|
) -> (DropRangesBuilder, FxHashSet<HirId>) {
|
||||||
let mut drop_range_visitor =
|
let mut drop_range_visitor =
|
||||||
DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
|
DropRangeVisitor::new(infcx, typeck_results, consumed_borrowed_places, num_exprs);
|
||||||
intravisit::walk_body(&mut drop_range_visitor, body);
|
intravisit::walk_body(&mut drop_range_visitor, body);
|
||||||
|
|
||||||
drop_range_visitor.drop_ranges.process_deferred_edges();
|
drop_range_visitor.drop_ranges.process_deferred_edges();
|
||||||
if let Some(filename) = &tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
|
if let Some(filename) = &infcx.tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
|
||||||
super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
|
super::cfg_visualize::write_graph_to_file(
|
||||||
|
&drop_range_visitor.drop_ranges,
|
||||||
|
filename,
|
||||||
|
infcx.tcx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
|
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
|
||||||
|
@ -82,19 +86,17 @@ pub(super) fn build_control_flow_graph<'tcx>(
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
struct DropRangeVisitor<'a, 'tcx> {
|
struct DropRangeVisitor<'a, 'tcx> {
|
||||||
hir: Map<'tcx>,
|
typeck_results: &'a TypeckResults<'tcx>,
|
||||||
|
infcx: &'a InferCtxt<'tcx>,
|
||||||
places: ConsumedAndBorrowedPlaces,
|
places: ConsumedAndBorrowedPlaces,
|
||||||
drop_ranges: DropRangesBuilder,
|
drop_ranges: DropRangesBuilder,
|
||||||
expr_index: PostOrderId,
|
expr_index: PostOrderId,
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
typeck_results: &'a TypeckResults<'tcx>,
|
|
||||||
label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
|
label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
||||||
fn new(
|
fn new(
|
||||||
hir: Map<'tcx>,
|
infcx: &'a InferCtxt<'tcx>,
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
typeck_results: &'a TypeckResults<'tcx>,
|
typeck_results: &'a TypeckResults<'tcx>,
|
||||||
places: ConsumedAndBorrowedPlaces,
|
places: ConsumedAndBorrowedPlaces,
|
||||||
num_exprs: usize,
|
num_exprs: usize,
|
||||||
|
@ -102,20 +104,23 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
||||||
debug!("consumed_places: {:?}", places.consumed);
|
debug!("consumed_places: {:?}", places.consumed);
|
||||||
let drop_ranges = DropRangesBuilder::new(
|
let drop_ranges = DropRangesBuilder::new(
|
||||||
places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
|
places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
|
||||||
hir,
|
infcx.tcx.hir(),
|
||||||
num_exprs,
|
num_exprs,
|
||||||
);
|
);
|
||||||
Self {
|
Self {
|
||||||
hir,
|
infcx,
|
||||||
|
typeck_results,
|
||||||
places,
|
places,
|
||||||
drop_ranges,
|
drop_ranges,
|
||||||
expr_index: PostOrderId::from_u32(0),
|
expr_index: PostOrderId::from_u32(0),
|
||||||
typeck_results,
|
|
||||||
tcx,
|
|
||||||
label_stack: vec![],
|
label_stack: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
|
self.infcx.tcx
|
||||||
|
}
|
||||||
|
|
||||||
fn record_drop(&mut self, value: TrackedValue) {
|
fn record_drop(&mut self, value: TrackedValue) {
|
||||||
if self.places.borrowed.contains(&value) {
|
if self.places.borrowed.contains(&value) {
|
||||||
debug!("not marking {:?} as dropped because it is borrowed at some point", value);
|
debug!("not marking {:?} as dropped because it is borrowed at some point", value);
|
||||||
|
@ -137,7 +142,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
||||||
.map_or(vec![], |places| places.iter().cloned().collect());
|
.map_or(vec![], |places| places.iter().cloned().collect());
|
||||||
for place in places {
|
for place in places {
|
||||||
trace!(?place, "consuming place");
|
trace!(?place, "consuming place");
|
||||||
for_each_consumable(self.hir, place, |value| self.record_drop(value));
|
for_each_consumable(self.tcx().hir(), place, |value| self.record_drop(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,10 +219,16 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
||||||
/// return.
|
/// return.
|
||||||
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
|
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
|
||||||
let ty = self.typeck_results.expr_ty(expr);
|
let ty = self.typeck_results.expr_ty(expr);
|
||||||
let ty = self.tcx.erase_regions(ty);
|
let ty = self.infcx.resolve_vars_if_possible(ty);
|
||||||
let m = self.tcx.parent_module(expr.hir_id).to_def_id();
|
let ty = self.tcx().erase_regions(ty);
|
||||||
let param_env = self.tcx.param_env(m.expect_local());
|
let m = self.tcx().parent_module(expr.hir_id).to_def_id();
|
||||||
if !ty.is_inhabited_from(self.tcx, m, param_env) {
|
let param_env = self.tcx().param_env(m.expect_local());
|
||||||
|
if ty.has_non_region_infer() {
|
||||||
|
self.tcx()
|
||||||
|
.sess
|
||||||
|
.delay_span_bug(expr.span, format!("could not resolve infer vars in `{ty}`"));
|
||||||
|
}
|
||||||
|
if !ty.is_inhabited_from(self.tcx(), m, param_env) {
|
||||||
// This function will not return. We model this fact as an infinite loop.
|
// This function will not return. We model this fact as an infinite loop.
|
||||||
self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
|
self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
|
||||||
}
|
}
|
||||||
|
@ -238,7 +249,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
||||||
destination: hir::Destination,
|
destination: hir::Destination,
|
||||||
) -> Result<HirId, LoopIdError> {
|
) -> Result<HirId, LoopIdError> {
|
||||||
destination.target_id.map(|target| {
|
destination.target_id.map(|target| {
|
||||||
let node = self.hir.get(target);
|
let node = self.tcx().hir().get(target);
|
||||||
match node {
|
match node {
|
||||||
hir::Node::Expr(_) => target,
|
hir::Node::Expr(_) => target,
|
||||||
hir::Node::Block(b) => find_last_block_expression(b),
|
hir::Node::Block(b) => find_last_block_expression(b),
|
||||||
|
|
|
@ -43,8 +43,7 @@ pub fn compute_drop_ranges<'a, 'tcx>(
|
||||||
let typeck_results = &fcx.typeck_results.borrow();
|
let typeck_results = &fcx.typeck_results.borrow();
|
||||||
let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
|
let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
|
||||||
let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
|
let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
|
||||||
fcx.tcx.hir(),
|
&fcx,
|
||||||
fcx.tcx,
|
|
||||||
typeck_results,
|
typeck_results,
|
||||||
consumed_borrowed_places,
|
consumed_borrowed_places,
|
||||||
body,
|
body,
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
// compile-flags: -Zdrop-tracking
|
||||||
|
// incremental
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
use std::future::*;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::*;
|
||||||
|
|
||||||
|
fn send<T: Send>(_: T) {}
|
||||||
|
|
||||||
|
pub trait Stream {
|
||||||
|
type Item;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Empty<T>(PhantomData<fn() -> T>);
|
||||||
|
|
||||||
|
impl<T> Stream for Empty<T> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FnOnce1<A> {
|
||||||
|
type Output;
|
||||||
|
fn call_once(self, arg: A) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, A, R> FnOnce1<A> for T
|
||||||
|
where
|
||||||
|
T: FnOnce(A) -> R,
|
||||||
|
{
|
||||||
|
type Output = R;
|
||||||
|
fn call_once(self, arg: A) -> R {
|
||||||
|
self(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FnMut1<A>: FnOnce1<A> {
|
||||||
|
fn call_mut(&mut self, arg: A) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, A, R> FnMut1<A> for T
|
||||||
|
where
|
||||||
|
T: FnMut(A) -> R,
|
||||||
|
{
|
||||||
|
fn call_mut(&mut self, arg: A) -> R {
|
||||||
|
self(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Map<St, F>(St, F);
|
||||||
|
|
||||||
|
impl<St, F> Stream for Map<St, F>
|
||||||
|
where
|
||||||
|
St: Stream,
|
||||||
|
F: FnMut1<St::Item>,
|
||||||
|
{
|
||||||
|
type Item = F::Output;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FuturesOrdered<T: Future>(PhantomData<fn() -> T::Output>);
|
||||||
|
|
||||||
|
pub struct Buffered<St: Stream>(St, FuturesOrdered<St::Item>, usize)
|
||||||
|
where
|
||||||
|
St::Item: Future;
|
||||||
|
|
||||||
|
impl<St> Stream for Buffered<St>
|
||||||
|
where
|
||||||
|
St: Stream,
|
||||||
|
St::Item: Future,
|
||||||
|
{
|
||||||
|
type Item = <St::Item as Future>::Output;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Next<'a, T: ?Sized>(&'a T);
|
||||||
|
|
||||||
|
impl<St: ?Sized + Stream + Unpin> Future for Next<'_, St> {
|
||||||
|
type Output = Option<St::Item>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
send(async {
|
||||||
|
//~^ ERROR implementation of `FnOnce` is not general enough
|
||||||
|
//~| ERROR implementation of `FnOnce` is not general enough
|
||||||
|
//~| ERROR implementation of `FnOnce` is not general enough
|
||||||
|
//~| ERROR implementation of `FnOnce` is not general enough
|
||||||
|
Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
error: implementation of `FnOnce` is not general enough
|
||||||
|
--> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
|
||||||
|
|
|
||||||
|
LL | / send(async {
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
|
||||||
|
LL | | });
|
||||||
|
| |______^ implementation of `FnOnce` is not general enough
|
||||||
|
|
|
||||||
|
= note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
|
||||||
|
= note: ...but it actually implements `FnOnce<(&(),)>`
|
||||||
|
|
||||||
|
error: implementation of `FnOnce` is not general enough
|
||||||
|
--> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
|
||||||
|
|
|
||||||
|
LL | / send(async {
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
|
||||||
|
LL | | });
|
||||||
|
| |______^ implementation of `FnOnce` is not general enough
|
||||||
|
|
|
||||||
|
= note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
|
||||||
|
= note: ...but it actually implements `FnOnce<(&(),)>`
|
||||||
|
|
||||||
|
error: implementation of `FnOnce` is not general enough
|
||||||
|
--> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
|
||||||
|
|
|
||||||
|
LL | / send(async {
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
|
||||||
|
LL | | });
|
||||||
|
| |______^ implementation of `FnOnce` is not general enough
|
||||||
|
|
|
||||||
|
= note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
|
||||||
|
= note: ...but it actually implements `FnOnce<(&(),)>`
|
||||||
|
|
||||||
|
error: implementation of `FnOnce` is not general enough
|
||||||
|
--> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
|
||||||
|
|
|
||||||
|
LL | / send(async {
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
|
||||||
|
LL | | });
|
||||||
|
| |______^ implementation of `FnOnce` is not general enough
|
||||||
|
|
|
||||||
|
= note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
|
||||||
|
= note: ...but it actually implements `FnOnce<(&(),)>`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue