Skip to content

Commit 1e7f6a7

Browse files
Pass InferCtxt to DropRangeVisitor so we can resolve vars
1 parent 66ccf36 commit 1e7f6a7

File tree

4 files changed

+201
-23
lines changed

4 files changed

+201
-23
lines changed

compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs

+32-21
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ use hir::{
99
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1010
use rustc_hir as hir;
1111
use rustc_index::vec::IndexVec;
12+
use rustc_infer::infer::InferCtxt;
1213
use rustc_middle::{
1314
hir::map::Map,
14-
ty::{TyCtxt, TypeckResults},
15+
ty::{TyCtxt, TypeVisitable, TypeckResults},
1516
};
1617
use std::mem::swap;
1718

@@ -21,20 +22,23 @@ use std::mem::swap;
2122
/// The resulting structure still needs to be iterated to a fixed point, which
2223
/// can be done with propagate_to_fixpoint in cfg_propagate.
2324
pub(super) fn build_control_flow_graph<'tcx>(
24-
hir: Map<'tcx>,
25-
tcx: TyCtxt<'tcx>,
25+
infcx: &InferCtxt<'tcx>,
2626
typeck_results: &TypeckResults<'tcx>,
2727
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
2828
body: &'tcx Body<'tcx>,
2929
num_exprs: usize,
3030
) -> (DropRangesBuilder, FxHashSet<HirId>) {
3131
let mut drop_range_visitor =
32-
DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
32+
DropRangeVisitor::new(infcx, typeck_results, consumed_borrowed_places, num_exprs);
3333
intravisit::walk_body(&mut drop_range_visitor, body);
3434

3535
drop_range_visitor.drop_ranges.process_deferred_edges();
36-
if let Some(filename) = &tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
37-
super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
36+
if let Some(filename) = &infcx.tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
37+
super::cfg_visualize::write_graph_to_file(
38+
&drop_range_visitor.drop_ranges,
39+
filename,
40+
infcx.tcx,
41+
);
3842
}
3943

4044
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
@@ -82,40 +86,41 @@ pub(super) fn build_control_flow_graph<'tcx>(
8286
/// ```
8387
8488
struct DropRangeVisitor<'a, 'tcx> {
85-
hir: Map<'tcx>,
89+
typeck_results: &'a TypeckResults<'tcx>,
90+
infcx: &'a InferCtxt<'tcx>,
8691
places: ConsumedAndBorrowedPlaces,
8792
drop_ranges: DropRangesBuilder,
8893
expr_index: PostOrderId,
89-
tcx: TyCtxt<'tcx>,
90-
typeck_results: &'a TypeckResults<'tcx>,
9194
label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
9295
}
9396

9497
impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
9598
fn new(
96-
hir: Map<'tcx>,
97-
tcx: TyCtxt<'tcx>,
99+
infcx: &'a InferCtxt<'tcx>,
98100
typeck_results: &'a TypeckResults<'tcx>,
99101
places: ConsumedAndBorrowedPlaces,
100102
num_exprs: usize,
101103
) -> Self {
102104
debug!("consumed_places: {:?}", places.consumed);
103105
let drop_ranges = DropRangesBuilder::new(
104106
places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
105-
hir,
107+
infcx.tcx.hir(),
106108
num_exprs,
107109
);
108110
Self {
109-
hir,
111+
infcx,
112+
typeck_results,
110113
places,
111114
drop_ranges,
112115
expr_index: PostOrderId::from_u32(0),
113-
typeck_results,
114-
tcx,
115116
label_stack: vec![],
116117
}
117118
}
118119

120+
fn tcx(&self) -> TyCtxt<'tcx> {
121+
self.infcx.tcx
122+
}
123+
119124
fn record_drop(&mut self, value: TrackedValue) {
120125
if self.places.borrowed.contains(&value) {
121126
debug!("not marking {:?} as dropped because it is borrowed at some point", value);
@@ -137,7 +142,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
137142
.map_or(vec![], |places| places.iter().cloned().collect());
138143
for place in places {
139144
trace!(?place, "consuming place");
140-
for_each_consumable(self.hir, place, |value| self.record_drop(value));
145+
for_each_consumable(self.tcx().hir(), place, |value| self.record_drop(value));
141146
}
142147
}
143148

@@ -214,10 +219,16 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
214219
/// return.
215220
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
216221
let ty = self.typeck_results.expr_ty(expr);
217-
let ty = self.tcx.erase_regions(ty);
218-
let m = self.tcx.parent_module(expr.hir_id).to_def_id();
219-
let param_env = self.tcx.param_env(m.expect_local());
220-
if !ty.is_inhabited_from(self.tcx, m, param_env) {
222+
let ty = self.infcx.resolve_vars_if_possible(ty);
223+
let ty = self.tcx().erase_regions(ty);
224+
let m = self.tcx().parent_module(expr.hir_id).to_def_id();
225+
let param_env = self.tcx().param_env(m.expect_local());
226+
if ty.has_non_region_infer() {
227+
self.tcx()
228+
.sess
229+
.delay_span_bug(expr.span, format!("could not resolve infer vars in `{ty}`"));
230+
}
231+
if !ty.is_inhabited_from(self.tcx(), m, param_env) {
221232
// This function will not return. We model this fact as an infinite loop.
222233
self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
223234
}
@@ -238,7 +249,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
238249
destination: hir::Destination,
239250
) -> Result<HirId, LoopIdError> {
240251
destination.target_id.map(|target| {
241-
let node = self.hir.get(target);
252+
let node = self.tcx().hir().get(target);
242253
match node {
243254
hir::Node::Expr(_) => target,
244255
hir::Node::Block(b) => find_last_block_expression(b),

compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ pub fn compute_drop_ranges<'a, 'tcx>(
4343
let typeck_results = &fcx.typeck_results.borrow();
4444
let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
4545
let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
46-
fcx.tcx.hir(),
47-
fcx.tcx,
46+
&fcx,
4847
typeck_results,
4948
consumed_borrowed_places,
5049
body,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// compile-flags: -Zdrop-tracking
2+
// incremental
3+
// edition: 2021
4+
5+
use std::future::*;
6+
use std::marker::PhantomData;
7+
use std::pin::Pin;
8+
use std::task::*;
9+
10+
fn send<T: Send>(_: T) {}
11+
12+
pub trait Stream {
13+
type Item;
14+
15+
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
16+
}
17+
18+
struct Empty<T>(PhantomData<fn() -> T>);
19+
20+
impl<T> Stream for Empty<T> {
21+
type Item = T;
22+
23+
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
24+
todo!()
25+
}
26+
}
27+
28+
pub trait FnOnce1<A> {
29+
type Output;
30+
fn call_once(self, arg: A) -> Self::Output;
31+
}
32+
33+
impl<T, A, R> FnOnce1<A> for T
34+
where
35+
T: FnOnce(A) -> R,
36+
{
37+
type Output = R;
38+
fn call_once(self, arg: A) -> R {
39+
self(arg)
40+
}
41+
}
42+
43+
pub trait FnMut1<A>: FnOnce1<A> {
44+
fn call_mut(&mut self, arg: A) -> Self::Output;
45+
}
46+
47+
impl<T, A, R> FnMut1<A> for T
48+
where
49+
T: FnMut(A) -> R,
50+
{
51+
fn call_mut(&mut self, arg: A) -> R {
52+
self(arg)
53+
}
54+
}
55+
56+
struct Map<St, F>(St, F);
57+
58+
impl<St, F> Stream for Map<St, F>
59+
where
60+
St: Stream,
61+
F: FnMut1<St::Item>,
62+
{
63+
type Item = F::Output;
64+
65+
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
66+
todo!()
67+
}
68+
}
69+
70+
struct FuturesOrdered<T: Future>(PhantomData<fn() -> T::Output>);
71+
72+
pub struct Buffered<St: Stream>(St, FuturesOrdered<St::Item>, usize)
73+
where
74+
St::Item: Future;
75+
76+
impl<St> Stream for Buffered<St>
77+
where
78+
St: Stream,
79+
St::Item: Future,
80+
{
81+
type Item = <St::Item as Future>::Output;
82+
83+
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
84+
todo!()
85+
}
86+
}
87+
88+
struct Next<'a, T: ?Sized>(&'a T);
89+
90+
impl<St: ?Sized + Stream + Unpin> Future for Next<'_, St> {
91+
type Output = Option<St::Item>;
92+
93+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
94+
todo!()
95+
}
96+
}
97+
98+
fn main() {
99+
send(async {
100+
//~^ ERROR implementation of `FnOnce` is not general enough
101+
//~| ERROR implementation of `FnOnce` is not general enough
102+
//~| ERROR implementation of `FnOnce` is not general enough
103+
//~| ERROR implementation of `FnOnce` is not general enough
104+
Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
105+
});
106+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
error: implementation of `FnOnce` is not general enough
2+
--> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
3+
|
4+
LL | / send(async {
5+
LL | |
6+
LL | |
7+
LL | |
8+
LL | |
9+
LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
10+
LL | | });
11+
| |______^ implementation of `FnOnce` is not general enough
12+
|
13+
= note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
14+
= note: ...but it actually implements `FnOnce<(&(),)>`
15+
16+
error: implementation of `FnOnce` is not general enough
17+
--> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
18+
|
19+
LL | / send(async {
20+
LL | |
21+
LL | |
22+
LL | |
23+
LL | |
24+
LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
25+
LL | | });
26+
| |______^ implementation of `FnOnce` is not general enough
27+
|
28+
= note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
29+
= note: ...but it actually implements `FnOnce<(&(),)>`
30+
31+
error: implementation of `FnOnce` is not general enough
32+
--> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
33+
|
34+
LL | / send(async {
35+
LL | |
36+
LL | |
37+
LL | |
38+
LL | |
39+
LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
40+
LL | | });
41+
| |______^ implementation of `FnOnce` is not general enough
42+
|
43+
= note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
44+
= note: ...but it actually implements `FnOnce<(&(),)>`
45+
46+
error: implementation of `FnOnce` is not general enough
47+
--> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
48+
|
49+
LL | / send(async {
50+
LL | |
51+
LL | |
52+
LL | |
53+
LL | |
54+
LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
55+
LL | | });
56+
| |______^ implementation of `FnOnce` is not general enough
57+
|
58+
= note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
59+
= note: ...but it actually implements `FnOnce<(&(),)>`
60+
61+
error: aborting due to 4 previous errors
62+

0 commit comments

Comments
 (0)