about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-05-17 15:45:22 +0200
committerGitHub <noreply@github.com>2025-05-17 15:45:22 +0200
commit909098728c37729a166a3d38d90532d655cfd511 (patch)
treef2355de8e4b8977cbc67663f860bfbdbe1c1364c
parent616650b6ca98e82fd2e8c32a6f2330dcef118421 (diff)
parent667504b176c9e1ab380cef6eb9eaeba4813337c3 (diff)
downloadrust-909098728c37729a166a3d38d90532d655cfd511.tar.gz
rust-909098728c37729a166a3d38d90532d655cfd511.zip
Rollup merge of #141125 - lcnr:coroutine_obligations_use_borrowck, r=compiler-errors
check coroutines with `TypingMode::Borrowck` to avoid cyclic reasoning

MIR borrowck taints its output if an obligation fails. This could then cause `check_coroutine_obligations` to silence its error, causing us to not emit and actual error and ICE.

Fixes the ICE in https://github.com/rust-lang/trait-system-refactor-initiative/issues/199. It is unfortunately still a regression.

r? compiler-errors
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs20
-rw-r--r--tests/ui/coroutine/delayed-obligations-emit.next.stderr15
-rw-r--r--tests/ui/coroutine/delayed-obligations-emit.rs33
3 files changed, 61 insertions, 7 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index f92b2aea160..da94331aa26 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1754,17 +1754,19 @@ pub(super) fn check_coroutine_obligations(
     debug!(?typeck_results.coroutine_stalled_predicates);
 
     let mode = if tcx.next_trait_solver_globally() {
-        TypingMode::post_borrowck_analysis(tcx, def_id)
+        // This query is conceptually between HIR typeck and
+        // MIR borrowck. We use the opaque types defined by HIR
+        // and ignore region constraints.
+        TypingMode::borrowck(tcx, def_id)
     } else {
         TypingMode::analysis_in_body(tcx, def_id)
     };
 
-    let infcx = tcx
-        .infer_ctxt()
-        // 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()
-        .build(mode);
+    // Typeck writeback gives us predicates with their regions erased.
+    // We only need to check the goals while ignoring lifetimes to give good
+    // error message and to avoid breaking the assumption of `mir_borrowck`
+    // that all obligations already hold modulo regions.
+    let infcx = tcx.infer_ctxt().ignoring_regions().build(mode);
 
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
     for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
@@ -1785,6 +1787,10 @@ pub(super) fn check_coroutine_obligations(
             let key = infcx.resolve_vars_if_possible(key);
             sanity_check_found_hidden_type(tcx, key, hidden_type)?;
         }
+    } else {
+        // We're not checking region constraints here, so we can simply drop the
+        // added opaque type uses in `TypingMode::Borrowck`.
+        let _ = infcx.take_opaque_types();
     }
 
     Ok(())
diff --git a/tests/ui/coroutine/delayed-obligations-emit.next.stderr b/tests/ui/coroutine/delayed-obligations-emit.next.stderr
new file mode 100644
index 00000000000..3a3663398c9
--- /dev/null
+++ b/tests/ui/coroutine/delayed-obligations-emit.next.stderr
@@ -0,0 +1,15 @@
+error[E0275]: overflow evaluating the requirement `{async block@$DIR/delayed-obligations-emit.rs:17:11: 17:16}: Send`
+  --> $DIR/delayed-obligations-emit.rs:17:5
+   |
+LL |     spawn(async { build_dependencies().await });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: required by a bound in `spawn`
+  --> $DIR/delayed-obligations-emit.rs:31:13
+   |
+LL | fn spawn<F: Send>(_: F) {}
+   |             ^^^^ required by this bound in `spawn`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/coroutine/delayed-obligations-emit.rs b/tests/ui/coroutine/delayed-obligations-emit.rs
new file mode 100644
index 00000000000..6334f29fcb2
--- /dev/null
+++ b/tests/ui/coroutine/delayed-obligations-emit.rs
@@ -0,0 +1,33 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ edition: 2024
+//@[current] check-pass
+
+// This previously caused an ICE with the new solver.
+// The delayed coroutine obligations were checked with the
+// opaque types inferred by borrowck.
+//
+// One of these delayed obligations failed with overflow in
+// borrowck, causing us to taint `type_of` for the opaque. This
+// then caused us to also not emit an error when checking the
+// coroutine obligations.
+
+fn build_multiple<'a>() -> impl Sized {
+    spawn(async { build_dependencies().await });
+    //[next]~^ ERROR overflow evaluating the requirement
+}
+
+// Adding an explicit `Send` bound fixes it.
+// Proving `build_dependencies(): Send` in `build_multiple` adds
+// addiitional defining uses/placeholders.
+fn build_dependencies() -> impl Future<Output = ()> /* + Send */ {
+    async {
+        Box::pin(build_dependencies()).await;
+        async { build_multiple() }.await;
+    }
+}
+
+fn spawn<F: Send>(_: F) {}
+
+fn main() {}