diff options
| author | Michael Goulet <michael@errs.io> | 2022-11-23 01:47:56 +0000 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2022-11-23 01:48:03 +0000 |
| commit | 1e7f6a7e0d27e0f8d2ab5bccdf2a0c4e627979d2 (patch) | |
| tree | 12062bb09f922724ae300dd81d3d3fe722b00192 | |
| parent | 66ccf36f161f67b121290e2af2517ead7e695d3b (diff) | |
| download | rust-1e7f6a7e0d27e0f8d2ab5bccdf2a0c4e627979d2.tar.gz rust-1e7f6a7e0d27e0f8d2ab5bccdf2a0c4e627979d2.zip | |
Pass InferCtxt to DropRangeVisitor so we can resolve vars
4 files changed, 201 insertions, 23 deletions
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index a78b294181c..8e7f5895845 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -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), diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs index 4f3bdfbe758..d5a5bb7d578 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs @@ -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, diff --git a/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs new file mode 100644 index 00000000000..7f729429581 --- /dev/null +++ b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs @@ -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 + }); +} diff --git a/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr new file mode 100644 index 00000000000..aa9a22e9e72 --- /dev/null +++ b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr @@ -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 + |
