diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e301f0b22ef77..00f636862beb2 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 = >::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 cbba990867e03..c982e2a93253f 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 0000000000000..e0061e1c6bb33 --- /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() {}