about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs22
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--tests/ui/coroutine/clone-rpit.rs17
3 files changed, 36 insertions, 5 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index e301f0b22ef..00f636862be 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1468,7 +1468,10 @@ fn opaque_type_cycle_error(
     err.emit()
 }
 
-pub(super) fn check_coroutine_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+pub(super) fn check_coroutine_obligations(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
     debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Coroutine));
 
     let typeck = tcx.typeck(def_id);
@@ -1482,8 +1485,9 @@ pub(super) fn check_coroutine_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         // typeck writeback gives us predicates with their regions erased.
         // As borrowck already has checked lifetimes, we do not need to do it again.
         .ignoring_regions()
-        // Bind opaque types to `def_id` as they should have been checked by borrowck.
-        .with_opaque_type_inference(DefiningAnchor::Bind(def_id))
+        // Bind opaque types to type checking root, as they should have been checked by borrowck,
+        // but may show up in some cases, like when (root) obligations are stalled in the new solver.
+        .with_opaque_type_inference(DefiningAnchor::Bind(typeck.hir_owner.def_id))
         .build();
 
     let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
@@ -1513,6 +1517,16 @@ pub(super) fn check_coroutine_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let errors = fulfillment_cx.select_all_or_error(&infcx);
     debug!(?errors);
     if !errors.is_empty() {
-        infcx.err_ctxt().report_fulfillment_errors(errors);
+        return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
     }
+
+    // Check that any hidden types found when checking these stalled coroutine obligations
+    // are valid.
+    for (key, ty) in infcx.take_opaque_types() {
+        let hidden_type = infcx.resolve_vars_if_possible(ty.hidden_type);
+        let key = infcx.resolve_vars_if_possible(key);
+        sanity_check_found_hidden_type(tcx, key, hidden_type)?;
+    }
+
+    Ok(())
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index cbba990867e..c982e2a9325 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -567,7 +567,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query check_coroutine_obligations(key: LocalDefId) {
+    query check_coroutine_obligations(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "verify auto trait bounds for coroutine interior type `{}`", tcx.def_path_str(key) }
     }
 
diff --git a/tests/ui/coroutine/clone-rpit.rs b/tests/ui/coroutine/clone-rpit.rs
new file mode 100644
index 00000000000..e0061e1c6bb
--- /dev/null
+++ b/tests/ui/coroutine/clone-rpit.rs
@@ -0,0 +1,17 @@
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+// check-pass
+
+#![feature(coroutines, coroutine_trait, coroutine_clone)]
+
+// This stalls the goal `{coroutine} <: impl Clone`, since that has a nested goal
+// of `{coroutine}: Clone`. That is only known if we can compute the generator
+// witness types, which we don't know until after borrowck. When we later check
+// the goal for correctness, we want to be able to bind the `impl Clone` opaque.
+pub fn foo<'a, 'b>() -> impl Clone {
+    move |_: ()| {
+        let () = yield ();
+    }
+}
+
+fn main() {}