Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass InferCtxt to DropRangeVisitor so we can resolve vars #104753

Merged
merged 2 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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::{ParamEnv, TyCtxt, TypeVisitable, TypeckResults},
};
use std::mem::swap;

Expand All @@ -21,20 +22,29 @@ 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>,
param_env: ParamEnv<'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);
let mut drop_range_visitor = DropRangeVisitor::new(
infcx,
typeck_results,
param_env,
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)
Expand Down Expand Up @@ -82,40 +92,44 @@ pub(super) fn build_control_flow_graph<'tcx>(
/// ```

struct DropRangeVisitor<'a, 'tcx> {
hir: Map<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
infcx: &'a InferCtxt<'tcx>,
param_env: ParamEnv<'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>,
param_env: ParamEnv<'tcx>,
places: ConsumedAndBorrowedPlaces,
num_exprs: usize,
) -> Self {
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,
param_env,
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);
Expand All @@ -137,7 +151,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));
}
}

Expand Down Expand Up @@ -214,10 +228,15 @@ 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);
if ty.has_non_region_infer() {
self.tcx()
.sess
.delay_span_bug(expr.span, format!("could not resolve infer vars in `{ty}`"));
}
let ty = self.tcx().erase_regions(ty);
let m = self.tcx().parent_module(expr.hir_id).to_def_id();
if !ty.is_inhabited_from(self.tcx(), m, self.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);
}
Expand All @@ -238,7 +257,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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ 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,
fcx.param_env,
consumed_borrowed_places,
body,
num_exprs,
Expand Down
106 changes: 106 additions & 0 deletions src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs
Original file line number Diff line number Diff line change
@@ -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
});
}
Original file line number Diff line number Diff line change
@@ -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