Skip to content

Commit 6938717

Browse files
authored
Rollup merge of #104753 - compiler-errors:drop-tracking-var-ice, r=oli-obk
Pass `InferCtxt` to `DropRangeVisitor` so we can resolve vars The types that we encounter in the `TypeckResults` that we pass to the `DropRangeVisitor` are not yet fully resolved, since that only happens in writeback after type checking is complete. Instead, pass down the whole `InferCtxt` so that we can resolve any inference vars that have been constrained since they were written into the results. This is similar to how the `MemCategorizationContext` in the `ExprUseVisitor` also needs to pass down both typeck results _and_ the inference context. Fixes an ICE mentioned in this comment: #104382 (comment)
2 parents c08c57e + 024bb8c commit 6938717

File tree

4 files changed

+211
-24
lines changed

4 files changed

+211
-24
lines changed

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

+41-22
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::{ParamEnv, TyCtxt, TypeVisitable, TypeckResults},
1516
};
1617
use std::mem::swap;
1718

@@ -21,20 +22,29 @@ 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>,
27+
param_env: ParamEnv<'tcx>,
2728
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
2829
body: &'tcx Body<'tcx>,
2930
num_exprs: usize,
3031
) -> (DropRangesBuilder, FxHashSet<HirId>) {
31-
let mut drop_range_visitor =
32-
DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
32+
let mut drop_range_visitor = DropRangeVisitor::new(
33+
infcx,
34+
typeck_results,
35+
param_env,
36+
consumed_borrowed_places,
37+
num_exprs,
38+
);
3339
intravisit::walk_body(&mut drop_range_visitor, body);
3440

3541
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);
42+
if let Some(filename) = &infcx.tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
43+
super::cfg_visualize::write_graph_to_file(
44+
&drop_range_visitor.drop_ranges,
45+
filename,
46+
infcx.tcx,
47+
);
3848
}
3949

4050
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
@@ -82,40 +92,44 @@ pub(super) fn build_control_flow_graph<'tcx>(
8292
/// ```
8393
8494
struct DropRangeVisitor<'a, 'tcx> {
85-
hir: Map<'tcx>,
95+
typeck_results: &'a TypeckResults<'tcx>,
96+
infcx: &'a InferCtxt<'tcx>,
97+
param_env: ParamEnv<'tcx>,
8698
places: ConsumedAndBorrowedPlaces,
8799
drop_ranges: DropRangesBuilder,
88100
expr_index: PostOrderId,
89-
tcx: TyCtxt<'tcx>,
90-
typeck_results: &'a TypeckResults<'tcx>,
91101
label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
92102
}
93103

94104
impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
95105
fn new(
96-
hir: Map<'tcx>,
97-
tcx: TyCtxt<'tcx>,
106+
infcx: &'a InferCtxt<'tcx>,
98107
typeck_results: &'a TypeckResults<'tcx>,
108+
param_env: ParamEnv<'tcx>,
99109
places: ConsumedAndBorrowedPlaces,
100110
num_exprs: usize,
101111
) -> Self {
102112
debug!("consumed_places: {:?}", places.consumed);
103113
let drop_ranges = DropRangesBuilder::new(
104114
places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
105-
hir,
115+
infcx.tcx.hir(),
106116
num_exprs,
107117
);
108118
Self {
109-
hir,
119+
infcx,
120+
typeck_results,
121+
param_env,
110122
places,
111123
drop_ranges,
112124
expr_index: PostOrderId::from_u32(0),
113-
typeck_results,
114-
tcx,
115125
label_stack: vec![],
116126
}
117127
}
118128

129+
fn tcx(&self) -> TyCtxt<'tcx> {
130+
self.infcx.tcx
131+
}
132+
119133
fn record_drop(&mut self, value: TrackedValue) {
120134
if self.places.borrowed.contains(&value) {
121135
debug!("not marking {:?} as dropped because it is borrowed at some point", value);
@@ -137,7 +151,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
137151
.map_or(vec![], |places| places.iter().cloned().collect());
138152
for place in places {
139153
trace!(?place, "consuming place");
140-
for_each_consumable(self.hir, place, |value| self.record_drop(value));
154+
for_each_consumable(self.tcx().hir(), place, |value| self.record_drop(value));
141155
}
142156
}
143157

@@ -214,10 +228,15 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
214228
/// return.
215229
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
216230
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) {
231+
let ty = self.infcx.resolve_vars_if_possible(ty);
232+
if ty.has_non_region_infer() {
233+
self.tcx()
234+
.sess
235+
.delay_span_bug(expr.span, format!("could not resolve infer vars in `{ty}`"));
236+
}
237+
let ty = self.tcx().erase_regions(ty);
238+
let m = self.tcx().parent_module(expr.hir_id).to_def_id();
239+
if !ty.is_inhabited_from(self.tcx(), m, self.param_env) {
221240
// This function will not return. We model this fact as an infinite loop.
222241
self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
223242
}
@@ -238,7 +257,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
238257
destination: hir::Destination,
239258
) -> Result<HirId, LoopIdError> {
240259
destination.target_id.map(|target| {
241-
let node = self.hir.get(target);
260+
let node = self.tcx().hir().get(target);
242261
match node {
243262
hir::Node::Expr(_) => target,
244263
hir::Node::Block(b) => find_last_block_expression(b),

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ 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,
48+
fcx.param_env,
4949
consumed_borrowed_places,
5050
body,
5151
num_exprs,
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)