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_hir as hir;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::{
|
||||
hir::map::Map,
|
||||
ty::{TyCtxt, TypeckResults},
|
||||
ty::{TyCtxt, TypeVisitable, TypeckResults},
|
||||
};
|
||||
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
|
||||
/// can be done with propagate_to_fixpoint in cfg_propagate.
|
||||
pub(super) fn build_control_flow_graph<'tcx>(
|
||||
hir: Map<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
typeck_results: &TypeckResults<'tcx>,
|
||||
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
|
||||
body: &'tcx Body<'tcx>,
|
||||
num_exprs: usize,
|
||||
) -> (DropRangesBuilder, FxHashSet<HirId>) {
|
||||
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);
|
||||
|
||||
drop_range_visitor.drop_ranges.process_deferred_edges();
|
||||
if let Some(filename) = &tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
|
||||
super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
|
||||
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,
|
||||
infcx.tcx,
|
||||
);
|
||||
}
|
||||
|
||||
(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> {
|
||||
hir: Map<'tcx>,
|
||||
typeck_results: &'a TypeckResults<'tcx>,
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
places: ConsumedAndBorrowedPlaces,
|
||||
drop_ranges: DropRangesBuilder,
|
||||
expr_index: PostOrderId,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typeck_results: &'a TypeckResults<'tcx>,
|
||||
label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
||||
fn new(
|
||||
hir: Map<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
typeck_results: &'a TypeckResults<'tcx>,
|
||||
places: ConsumedAndBorrowedPlaces,
|
||||
num_exprs: usize,
|
||||
|
@ -102,20 +104,23 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
|||
debug!("consumed_places: {:?}", places.consumed);
|
||||
let drop_ranges = DropRangesBuilder::new(
|
||||
places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
|
||||
hir,
|
||||
infcx.tcx.hir(),
|
||||
num_exprs,
|
||||
);
|
||||
Self {
|
||||
hir,
|
||||
infcx,
|
||||
typeck_results,
|
||||
places,
|
||||
drop_ranges,
|
||||
expr_index: PostOrderId::from_u32(0),
|
||||
typeck_results,
|
||||
tcx,
|
||||
label_stack: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn record_drop(&mut self, value: TrackedValue) {
|
||||
if self.places.borrowed.contains(&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());
|
||||
for place in places {
|
||||
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.
|
||||
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
|
||||
let ty = self.typeck_results.expr_ty(expr);
|
||||
let ty = self.tcx.erase_regions(ty);
|
||||
let m = self.tcx.parent_module(expr.hir_id).to_def_id();
|
||||
let param_env = self.tcx.param_env(m.expect_local());
|
||||
if !ty.is_inhabited_from(self.tcx, m, param_env) {
|
||||
let ty = self.infcx.resolve_vars_if_possible(ty);
|
||||
let ty = self.tcx().erase_regions(ty);
|
||||
let m = self.tcx().parent_module(expr.hir_id).to_def_id();
|
||||
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.
|
||||
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,
|
||||
) -> Result<HirId, LoopIdError> {
|
||||
destination.target_id.map(|target| {
|
||||
let node = self.hir.get(target);
|
||||
let node = self.tcx().hir().get(target);
|
||||
match node {
|
||||
hir::Node::Expr(_) => target,
|
||||
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 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(
|
||||
fcx.tcx.hir(),
|
||||
fcx.tcx,
|
||||
&fcx,
|
||||
typeck_results,
|
||||
consumed_borrowed_places,
|
||||
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