From 67df5b9cfa990720d6606c663e451acd059def47 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Mar 2025 21:17:28 +0000 Subject: [PATCH 1/6] Collect and resolve ambiguous obligations from normalizing in writeback --- compiler/rustc_hir_typeck/src/writeback.rs | 53 ++++++++++++++++--- compiler/rustc_trait_selection/src/solve.rs | 5 +- .../src/solve/normalize.rs | 36 ++++++++++++- 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6ba7435cb790d..3caaa7f9a9d0b 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -8,6 +8,7 @@ use rustc_data_structures::unord::ExtendUnord; use rustc_errors::ErrorGuaranteed; use rustc_hir::intravisit::{self, InferKind, Visitor}; use rustc_hir::{self as hir, AmbigArg, HirId}; +use rustc_infer::traits::solve::Goal; use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -763,7 +764,32 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { T: TypeFoldable>, { let value = self.fcx.resolve_vars_if_possible(value); - let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true)); + + let mut goals = vec![]; + let value = + value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true, &mut goals)); + + // Ensure that we resolve goals we get from normalizing coroutine interiors, + // but we shouldn't expect those goals to need normalizing (or else we'd get + // into a somewhat awkward fixpoint situation, and we don't need it anyways). + let mut unexpected_goals = vec![]; + self.typeck_results.coroutine_stalled_predicates.extend( + goals + .into_iter() + .map(|pred| { + self.fcx.resolve_vars_if_possible(pred).fold_with(&mut Resolver::new( + self.fcx, + span, + self.body, + false, + &mut unexpected_goals, + )) + }) + // FIXME: throwing away the param-env :( + .map(|goal| (goal.predicate, self.fcx.misc(span.to_span(self.fcx.tcx)))), + ); + assert_eq!(unexpected_goals, vec![]); + assert!(!value.has_infer()); // We may have introduced e.g. `ty::Error`, if inference failed, make sure @@ -781,7 +807,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { T: TypeFoldable>, { let value = self.fcx.resolve_vars_if_possible(value); - let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false)); + + let mut goals = vec![]; + let value = + value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false, &mut goals)); + assert_eq!(goals, vec![]); + assert!(!value.has_infer()); // We may have introduced e.g. `ty::Error`, if inference failed, make sure @@ -818,6 +849,7 @@ struct Resolver<'cx, 'tcx> { /// Whether we should normalize using the new solver, disabled /// both when using the old solver and when resolving predicates. should_normalize: bool, + nested_goals: &'cx mut Vec>>, } impl<'cx, 'tcx> Resolver<'cx, 'tcx> { @@ -826,8 +858,9 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, should_normalize: bool, + nested_goals: &'cx mut Vec>>, ) -> Resolver<'cx, 'tcx> { - Resolver { fcx, span, body, should_normalize } + Resolver { fcx, span, body, nested_goals, should_normalize } } fn report_error(&self, p: impl Into>) -> ErrorGuaranteed { @@ -864,12 +897,18 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { let cause = ObligationCause::misc(self.span.to_span(tcx), body_id); let at = self.fcx.at(&cause, self.fcx.param_env); let universes = vec![None; outer_exclusive_binder(value).as_usize()]; - solve::deeply_normalize_with_skipped_universes(at, value, universes).unwrap_or_else( - |errors| { + match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals( + at, value, universes, + ) { + Ok((value, goals)) => { + self.nested_goals.extend(goals); + value + } + Err(errors) => { let guar = self.fcx.err_ctxt().report_fulfillment_errors(errors); new_err(tcx, guar) - }, - ) + } + } } else { value }; diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index d425ab50ae0fd..0c2451a80a705 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -9,5 +9,8 @@ mod select; pub(crate) use delegate::SolverDelegate; pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub(crate) use normalize::deeply_normalize_for_diagnostics; -pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +pub use normalize::{ + deeply_normalize, deeply_normalize_with_skipped_universes, + deeply_normalize_with_skipped_universes_and_ambiguous_goals, +}; pub use select::InferCtxtSelectExt; diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 79fb044a67f88..7b80059722a20 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::InferCtxt; use rustc_infer::infer::at::At; +use rustc_infer::traits::solve::Goal; use rustc_infer::traits::{FromSolverError, Obligation, TraitEngine}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{ @@ -41,6 +42,30 @@ pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>( value: T, universes: Vec>, ) -> Result> +where + T: TypeFoldable>, + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ + let (value, goals) = + deeply_normalize_with_skipped_universes_and_ambiguous_goals(at, value, universes)?; + assert_eq!(goals, vec![]); + + Ok(value) +} + +/// Deeply normalize all aliases in `value`. This does not handle inference and expects +/// its input to be already fully resolved. +/// +/// Additionally takes a list of universes which represents the binders which have been +/// entered before passing `value` to the function. This is currently needed for +/// `normalize_erasing_regions`, which skips binders as it walks through a type. +/// +/// TODO: doc +pub fn deeply_normalize_with_skipped_universes_and_ambiguous_goals<'tcx, T, E>( + at: At<'_, 'tcx>, + value: T, + universes: Vec>, +) -> Result<(T, Vec>>), Vec> where T: TypeFoldable>, E: FromSolverError<'tcx, NextSolverError<'tcx>>, @@ -48,8 +73,15 @@ where let fulfill_cx = FulfillmentCtxt::new(at.infcx); let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes, _errors: PhantomData }; - - value.try_fold_with(&mut folder) + let value = value.try_fold_with(&mut folder)?; + let goals = folder + .fulfill_cx + .drain_unstalled_obligations(at.infcx) + .into_iter() + .map(|obl| obl.as_goal()) + .collect(); + let errors = folder.fulfill_cx.select_all_or_error(at.infcx); + if errors.is_empty() { Ok((value, goals)) } else { Err(errors) } } struct NormalizationFolder<'me, 'tcx, E> { From 169955f3be4659e486db9b7dabafdbcee18819a3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Mar 2025 23:49:14 +0000 Subject: [PATCH 2/6] 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 | 50 ++++++++- compiler/rustc_type_ir/src/infer_ctxt.rs | 23 +++- compiler/rustc_type_ir/src/interner.rs | 9 +- 19 files changed, 241 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index b8968b58769a2..b7ae66eba6f4b 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 87d92b3fbde8d..3cf7d277f1fde 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 5b4fc51cec885..ac69493d9567e 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 529e996ad1e7d..3b0e85601592f 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 1eae10673b62b..9e51a53ae95fa 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 e94f088304b19..4d4096b02254a 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 a099f77041709..c16adef63eaeb 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 fa2f1cf1a1c87..f8f66b58c1db8 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 7641e9a16ee62..8868769906d27 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 aa89e77bb6fb9..dcfc3b3a701cf 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 7bd1300f34ed7..38c4d0205cd50 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 192e632a2d5b9..abee5ac52c1c8 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 d8dcd12aecb98..e31cad6b40dd5 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 7b80059722a20..65ab14ae07cda 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 1b76d48e43109..a11f8d3a9ec6b 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 4d88a23250a7e..5255b57c7912a 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 cd730aeeea900..b6e19b9901c4c 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) } +// 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, ..*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 fec6e24e2cb4d..3570de064cb11 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 71bfeabfda878..afd7b88c256c4 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` From a9229833932e2fc094ea60121c269c127dff100b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Mar 2025 23:56:11 +0000 Subject: [PATCH 3/6] Eagerly instantiate coroutine witness in new solver --- compiler/rustc_hir_typeck/src/closure.rs | 9 +++- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 45 ++++++++++--------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index b7ae66eba6f4b..8fd59999fce5e 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -163,10 +163,15 @@ 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 + // 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); + let interior = if self.next_trait_solver() { + Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args) + } else { + self.next_ty_var(expr_span) + }; + self.deferred_coroutine_interiors.borrow_mut().push((expr_def_id, interior)); // Coroutines that come from coroutine closures have not yet determined diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 3cf7d277f1fde..cac8237f8f61a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -635,28 +635,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut obligations = vec![]; - for &(coroutine_def_id, interior) in coroutines.iter() { - debug!(?coroutine_def_id); + if !self.next_trait_solver() { + for &(coroutine_def_id, interior) in coroutines.iter() { + debug!(?coroutine_def_id); + + // Create the `CoroutineWitness` type that we will unify with `interior`. + let args = ty::GenericArgs::identity_for_item( + self.tcx, + self.tcx.typeck_root_def_id(coroutine_def_id.to_def_id()), + ); + let witness = + Ty::new_coroutine_witness(self.tcx, coroutine_def_id.to_def_id(), args); - // Create the `CoroutineWitness` type that we will unify with `interior`. - let args = ty::GenericArgs::identity_for_item( - self.tcx, - self.tcx.typeck_root_def_id(coroutine_def_id.to_def_id()), - ); - let witness = Ty::new_coroutine_witness(self.tcx, coroutine_def_id.to_def_id(), args); - - // Unify `interior` with `witness` and collect all the resulting obligations. - let span = self.tcx.hir_body_owned_by(coroutine_def_id).value.span; - let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else { - span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind()) - }; - let ok = self - .at(&self.misc(span), self.param_env) - // Will never define opaque types, as all we do is instantiate a type variable. - .eq(DefineOpaqueTypes::Yes, interior, witness) - .expect("Failed to unify coroutine interior type"); - - obligations.extend(ok.obligations); + // Unify `interior` with `witness` and collect all the resulting obligations. + let span = self.tcx.hir_body_owned_by(coroutine_def_id).value.span; + let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else { + span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind()) + }; + let ok = self + .at(&self.misc(span), self.param_env) + // Will never define opaque types, as all we do is instantiate a type variable. + .eq(DefineOpaqueTypes::Yes, interior, witness) + .expect("Failed to unify coroutine interior type"); + + obligations.extend(ok.obligations); + } } if !coroutines.is_empty() { From 1727badf77704a5c44c40a30df833702ed309324 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 1 Apr 2025 23:03:12 +0000 Subject: [PATCH 4/6] Don't compute query unless in new solver --- compiler/rustc_middle/src/ty/context.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f8f66b58c1db8..f5872f0269ec4 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -679,7 +679,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } fn stalled_generators_within(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds { - self.stalled_generators_within(defining_anchor) + if self.next_trait_solver_globally() { + self.stalled_generators_within(defining_anchor) + } else { + ty::List::empty() + } } } From 7c1661f9457825df6e6bbf4869be3cad59b608a9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Apr 2025 17:26:30 +0000 Subject: [PATCH 5/6] Consider Copy/Clone too --- .../src/solve/trait_goals.rs | 17 +++++++++++++++++ compiler/rustc_trait_selection/src/infer.rs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) 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 38c4d0205cd50..13132d60dfae4 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,7 @@ where } } + // TODO: if let ty::CoroutineWitness(def_id, _) = goal.predicate.self_ty().kind() { match ecx.typing_mode() { TypingMode::Analysis { stalled_generators, defining_opaque_types: _ } => { @@ -274,6 +275,22 @@ where return Err(NoSolution); } + // TODO: + 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/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 84ac229b743d9..0dab3adadb033 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -34,7 +34,7 @@ impl<'tcx> InferCtxt<'tcx> { // FIXME(#132279): This should be removed as it causes us to incorrectly // handle opaques in their defining scope. - if !(param_env, ty).has_infer() { + if !self.next_trait_solver() && !(param_env, ty).has_infer() { return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty); } From f943f73db4791d64ff83d72986da8d6250c42933 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 22 Apr 2025 23:31:22 +0000 Subject: [PATCH 6/6] More --- compiler/rustc_infer/src/infer/mod.rs | 6 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 17 ++++-- .../rustc_next_trait_solver/src/solve/mod.rs | 5 +- .../src/solve/normalizes_to/opaque_types.rs | 4 +- .../src/solve/trait_goals.rs | 58 ++++++++++--------- .../src/solve/fulfill.rs | 47 ++++++++++----- .../src/solve/normalize.rs | 42 +++++++++----- .../src/traits/select/mod.rs | 4 +- compiler/rustc_ty_utils/src/lib.rs | 2 + compiler/rustc_ty_utils/src/opaque_types.rs | 50 +--------------- .../rustc_ty_utils/src/stalled_generators.rs | 54 +++++++++++++++++ compiler/rustc_type_ir/src/infer_ctxt.rs | 17 +++--- compiler/rustc_type_ir/src/interner.rs | 5 +- .../async-closures/is-not-fn.next.stderr | 6 +- .../async-await/async-closures/is-not-fn.rs | 3 +- tests/ui/coroutine/clone-rpit.next.stderr | 47 --------------- tests/ui/coroutine/clone-rpit.rs | 3 +- 19 files changed, 189 insertions(+), 187 deletions(-) create mode 100644 compiler/rustc_ty_utils/src/stalled_generators.rs delete mode 100644 tests/ui/coroutine/clone-rpit.next.stderr diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 3b0e85601592f..c4698e5cbb456 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -967,7 +967,9 @@ 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, stalled_generators: _ } + TypingMode::Analysis { + defining_opaque_types_and_generators: defining_opaque_types, + } | TypingMode::Borrowck { defining_opaque_types } => { id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id)) } @@ -1262,7 +1264,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: _, stalled_generators: _ } + ty::TypingMode::Analysis { defining_opaque_types_and_generators: _ } | ty::TypingMode::Borrowck { defining_opaque_types: _ } => { TypingMode::non_body_analysis() } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4d4096b02254a..3432648feab07 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -391,7 +391,7 @@ rustc_queries! { key: LocalDefId ) -> &'tcx ty::List { desc { - |tcx| "computing the opaque types defined by `{}`", + |tcx| "computing the coroutines defined within `{}`", tcx.def_path_str(key.to_def_id()) } } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index c16adef63eaeb..69b6f88d72bfd 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 96 bytes by accident. + // Ensure that keys grow no larger than 88 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::>() > 96 { + if size_of::>() > 88 { 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 f5872f0269ec4..98057a25f04c7 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -678,11 +678,18 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.opaque_types_defined_by(defining_anchor) } - fn stalled_generators_within(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds { + fn opaque_types_and_generators_defined_by( + self, + defining_anchor: Self::LocalDefId, + ) -> Self::LocalDefIds { if self.next_trait_solver_globally() { - self.stalled_generators_within(defining_anchor) + self.mk_local_def_ids_from_iter( + self.opaque_types_defined_by(defining_anchor) + .iter() + .chain(self.stalled_generators_within(defining_anchor)), + ) } else { - ty::List::empty() + self.opaque_types_defined_by(defining_anchor) } } } @@ -2914,11 +2921,11 @@ impl<'tcx> TyCtxt<'tcx> { self.interners.intern_clauses(clauses) } - pub fn mk_local_def_ids(self, clauses: &[LocalDefId]) -> &'tcx List { + pub fn mk_local_def_ids(self, def_ids: &[LocalDefId]) -> &'tcx List { // FIXME consider asking the input slice to be sorted to avoid // re-interning permutations, in which case that would be asserted // here. - self.intern_local_def_ids(clauses) + self.intern_local_def_ids(def_ids) } pub fn mk_local_def_ids_from_iter(self, iter: I) -> T::Output diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 8868769906d27..0695c5acdcab3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -329,10 +329,7 @@ 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, - stalled_generators: _, - } + TypingMode::Analysis { defining_opaque_types_and_generators: non_rigid_opaques } | 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 dcfc3b3a701cf..ee439f1b3d0d5 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,11 +33,11 @@ where ); self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } - TypingMode::Analysis { defining_opaque_types, stalled_generators: _ } => { + TypingMode::Analysis { defining_opaque_types_and_generators } => { let Some(def_id) = opaque_ty .def_id .as_local() - .filter(|&def_id| defining_opaque_types.contains(&def_id)) + .filter(|&def_id| defining_opaque_types_and_generators.contains(&def_id)) else { self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); 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 13132d60dfae4..827853be280ed 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -208,20 +208,9 @@ where } } - // TODO: - 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: _ } => {} - } + // We need to make sure to stall any coroutines we are inferring to avoid query cycles. + if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) { + return cand; } ecx.probe_and_evaluate_goal_for_constituent_tys( @@ -275,20 +264,9 @@ where return Err(NoSolution); } - // TODO: - 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: _ } => {} - } + // We need to make sure to stall any coroutines we are inferring to avoid query cycles. + if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) { + return cand; } ecx.probe_and_evaluate_goal_for_constituent_tys( @@ -1400,4 +1378,28 @@ where let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); self.merge_trait_candidates(goal, candidates) } + + fn try_stall_coroutine_witness( + &mut self, + self_ty: I::Ty, + ) -> Option, NoSolution>> { + if let ty::CoroutineWitness(def_id, _) = self_ty.kind() { + match self.typing_mode() { + TypingMode::Analysis { + defining_opaque_types_and_generators: stalled_generators, + } => { + if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id)) + { + return Some(self.forced_ambiguity(MaybeCause::Ambiguity)); + } + } + TypingMode::Coherence + | TypingMode::PostAnalysis + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {} + } + } + + None + } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index abee5ac52c1c8..848d0646d009f 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{ }; use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; use rustc_span::Span; +use rustc_type_ir::data_structures::DelayedSet; use tracing::instrument; use self::derive_errors::*; @@ -217,26 +218,30 @@ where &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; + let stalled_generators = match infcx.typing_mode() { + TypingMode::Analysis { defining_opaque_types_and_generators } => { + defining_opaque_types_and_generators } + TypingMode::Coherence + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } + | TypingMode::PostAnalysis => return Default::default(), + }; + + if stalled_generators.is_empty() { + return Default::default(); + } + self.obligations.drain_pending(|obl| { infcx.probe(|_| { infcx .visit_proof_tree( obl.as_goal(), - &mut StalledOnCoroutines { stalled_generators, span: obl.cause.span }, + &mut StalledOnCoroutines { + stalled_generators, + span: obl.cause.span, + cache: Default::default(), + }, ) .is_break() }) @@ -244,10 +249,18 @@ where } } +/// Detect if a goal is stalled on a coroutine that is owned by the current typeck root. +/// +/// This function can (erroneously) fail to detect a predicate, i.e. it doesn't need to +/// be complete. However, this will lead to ambiguity errors, so we want to make it +/// accurate. +/// +/// This function can be also return false positives, which will lead to poor diagnostics +/// so we want to keep this visitor *precise* too. struct StalledOnCoroutines<'tcx> { stalled_generators: &'tcx ty::List, span: Span, - // TODO: Cache + cache: DelayedSet>, } impl<'tcx> inspect::ProofTreeVisitor<'tcx> for StalledOnCoroutines<'tcx> { @@ -272,6 +285,10 @@ impl<'tcx> TypeVisitor> for StalledOnCoroutines<'tcx> { type Result = ControlFlow<()>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + if !self.cache.insert(ty) { + return ControlFlow::Continue(()); + } + if let ty::CoroutineWitness(def_id, _) = *ty.kind() && def_id.as_local().is_some_and(|def_id| self.stalled_generators.contains(&def_id)) { diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 65ab14ae07cda..5f1e63ab225ab 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,6 +1,5 @@ use std::assert_matches::assert_matches; use std::fmt::Debug; -use std::marker::PhantomData; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::InferCtxt; @@ -60,7 +59,8 @@ where /// entered before passing `value` to the function. This is currently needed for /// `normalize_erasing_regions`, which skips binders as it walks through a type. /// -/// TODO: doc +/// This returns a set of stalled obligations if the typing mode of the underlying infcx +/// has any stalled coroutine def ids. pub fn deeply_normalize_with_skipped_universes_and_ambiguous_goals<'tcx, T, E>( at: At<'_, 'tcx>, value: T, @@ -72,16 +72,10 @@ where { let fulfill_cx = FulfillmentCtxt::new(at.infcx); let mut folder = - NormalizationFolder { at, fulfill_cx, depth: 0, universes, _errors: PhantomData }; + NormalizationFolder { at, fulfill_cx, depth: 0, universes, stalled_goals: vec![] }; let value = value.try_fold_with(&mut folder)?; - let goals = folder - .fulfill_cx - .drain_stalled_obligations_for_coroutines(at.infcx) - .into_iter() - .map(|obl| obl.as_goal()) - .collect(); let errors = folder.fulfill_cx.select_all_or_error(at.infcx); - if errors.is_empty() { Ok((value, goals)) } else { Err(errors) } + if errors.is_empty() { Ok((value, folder.stalled_goals)) } else { Err(errors) } } struct NormalizationFolder<'me, 'tcx, E> { @@ -89,7 +83,7 @@ struct NormalizationFolder<'me, 'tcx, E> { fulfill_cx: FulfillmentCtxt<'tcx, E>, depth: usize, universes: Vec>, - _errors: PhantomData, + stalled_goals: Vec>>, } impl<'tcx, E> NormalizationFolder<'_, 'tcx, E> @@ -130,10 +124,7 @@ where ); self.fulfill_cx.register_predicate_obligation(infcx, obligation); - let errors = self.fulfill_cx.select_where_possible(infcx); - if !errors.is_empty() { - return Err(errors); - } + self.select_all_and_stall_coroutine_predicates()?; // Alias is guaranteed to be fully structurally resolved, // so we can super fold here. @@ -184,6 +175,27 @@ where self.depth -= 1; Ok(result) } + + fn select_all_and_stall_coroutine_predicates(&mut self) -> Result<(), Vec> { + let errors = self.fulfill_cx.select_where_possible(self.at.infcx); + if !errors.is_empty() { + return Err(errors); + } + + self.stalled_goals.extend( + self.fulfill_cx + .drain_stalled_obligations_for_coroutines(self.at.infcx) + .into_iter() + .map(|obl| obl.as_goal()), + ); + + let errors = self.fulfill_cx.collect_remaining_errors(self.at.infcx); + if !errors.is_empty() { + return Err(errors); + } + + Ok(()) + } } impl<'tcx, E> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx, E> diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5255b57c7912a..c7ce13c8014f0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1498,7 +1498,9 @@ 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, stalled_generators: _ } + TypingMode::Analysis { + defining_opaque_types_and_generators: defining_opaque_types, + } | TypingMode::Borrowck { defining_opaque_types } => { defining_opaque_types.is_empty() || !pred.has_opaque_types() } diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 35cc6f3985652..57051e0df5550 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -32,6 +32,7 @@ mod needs_drop; mod opaque_types; mod representability; pub mod sig_types; +mod stalled_generators; mod structural_match; mod ty; @@ -50,4 +51,5 @@ pub fn provide(providers: &mut Providers) { ty::provide(providers); instance::provide(providers); structural_match::provide(providers); + stalled_generators::provide(providers); } diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index b6e19b9901c4c..cd730aeeea900 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -1,7 +1,6 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_middle::query::Providers; @@ -356,51 +355,6 @@ fn opaque_types_defined_by<'tcx>( tcx.mk_local_def_ids(&collector.opaques) } -// 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 }; + *providers = Providers { opaque_types_defined_by, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/stalled_generators.rs b/compiler/rustc_ty_utils/src/stalled_generators.rs new file mode 100644 index 0000000000000..8b45e8b0f6f9a --- /dev/null +++ b/compiler/rustc_ty_utils/src/stalled_generators.rs @@ -0,0 +1,54 @@ +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit; +use rustc_hir::intravisit::Visitor; +use rustc_middle::query::Providers; +use rustc_middle::ty::{self, TyCtxt}; + +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 { 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 3570de064cb11..8fa56c3599963 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::LocalDefIds, stalled_generators: I::LocalDefIds }, + Analysis { defining_opaque_types_and_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. @@ -94,25 +94,24 @@ 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(), - stalled_generators: Default::default(), - } + TypingMode::Analysis { defining_opaque_types_and_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), + defining_opaque_types_and_generators: cx + .opaque_types_and_generators_defined_by(body_def_id), } } /// While typechecking a body, we need to be able to define the opaque /// types defined by that body. + /// + /// FIXME: This will be removed because it's generally not correct to define + /// opaques outside of HIR typeck. 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), - stalled_generators: Default::default(), + defining_opaque_types_and_generators: cx.opaque_types_defined_by(body_def_id), } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index afd7b88c256c4..ab38556589e03 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -332,7 +332,10 @@ pub trait Interner: fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds; - fn stalled_generators_within(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds; + fn opaque_types_and_generators_defined_by( + self, + defining_anchor: Self::LocalDefId, + ) -> Self::LocalDefIds; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/tests/ui/async-await/async-closures/is-not-fn.next.stderr b/tests/ui/async-await/async-closures/is-not-fn.next.stderr index 0fab1c15f27df..970970a915114 100644 --- a/tests/ui/async-await/async-closures/is-not-fn.next.stderr +++ b/tests/ui/async-await/async-closures/is-not-fn.next.stderr @@ -1,13 +1,11 @@ -error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to return `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` +error[E0271]: type mismatch resolving `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25} == ()` --> $DIR/is-not-fn.rs:8:14 | LL | needs_fn(async || {}); - | -------- ^^^^^^^^^^^ expected `()`, found `async` closure body + | -------- ^^^^^^^^^^^ types differ | | | required by a bound introduced by this call | - = note: expected unit type `()` - found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` note: required by a bound in `needs_fn` --> $DIR/is-not-fn.rs:7:25 | diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs index e5ab4742daba1..c09ccb3fc2b09 100644 --- a/tests/ui/async-await/async-closures/is-not-fn.rs +++ b/tests/ui/async-await/async-closures/is-not-fn.rs @@ -6,5 +6,6 @@ fn main() { fn needs_fn(x: impl FnOnce()) {} needs_fn(async || {}); - //~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to return `()` + //[current]~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to return `()` + //[next]~^^ ERROR type mismatch resolving `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25} == ()` } diff --git a/tests/ui/coroutine/clone-rpit.next.stderr b/tests/ui/coroutine/clone-rpit.next.stderr deleted file mode 100644 index 213e9e908f56d..0000000000000 --- a/tests/ui/coroutine/clone-rpit.next.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0391]: cycle detected when type-checking `foo` - --> $DIR/clone-rpit.rs:13:1 - | -LL | pub fn foo<'a, 'b>() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires coroutine witness types for `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:15:5 - | -LL | move |_: ()| { - | ^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:15:5 - | -LL | move |_: ()| { - | ^^^^^^^^^^^^ -note: ...which requires checking if `foo::{closure#0}` contains FFI-unwind calls... - --> $DIR/clone-rpit.rs:15:5 - | -LL | move |_: ()| { - | ^^^^^^^^^^^^ -note: ...which requires building MIR for `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:15:5 - | -LL | move |_: ()| { - | ^^^^^^^^^^^^ -note: ...which requires match-checking `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:15:5 - | -LL | move |_: ()| { - | ^^^^^^^^^^^^ -note: ...which requires type-checking `foo::{closure#0}`... - --> $DIR/clone-rpit.rs:15:5 - | -LL | move |_: ()| { - | ^^^^^^^^^^^^ - = note: ...which again requires type-checking `foo`, completing the cycle -note: cycle used when match-checking `foo` - --> $DIR/clone-rpit.rs:13:1 - | -LL | pub fn foo<'a, 'b>() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/coroutine/clone-rpit.rs b/tests/ui/coroutine/clone-rpit.rs index 66569b4f42741..3882564639b4e 100644 --- a/tests/ui/coroutine/clone-rpit.rs +++ b/tests/ui/coroutine/clone-rpit.rs @@ -1,8 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[current] check-pass -//@[next] known-bug: trait-system-refactor-initiative#82 +//@ check-pass #![feature(coroutines, coroutine_trait, coroutine_clone)]