diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index e351b650a16c1..10e673cd9297b 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -95,6 +95,10 @@ pub trait ForestObligation: Clone + Debug { pub trait ObligationProcessor { type Obligation: ForestObligation; type Error: Debug; + type OUT: OutcomeTrait< + Obligation = Self::Obligation, + Error = Error, + >; fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool; @@ -111,7 +115,11 @@ pub trait ObligationProcessor { /// In other words, if we had O1 which required O2 which required /// O3 which required O1, we would give an iterator yielding O1, /// O2, O3 (O1 is not yielded twice). - fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c Self::Obligation>) + fn process_backedge<'c, I>( + &mut self, + cycle: I, + _marker: PhantomData<&'c Self::Obligation>, + ) -> Result<(), Self::Error> where I: Clone + Iterator; } @@ -402,12 +410,11 @@ impl ObligationForest { /// Performs a fixpoint computation over the obligation list. #[inline(never)] - pub fn process_obligations(&mut self, processor: &mut P) -> OUT + pub fn process_obligations

(&mut self, processor: &mut P) -> P::OUT where P: ObligationProcessor, - OUT: OutcomeTrait>, { - let mut outcome = OUT::new(); + let mut outcome = P::OUT::new(); // Fixpoint computation: we repeat until the inner loop stalls. loop { @@ -473,7 +480,7 @@ impl ObligationForest { } self.mark_successes(); - self.process_cycles(processor); + self.process_cycles(processor, &mut outcome); self.compress(|obl| outcome.record_completed(obl)); } @@ -558,7 +565,7 @@ impl ObligationForest { /// Report cycles between all `Success` nodes, and convert all `Success` /// nodes to `Done`. This must be called after `mark_successes`. - fn process_cycles

(&mut self, processor: &mut P) + fn process_cycles

(&mut self, processor: &mut P, outcome: &mut P::OUT) where P: ObligationProcessor, { @@ -568,7 +575,7 @@ impl ObligationForest { // to handle the no-op cases immediately to avoid the cost of the // function call. if node.state.get() == NodeState::Success { - self.find_cycles_from_node(&mut stack, processor, index); + self.find_cycles_from_node(&mut stack, processor, index, outcome); } } @@ -576,8 +583,13 @@ impl ObligationForest { self.reused_node_vec = stack; } - fn find_cycles_from_node

(&self, stack: &mut Vec, processor: &mut P, index: usize) - where + fn find_cycles_from_node

( + &self, + stack: &mut Vec, + processor: &mut P, + index: usize, + outcome: &mut P::OUT, + ) where P: ObligationProcessor, { let node = &self.nodes[index]; @@ -586,17 +598,20 @@ impl ObligationForest { None => { stack.push(index); for &dep_index in node.dependents.iter() { - self.find_cycles_from_node(stack, processor, dep_index); + self.find_cycles_from_node(stack, processor, dep_index, outcome); } stack.pop(); node.state.set(NodeState::Done); } Some(rpos) => { // Cycle detected. - processor.process_backedge( + let result = processor.process_backedge( stack[rpos..].iter().map(|&i| &self.nodes[i].obligation), PhantomData, ); + if let Err(err) = result { + outcome.record_error(Error { error: err, backtrace: self.error_at(index) }); + } } } } diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs index e2991aae1742c..bc252f772a168 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs @@ -64,6 +64,7 @@ where { type Obligation = O; type Error = E; + type OUT = TestOutcome; fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool { true @@ -76,10 +77,15 @@ where (self.process_obligation)(obligation) } - fn process_backedge<'c, I>(&mut self, _cycle: I, _marker: PhantomData<&'c Self::Obligation>) + fn process_backedge<'c, I>( + &mut self, + _cycle: I, + _marker: PhantomData<&'c Self::Obligation>, + ) -> Result<(), Self::Error> where I: Clone + Iterator, { + Ok(()) } } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 4df4de21a0f07..ed2beefc6e773 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -105,6 +105,8 @@ pub struct FulfillmentError<'tcx> { #[derive(Clone)] pub enum FulfillmentErrorCode<'tcx> { + /// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented. + CodeCycle(Vec>>), CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeSubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 573d2d1e33016..1c6ab6a082b99 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -47,6 +47,7 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { write!(f, "CodeConstEquateError({:?}, {:?})", a, b) } super::CodeAmbiguity => write!(f, "Ambiguity"), + super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle), } } } diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 08adbcbd410c6..0155798c8b6d7 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -4,10 +4,12 @@ // general routines. use crate::infer::{DefiningAnchor, TyCtxtInferExt}; +use crate::traits::error_reporting::InferCtxtExt; use crate::traits::{ ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, Unimplemented, }; +use rustc_infer::traits::FulfillmentErrorCode; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt}; @@ -62,6 +64,14 @@ pub fn codegen_select_candidate<'tcx>( // optimization to stop iterating early. let errors = fulfill_cx.select_all_or_error(&infcx); if !errors.is_empty() { + // `rustc_monomorphize::collector` assumes there are no type errors. + // Cycle errors are the only post-monomorphization errors possible; emit them now so + // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. + for err in errors { + if let FulfillmentErrorCode::CodeCycle(cycle) = err.code { + infcx.report_overflow_error_cycle(&cycle); + } + } return Err(CodegenObligationError::FulfillmentError); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index efdb1ace13992..d62b399c1b562 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1540,6 +1540,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } diag.emit(); } + FulfillmentErrorCode::CodeCycle(ref cycle) => { + self.report_overflow_error_cycle(cycle); + } } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 3763a98c488b7..1cd8e1c21236f 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -25,10 +25,9 @@ use super::Unimplemented; use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation}; -use crate::traits::error_reporting::InferCtxtExt as _; use crate::traits::project::PolyProjectionObligation; use crate::traits::project::ProjectionCacheKeyExt as _; -use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +use crate::traits::query::evaluate_obligation::InferCtxtExt; impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { /// Note that we include both the `ParamEnv` and the `Predicate`, @@ -224,6 +223,7 @@ fn mk_pending(os: Vec>) -> Vec ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { type Obligation = PendingPredicateObligation<'tcx>; type Error = FulfillmentErrorCode<'tcx>; + type OUT = Outcome; /// Identifies whether a predicate obligation needs processing. /// @@ -602,14 +602,16 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { &mut self, cycle: I, _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, - ) where + ) -> Result<(), FulfillmentErrorCode<'tcx>> + where I: Clone + Iterator>, { if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { debug!("process_child_obligations: coinductive match"); + Ok(()) } else { let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); - self.selcx.infcx().report_overflow_error_cycle(&cycle); + Err(FulfillmentErrorCode::CodeCycle(cycle)) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 8b15e10ba9cbf..6bdd613be5aa7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -226,13 +226,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { - SelectionContext { - infcx, - freshener: infcx.freshener_keep_static(), - intercrate: true, - intercrate_ambiguity_causes: None, - query_mode: TraitQueryMode::Standard, - } + SelectionContext { intercrate: true, ..SelectionContext::new(infcx) } } pub fn with_query_mode( @@ -240,13 +234,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { query_mode: TraitQueryMode, ) -> SelectionContext<'cx, 'tcx> { debug!(?query_mode, "with_query_mode"); - SelectionContext { - infcx, - freshener: infcx.freshener_keep_static(), - intercrate: false, - intercrate_ambiguity_causes: None, - query_mode, - } + SelectionContext { query_mode, ..SelectionContext::new(infcx) } } /// Enables tracking of intercrate ambiguity causes. See diff --git a/src/test/rustdoc-ui/normalize-cycle.rs b/src/test/rustdoc-ui/normalize-cycle.rs index 14ffac1e1dce6..1ed9ac6bc34ac 100644 --- a/src/test/rustdoc-ui/normalize-cycle.rs +++ b/src/test/rustdoc-ui/normalize-cycle.rs @@ -1,4 +1,5 @@ // check-pass +// compile-flags: -Znormalize-docs // Regression test for . pub trait Query {}