about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-11-23 01:47:56 +0000
committerMichael Goulet <michael@errs.io>2022-11-23 01:48:03 +0000
commit1e7f6a7e0d27e0f8d2ab5bccdf2a0c4e627979d2 (patch)
tree12062bb09f922724ae300dd81d3d3fe722b00192
parent66ccf36f161f67b121290e2af2517ead7e695d3b (diff)
downloadrust-1e7f6a7e0d27e0f8d2ab5bccdf2a0c4e627979d2.tar.gz
rust-1e7f6a7e0d27e0f8d2ab5bccdf2a0c4e627979d2.zip
Pass InferCtxt to DropRangeVisitor so we can resolve vars
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs53
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs3
-rw-r--r--src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs106
-rw-r--r--src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr62
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
+