From 169955f3be4659e486db9b7dabafdbcee18819a3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Mar 2025 23:49:14 +0000 Subject: [PATCH] Properly drain pending obligations for coroutines --- compiler/rustc_hir_typeck/src/closure.rs | 3 + .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 8 +- .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 4 +- compiler/rustc_infer/src/traits/engine.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 9 ++ compiler/rustc_middle/src/query/plumbing.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 8 +- .../rustc_next_trait_solver/src/solve/mod.rs | 5 +- .../src/solve/normalizes_to/opaque_types.rs | 2 +- .../src/solve/trait_goals.rs | 15 +++ .../src/solve/fulfill.rs | 100 +++++++++++++++--- .../src/solve/fulfill/derive_errors.rs | 10 +- .../src/solve/normalize.rs | 46 ++++---- .../src/traits/fulfill.rs | 2 +- .../src/traits/select/mod.rs | 2 +- compiler/rustc_ty_utils/src/opaque_types.rs | 52 ++++++++- compiler/rustc_type_ir/src/infer_ctxt.rs | 23 +++- compiler/rustc_type_ir/src/interner.rs | 9 +- 19 files changed, 242 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index b8968b58769a..b7ae66eba6f4 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -163,6 +163,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resume type defaults to `()` if the coroutine has no argument. let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); + // TODO: In the new solver, we can just instantiate this eagerly + // with the witness. This will ensure that goals that don't need + // to stall on interior types will get processed eagerly. let interior = self.next_ty_var(expr_span); self.deferred_coroutine_interiors.borrow_mut().push((expr_def_id, interior)); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 87d92b3fbde8..3cf7d277f1fd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -659,10 +659,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligations.extend(ok.obligations); } - // FIXME: Use a real visitor for unstalled obligations in the new solver. if !coroutines.is_empty() { - obligations - .extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx)); + obligations.extend( + self.fulfillment_cx + .borrow_mut() + .drain_stalled_obligations_for_coroutines(&self.infcx), + ); } self.typeck_results diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 5b4fc51cec88..ac69493d9567 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -84,7 +84,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; let infcx = - tcx.infer_ctxt().ignoring_regions().build(TypingMode::analysis_in_body(tcx, def_id)); + tcx.infer_ctxt().ignoring_regions().build(TypingMode::typeck_for_body(tcx, def_id)); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); TypeckRootCtxt { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 529e996ad1e7..3b0e85601592 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -967,7 +967,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn can_define_opaque_ty(&self, id: impl Into) -> bool { debug_assert!(!self.next_trait_solver()); match self.typing_mode() { - TypingMode::Analysis { defining_opaque_types } + TypingMode::Analysis { defining_opaque_types, stalled_generators: _ } | TypingMode::Borrowck { defining_opaque_types } => { id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id)) } @@ -1262,7 +1262,7 @@ impl<'tcx> InferCtxt<'tcx> { // to handle them without proper canonicalization. This means we may cause cycle // errors and fail to reveal opaques while inside of bodies. We should rename this // function and require explicit comments on all use-sites in the future. - ty::TypingMode::Analysis { defining_opaque_types: _ } + ty::TypingMode::Analysis { defining_opaque_types: _, stalled_generators: _ } | ty::TypingMode::Borrowck { defining_opaque_types: _ } => { TypingMode::non_body_analysis() } diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 1eae10673b62..9e51a53ae95f 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -94,7 +94,7 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx { /// Among all pending obligations, collect those are stalled on a inference variable which has /// changed since the last call to `select_where_possible`. Those obligations are marked as /// successful and returned. - fn drain_unstalled_obligations( + fn drain_stalled_obligations_for_coroutines( &mut self, infcx: &InferCtxt<'tcx>, ) -> PredicateObligations<'tcx>; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e94f088304b1..4d4096b02254 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -387,6 +387,15 @@ rustc_queries! { } } + query stalled_generators_within( + key: LocalDefId + ) -> &'tcx ty::List { + desc { + |tcx| "computing the opaque types defined by `{}`", + tcx.def_path_str(key.to_def_id()) + } + } + /// Returns the explicitly user-written *bounds* on the associated or opaque type given by `DefId` /// that must be proven true at definition site (and which can be assumed at usage sites). /// diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index a099f7704170..c16adef63eae 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -366,11 +366,11 @@ macro_rules! define_callbacks { pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache>; - // Ensure that keys grow no larger than 80 bytes by accident. + // Ensure that keys grow no larger than 96 bytes by accident. // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] const _: () = { - if size_of::>() > 88 { + if size_of::>() > 96 { panic!("{}", concat!( "the query `", stringify!($name), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index fa2f1cf1a1c8..f8f66b58c1db 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -106,7 +106,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> Self::PredefinedOpaques { self.mk_predefined_opaques_in_body(data) } - type DefiningOpaqueTypes = &'tcx ty::List; + type LocalDefIds = &'tcx ty::List; type CanonicalVars = CanonicalVarInfos<'tcx>; fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) @@ -674,9 +674,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.anonymize_bound_vars(binder) } - fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::DefiningOpaqueTypes { + fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::LocalDefIds { self.opaque_types_defined_by(defining_anchor) } + + fn stalled_generators_within(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds { + self.stalled_generators_within(defining_anchor) + } } macro_rules! bidirectional_lang_item_map { diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 7641e9a16ee6..8868769906d2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -329,7 +329,10 @@ where TypingMode::Coherence | TypingMode::PostAnalysis => false, // During analysis, opaques are rigid unless they may be defined by // the current body. - TypingMode::Analysis { defining_opaque_types: non_rigid_opaques } + TypingMode::Analysis { + defining_opaque_types: non_rigid_opaques, + stalled_generators: _, + } | TypingMode::Borrowck { defining_opaque_types: non_rigid_opaques } | TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => { !def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id)) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index aa89e77bb6fb..dcfc3b3a701c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -33,7 +33,7 @@ where ); self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } - TypingMode::Analysis { defining_opaque_types } => { + TypingMode::Analysis { defining_opaque_types, stalled_generators: _ } => { let Some(def_id) = opaque_ty .def_id .as_local() diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 7bd1300f34ed..38c4d0205cd5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -208,6 +208,21 @@ where } } + if let ty::CoroutineWitness(def_id, _) = goal.predicate.self_ty().kind() { + match ecx.typing_mode() { + TypingMode::Analysis { stalled_generators, defining_opaque_types: _ } => { + if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id)) + { + return ecx.forced_ambiguity(MaybeCause::Ambiguity); + } + } + TypingMode::Coherence + | TypingMode::PostAnalysis + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {} + } + } + ecx.probe_and_evaluate_goal_for_constituent_tys( CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 192e632a2d5b..abee5ac52c1c 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,18 +1,25 @@ use std::marker::PhantomData; use std::mem; +use std::ops::ControlFlow; use rustc_data_structures::thinvec::ExtractIf; +use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::{ FromSolverError, PredicateObligation, PredicateObligations, TraitEngine, }; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, +}; use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; +use rustc_span::Span; use tracing::instrument; use self::derive_errors::*; use super::Certainty; use super::delegate::SolverDelegate; +use super::inspect::{self, ProofTreeInferCtxtExt}; use crate::traits::{FulfillmentError, ScrubbedTraitError}; mod derive_errors; @@ -39,7 +46,7 @@ pub struct FulfillmentCtxt<'tcx, E: 'tcx> { _errors: PhantomData, } -#[derive(Default)] +#[derive(Default, Debug)] struct ObligationStorage<'tcx> { /// Obligations which resulted in an overflow in fulfillment itself. /// @@ -55,20 +62,23 @@ impl<'tcx> ObligationStorage<'tcx> { self.pending.push(obligation); } + fn has_pending_obligations(&self) -> bool { + !self.pending.is_empty() || !self.overflowed.is_empty() + } + fn clone_pending(&self) -> PredicateObligations<'tcx> { let mut obligations = self.pending.clone(); obligations.extend(self.overflowed.iter().cloned()); obligations } - fn take_pending(&mut self) -> PredicateObligations<'tcx> { - let mut obligations = mem::take(&mut self.pending); - obligations.append(&mut self.overflowed); - obligations - } - - fn unstalled_for_select(&mut self) -> impl Iterator> + 'tcx { - mem::take(&mut self.pending).into_iter() + fn drain_pending( + &mut self, + cond: impl Fn(&PredicateObligation<'tcx>) -> bool, + ) -> PredicateObligations<'tcx> { + let (unstalled, pending) = mem::take(&mut self.pending).into_iter().partition(cond); + self.pending = pending; + unstalled } fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) { @@ -160,7 +170,7 @@ where } let mut has_changed = false; - for obligation in self.obligations.unstalled_for_select() { + for obligation in self.obligations.drain_pending(|_| true) { let goal = obligation.as_goal(); let result = <&SolverDelegate<'tcx>>::from(infcx) .evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span) @@ -196,15 +206,79 @@ where } fn has_pending_obligations(&self) -> bool { - !self.obligations.pending.is_empty() || !self.obligations.overflowed.is_empty() + self.obligations.has_pending_obligations() } fn pending_obligations(&self) -> PredicateObligations<'tcx> { self.obligations.clone_pending() } - fn drain_unstalled_obligations(&mut self, _: &InferCtxt<'tcx>) -> PredicateObligations<'tcx> { - self.obligations.take_pending() + fn drain_stalled_obligations_for_coroutines( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> PredicateObligations<'tcx> { + self.obligations.drain_pending(|obl| { + let stalled_generators = match infcx.typing_mode() { + TypingMode::Analysis { defining_opaque_types: _, stalled_generators } => { + stalled_generators + } + TypingMode::Coherence + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } + | TypingMode::PostAnalysis => return false, + }; + + if stalled_generators.is_empty() { + return false; + } + + infcx.probe(|_| { + infcx + .visit_proof_tree( + obl.as_goal(), + &mut StalledOnCoroutines { stalled_generators, span: obl.cause.span }, + ) + .is_break() + }) + }) + } +} + +struct StalledOnCoroutines<'tcx> { + stalled_generators: &'tcx ty::List, + span: Span, + // TODO: Cache +} + +impl<'tcx> inspect::ProofTreeVisitor<'tcx> for StalledOnCoroutines<'tcx> { + type Result = ControlFlow<()>; + + fn span(&self) -> rustc_span::Span { + self.span + } + + fn visit_goal(&mut self, inspect_goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result { + inspect_goal.goal().predicate.visit_with(self)?; + + if let Some(candidate) = inspect_goal.unique_applicable_candidate() { + candidate.visit_nested_no_probe(self) + } else { + ControlFlow::Continue(()) + } + } +} + +impl<'tcx> TypeVisitor> for StalledOnCoroutines<'tcx> { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + if let ty::CoroutineWitness(def_id, _) = *ty.kind() + && def_id.as_local().is_some_and(|def_id| self.stalled_generators.contains(&def_id)) + { + return ControlFlow::Break(()); + } + + ty.super_visit_with(self) } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index d8dcd12aecb9..e31cad6b40dd 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -109,10 +109,16 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>( false, ), Ok((_, Certainty::Yes)) => { - bug!("did not expect successful goal when collecting ambiguity errors") + bug!( + "did not expect successful goal when collecting ambiguity errors for `{:?}`", + infcx.resolve_vars_if_possible(root_obligation.predicate), + ) } Err(_) => { - bug!("did not expect selection error when collecting ambiguity errors") + bug!( + "did not expect selection error when collecting ambiguity errors for `{:?}`", + infcx.resolve_vars_if_possible(root_obligation.predicate), + ) } } }); diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 7b80059722a2..65ab14ae07cd 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -76,7 +76,7 @@ where let value = value.try_fold_with(&mut folder)?; let goals = folder .fulfill_cx - .drain_unstalled_obligations(at.infcx) + .drain_stalled_obligations_for_coroutines(at.infcx) .into_iter() .map(|obl| obl.as_goal()) .collect(); @@ -130,7 +130,7 @@ where ); self.fulfill_cx.register_predicate_obligation(infcx, obligation); - let errors = self.fulfill_cx.select_all_or_error(infcx); + let errors = self.fulfill_cx.select_where_possible(infcx); if !errors.is_empty() { return Err(errors); } @@ -171,7 +171,7 @@ where let result = if infcx.predicate_may_hold(&obligation) { self.fulfill_cx.register_predicate_obligation(infcx, obligation); - let errors = self.fulfill_cx.select_all_or_error(infcx); + let errors = self.fulfill_cx.select_where_possible(infcx); if !errors.is_empty() { return Err(errors); } @@ -286,27 +286,31 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let infcx = self.at.infcx; - infcx - .commit_if_ok(|_| { - deeply_normalize_with_skipped_universes( - self.at, - ty, - vec![None; ty.outer_exclusive_binder().as_usize()], - ) - }) - .unwrap_or_else(|_: Vec>| ty.super_fold_with(self)) + let result = + infcx.commit_if_ok(|_| { + deeply_normalize_with_skipped_universes_and_ambiguous_goals::< + _, + ScrubbedTraitError<'tcx>, + >(self.at, ty, vec![None; ty.outer_exclusive_binder().as_usize()]) + }); + match result { + Ok((ty, _)) => ty, + Err(_) => ty.super_fold_with(self), + } } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { let infcx = self.at.infcx; - infcx - .commit_if_ok(|_| { - deeply_normalize_with_skipped_universes( - self.at, - ct, - vec![None; ct.outer_exclusive_binder().as_usize()], - ) - }) - .unwrap_or_else(|_: Vec>| ct.super_fold_with(self)) + let result = + infcx.commit_if_ok(|_| { + deeply_normalize_with_skipped_universes_and_ambiguous_goals::< + _, + ScrubbedTraitError<'tcx>, + >(self.at, ct, vec![None; ct.outer_exclusive_binder().as_usize()]) + }); + match result { + Ok((ct, _)) => ct, + Err(_) => ct.super_fold_with(self), + } } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1b76d48e4310..a11f8d3a9ec6 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -162,7 +162,7 @@ where self.select(selcx) } - fn drain_unstalled_obligations( + fn drain_stalled_obligations_for_coroutines( &mut self, infcx: &InferCtxt<'tcx>, ) -> PredicateObligations<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4d88a23250a7..5255b57c7912 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1498,7 +1498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // However, if we disqualify *all* goals from being cached, perf suffers. // This is likely fixed by better caching in general in the new solver. // See: . - TypingMode::Analysis { defining_opaque_types } + TypingMode::Analysis { defining_opaque_types, stalled_generators: _ } | TypingMode::Borrowck { defining_opaque_types } => { defining_opaque_types.is_empty() || !pred.has_opaque_types() } diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index cd730aeeea90..b6e19b9901c4 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -1,6 +1,7 @@ use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_middle::query::Providers; @@ -355,6 +356,51 @@ fn opaque_types_defined_by<'tcx>( tcx.mk_local_def_ids(&collector.opaques) } -pub(super) fn provide(providers: &mut Providers) { - *providers = Providers { opaque_types_defined_by, ..*providers }; +// TODO: Move this out of `opaque_types` +fn stalled_generators_within<'tcx>( + tcx: TyCtxt<'tcx>, + item: LocalDefId, +) -> &'tcx ty::List { + if !tcx.next_trait_solver_globally() { + return ty::List::empty(); + } + + let body = tcx.hir_body_owned_by(item); + let mut collector = + StalledGeneratorVisitor { tcx, root_def_id: item.to_def_id(), stalled_coroutines: vec![] }; + collector.visit_body(body); + tcx.mk_local_def_ids(&collector.stalled_coroutines) +} + +struct StalledGeneratorVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + root_def_id: DefId, + stalled_coroutines: Vec, +} + +impl<'tcx> Visitor<'tcx> for StalledGeneratorVisitor<'tcx> { + fn visit_nested_body(&mut self, id: hir::BodyId) { + if self.tcx.typeck_root_def_id(self.tcx.hir_body_owner_def_id(id).to_def_id()) + == self.root_def_id + { + let body = self.tcx.hir_body(id); + self.visit_body(body); + } + } + + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Closure(&hir::Closure { + def_id, + kind: hir::ClosureKind::Coroutine(_), + .. + }) = ex.kind + { + self.stalled_coroutines.push(def_id); + } + intravisit::walk_expr(self, ex); + } +} + +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { opaque_types_defined_by, stalled_generators_within, ..*providers }; } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index fec6e24e2cb4..3570de064cb1 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -65,7 +65,7 @@ pub enum TypingMode { /// let x: <() as Assoc>::Output = true; /// } /// ``` - Analysis { defining_opaque_types: I::DefiningOpaqueTypes }, + Analysis { defining_opaque_types: I::LocalDefIds, stalled_generators: I::LocalDefIds }, /// The behavior during MIR borrowck is identical to `TypingMode::Analysis` /// except that the initial value for opaque types is the type computed during /// HIR typeck with unique unconstrained region inference variables. @@ -73,13 +73,13 @@ pub enum TypingMode { /// This is currently only used with by the new solver as it results in new /// non-universal defining uses of opaque types, which is a breaking change. /// See tests/ui/impl-trait/non-defining-use/as-projection-term.rs. - Borrowck { defining_opaque_types: I::DefiningOpaqueTypes }, + Borrowck { defining_opaque_types: I::LocalDefIds }, /// Any analysis after borrowck for a given body should be able to use all the /// hidden types defined by borrowck, without being able to define any new ones. /// /// This is currently only used by the new solver, but should be implemented in /// the old solver as well. - PostBorrowckAnalysis { defined_opaque_types: I::DefiningOpaqueTypes }, + PostBorrowckAnalysis { defined_opaque_types: I::LocalDefIds }, /// After analysis, mostly during codegen and MIR optimizations, we're able to /// reveal all opaque types. As the concrete type should *never* be observable /// directly by the user, this should not be used by checks which may expose @@ -94,13 +94,26 @@ pub enum TypingMode { impl TypingMode { /// Analysis outside of a body does not define any opaque types. pub fn non_body_analysis() -> TypingMode { - TypingMode::Analysis { defining_opaque_types: Default::default() } + TypingMode::Analysis { + defining_opaque_types: Default::default(), + stalled_generators: Default::default(), + } + } + + pub fn typeck_for_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode { + TypingMode::Analysis { + defining_opaque_types: cx.opaque_types_defined_by(body_def_id), + stalled_generators: cx.stalled_generators_within(body_def_id), + } } /// While typechecking a body, we need to be able to define the opaque /// types defined by that body. pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode { - TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } + TypingMode::Analysis { + defining_opaque_types: cx.opaque_types_defined_by(body_def_id), + stalled_generators: Default::default(), + } } pub fn borrowck(cx: I, body_def_id: I::LocalDefId) -> TypingMode { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 71bfeabfda87..afd7b88c256c 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -56,7 +56,7 @@ pub trait Interner: data: PredefinedOpaquesData, ) -> Self::PredefinedOpaques; - type DefiningOpaqueTypes: Copy + type LocalDefIds: Copy + Debug + Hash + Default @@ -330,10 +330,9 @@ pub trait Interner: binder: ty::Binder, ) -> ty::Binder; - fn opaque_types_defined_by( - self, - defining_anchor: Self::LocalDefId, - ) -> Self::DefiningOpaqueTypes; + fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds; + + fn stalled_generators_within(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`