From 39165e3ed645ad99deb2db73d66cc6a18546e6d7 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 17 Nov 2022 16:46:15 +0100 Subject: [PATCH 1/5] non-fatal overflow --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 16 +- .../src/const_eval/valtrees.rs | 20 +- .../src/transform/check_consts/check.rs | 4 +- .../src/transform/check_consts/ops.rs | 2 +- .../src/transform/check_consts/qualifs.rs | 2 +- .../src/obligation_forest/mod.rs | 19 +- .../src/obligation_forest/tests.rs | 10 +- .../src/impl_wf_check/min_specialization.rs | 3 + compiler/rustc_hir_typeck/src/coercion.rs | 5 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 4 +- compiler/rustc_infer/src/traits/engine.rs | 8 - compiler/rustc_infer/src/traits/mod.rs | 3 +- compiler/rustc_infer/src/traits/project.rs | 8 +- .../src/traits/structural_impls.rs | 17 - compiler/rustc_middle/src/infer/canonical.rs | 22 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 9 +- compiler/rustc_middle/src/traits/select.rs | 46 +- compiler/rustc_middle/src/ty/sty.rs | 11 +- compiler/rustc_middle/src/ty/util.rs | 24 +- .../rustc_trait_selection/src/autoderef.rs | 18 +- compiler/rustc_trait_selection/src/infer.rs | 4 +- .../src/traits/auto_trait.rs | 12 +- .../src/traits/chalk_fulfill.rs | 75 ++- .../src/traits/codegen.rs | 19 +- .../src/traits/coherence.rs | 2 +- .../src/traits/error_reporting/mod.rs | 30 +- .../src/traits/error_reporting/suggestions.rs | 12 +- .../src/traits/fulfill.rs | 121 ++--- .../rustc_trait_selection/src/traits/mod.rs | 19 +- .../src/traits/project.rs | 467 ++++++++++-------- .../src/traits/query/evaluate_obligation.rs | 61 +-- .../src/traits/query/normalize.rs | 51 +- .../src/traits/relationships.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 121 +++-- .../src/traits/select/confirmation.rs | 246 +++++---- .../src/traits/select/mod.rs | 427 +++++++--------- .../rustc_trait_selection/src/traits/wf.rs | 32 +- .../rustc_traits/src/evaluate_obligation.rs | 6 +- .../src/implied_outlives_bounds.rs | 8 +- .../src/normalize_projection_ty.rs | 12 +- src/librustdoc/clean/blanket_impl.rs | 8 +- 43 files changed, 995 insertions(+), 995 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index cf590a43826e5..4cf05996cd411 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1745,9 +1745,11 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, match in_elem.kind() { ty::RawPtr(p) => { - let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| { - bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) - }); + let (metadata, check_sized) = + p.ty.ptr_metadata_ty(bx.tcx, |ty| { + Ok(bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)) + }) + .unwrap(); assert!(!check_sized); // we are in codegen, so we shouldn't see these types require!(metadata.is_unit(), "cannot cast fat pointer `{}`", in_elem) } @@ -1755,9 +1757,11 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, } match out_elem.kind() { ty::RawPtr(p) => { - let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| { - bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) - }); + let (metadata, check_sized) = + p.ty.ptr_metadata_ty(bx.tcx, |ty| { + Ok(bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)) + }) + .unwrap(); assert!(!check_sized); // we are in codegen, so we shouldn't see these types require!(metadata.is_unit(), "cannot cast to fat pointer `{}`", out_elem) } diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index f4da11883957a..3f1148b2f28cd 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -177,15 +177,17 @@ fn get_info_on_unsized_field<'tcx>( tcx: TyCtxt<'tcx>, ) -> (Ty<'tcx>, usize) { let mut last_valtree = valtree; - let tail = tcx.struct_tail_with_normalize( - ty, - |ty| ty, - || { - let branches = last_valtree.unwrap_branch(); - last_valtree = branches[branches.len() - 1]; - debug!(?branches, ?last_valtree); - }, - ); + let tail = tcx + .struct_tail_with_normalize( + ty, + |ty| Ok(ty), + || { + let branches = last_valtree.unwrap_branch(); + last_valtree = branches[branches.len() - 1]; + debug!(?branches, ?last_valtree); + }, + ) + .unwrap(); let unsized_inner_ty = match tail.kind() { ty::Slice(t) => *t, ty::Str => tail, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 5a8b3e30b9fc0..7c0636ec627b9 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -770,14 +770,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } match implsrc { - Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => { + Ok(Ok(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => { debug!( "const_trait_impl: provided {:?} via where-clause in {:?}", trait_ref, param_env ); return; } - Ok(Some(ImplSource::UserDefined(data))) => { + Ok(Ok(ImplSource::UserDefined(data))) => { let callee_name = tcx.item_name(callee); if let Some(&did) = tcx .associated_item_def_ids(data.impl_def_id) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index b28d70194917b..21b5f643b018c 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -160,7 +160,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { let mut selcx = SelectionContext::new(&infcx); let implsrc = selcx.select(&obligation); - if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { + if let Ok(Ok(ImplSource::UserDefined(data))) = implsrc { let span = tcx.def_span(data.impl_def_id); err.span_note(span, "impl defined here, but it is not `const`"); } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index d995d533ca3e4..574ab351b0f27 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -170,7 +170,7 @@ impl Qualif for NeedsNonConstDrop { let infcx = cx.tcx.infer_ctxt().build(); let mut selcx = SelectionContext::new(&infcx); - let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { + let Ok(Ok(impl_src)) = selcx.select(&obligation) else { // If we couldn't select a const destruct candidate, then it's bad return true; }; diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 10e673cd9297b..7ac9ecaac954e 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -107,6 +107,12 @@ pub trait ObligationProcessor { obligation: &mut Self::Obligation, ) -> ProcessResult; + fn update_obligation_depth( + &mut self, + obligation: &Self::Obligation, + child: &mut Self::Obligation, + ); + /// As we do the cycle check, we invoke this callback when we /// encounter an actual cycle. `cycle` is an iterator that starts /// at the start of the cycle in the stack and walks **toward the @@ -375,13 +381,16 @@ impl ObligationForest { } /// Converts all remaining obligations to the given error. - pub fn to_errors(&mut self, error: E) -> Vec> { + pub fn to_errors(&mut self, mut mk_error: impl FnMut(&O) -> E) -> Vec> { let errors = self .nodes .iter() .enumerate() .filter(|(_index, node)| node.state.get() == NodeState::Pending) - .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) + .map(|(index, node)| Error { + error: mk_error(&node.obligation), + backtrace: self.error_at(index), + }) .collect(); self.compress(|_| assert!(false)); @@ -447,11 +456,15 @@ impl ObligationForest { ProcessResult::Unchanged => { // No change in state. } - ProcessResult::Changed(children) => { + ProcessResult::Changed(mut children) => { // We are not (yet) stalled. has_changed = true; node.state.set(NodeState::Success); + for child in &mut children { + processor.update_obligation_depth(&node.obligation, child); + } + for child in children { let st = self.register_obligation_at(child, Some(index)); if let Err(()) = st { diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs index bc252f772a168..be86005aaf641 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs @@ -70,6 +70,8 @@ where true } + fn update_obligation_depth(&mut self, _: &Self::Obligation, _: &mut Self::Obligation) {} + fn process_obligation( &mut self, obligation: &mut Self::Obligation, @@ -256,7 +258,7 @@ fn to_errors_no_throw() { )); assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); - let errors = forest.to_errors(()); + let errors = forest.to_errors(|_| ()); assert_eq!(errors[0].backtrace, vec!["A.1", "A"]); assert_eq!(errors[1].backtrace, vec!["A.2", "A"]); assert_eq!(errors[2].backtrace, vec!["A.3", "A"]); @@ -308,7 +310,7 @@ fn diamond() { assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]); assert_eq!(err.len(), 0); - let errors = forest.to_errors(()); + let errors = forest.to_errors(|_| ()); assert_eq!(errors.len(), 0); forest.register_obligation("A'"); @@ -353,7 +355,7 @@ fn diamond() { vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }] ); - let errors = forest.to_errors(()); + let errors = forest.to_errors(|_| ()); assert_eq!(errors.len(), 0); } @@ -446,7 +448,7 @@ fn orphan() { assert_eq!(ok.len(), 0); assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]); - let errors = forest.to_errors(()); + let errors = forest.to_errors(|_| ()); assert_eq!(errors.len(), 0); } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 55cca0cd2d7b5..8c774a1038eb7 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -74,6 +74,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::specialization_graph::Node; +use rustc_infer::traits::Overflow; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; @@ -377,7 +378,9 @@ fn check_predicates<'tcx>( 0, arg, span, + true, ) + .unwrap_or_else(|Overflow| bug!("impossible non-fatal overflow")) .unwrap(); assert!(!obligations.needs_infer()); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 71949b4211819..ccdd8b780afb9 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -671,7 +671,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }; match selcx.select(&obligation.with(trait_pred)) { // Uncertain or unimplemented. - Ok(None) => { + Ok(Err(true)) => self.err_ctxt().report_overflow_error(&obligation, true), + Ok(Err(false)) => { if trait_pred.def_id() == unsize_did { let trait_pred = self.resolve_vars_if_possible(trait_pred); let self_ty = trait_pred.skip_binder().self_ty(); @@ -712,7 +713,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // be silent, as it causes a type mismatch later. } - Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), + Ok(Ok(impl_source)) => queue.extend(impl_source.nested_obligations()), } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 8cf70eb5431a8..afd019843b9d5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2159,7 +2159,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }), ); match SelectionContext::new(&self).select(&obligation) { - Ok(Some(traits::ImplSource::UserDefined(impl_source))) => { + Ok(Ok(traits::ImplSource::UserDefined(impl_source))) => { Some(impl_source.impl_def_id) } _ => None, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 46a760851893d..65cef8842865b 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1447,7 +1447,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .define_opaque_types(false) .sup(candidate.xform_self_ty, self_ty); match self.select_trait_candidate(trait_ref) { - Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { + Ok(Ok(traits::ImplSource::UserDefined(ref impl_data))) => { // If only a single impl matches, make the error message point // to that impl. CandidateSource::Impl(impl_data.impl_def_id) @@ -1566,7 +1566,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if self.probe(|_| { match self.select_trait_candidate(trait_ref) { Err(_) => return true, - Ok(Some(impl_source)) + Ok(Ok(impl_source)) if !impl_source.borrow_nested_obligations().is_empty() => { for obligation in impl_source.borrow_nested_obligations() { diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index b2b985a22ac01..bdd27fafc00cb 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -8,14 +8,6 @@ use super::FulfillmentError; use super::{ObligationCause, PredicateObligation}; pub trait TraitEngine<'tcx>: 'tcx { - fn normalize_projection_type( - &mut self, - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - ) -> Ty<'tcx>; - /// Requires that `ty` must implement the trait with `def_id` in /// the given environment. This trait must not have any type /// parameters (except for `Self`). diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index c8600ded987e5..9b1e7af87fec9 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -111,7 +111,7 @@ pub struct FulfillmentError<'tcx> { pub root_obligation: PredicateObligation<'tcx>, } -#[derive(Clone)] +#[derive(Debug, Clone)] pub enum FulfillmentErrorCode<'tcx> { /// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented. CodeCycle(Vec>>), @@ -120,6 +120,7 @@ pub enum FulfillmentErrorCode<'tcx> { CodeSubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate CodeConstEquateError(ExpectedFound>, TypeError<'tcx>), CodeAmbiguity, + CodeOverflow, } impl<'tcx, O> Obligation<'tcx, O> { diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index 5d22f9f972e10..1210819a50702 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -90,6 +90,7 @@ impl<'tcx> ProjectionCacheKey<'tcx> { pub enum ProjectionCacheEntry<'tcx> { InProgress, Ambiguous, + Overflow, Recur, Error, NormalizedTy { @@ -184,7 +185,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { key, value ); let mut map = self.map(); - if let Some(ProjectionCacheEntry::Recur) = map.get(&key) { + if let Some(ProjectionCacheEntry::Recur | ProjectionCacheEntry::Overflow) = map.get(&key) { debug!("Not overwriting Recur"); return; } @@ -223,6 +224,11 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { }) } + pub fn overflow(&mut self, key: ProjectionCacheKey<'tcx>) { + let fresh = self.map().insert(key, ProjectionCacheEntry::Overflow); + assert!(!fresh, "never started projecting `{:?}", key); + } + /// Indicates that trying to normalize `key` resulted in /// ambiguity. No point in trying it again then until we gain more /// type information (in which case, the "fully resolved" key will diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 1c6ab6a082b99..75dc5bcbb0c2e 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -35,23 +35,6 @@ impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { } } -impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - super::CodeSelectionError(ref e) => write!(f, "{:?}", e), - super::CodeProjectionError(ref e) => write!(f, "{:?}", e), - super::CodeSubtypeError(ref a, ref b) => { - write!(f, "CodeSubtypeError({:?}, {:?})", a, b) - } - super::CodeConstEquateError(ref a, ref b) => { - write!(f, "CodeConstEquateError({:?}, {:?})", a, b) - } - super::CodeAmbiguity => write!(f, "Ambiguity"), - super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle), - } - } -} - impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "MismatchedProjectionTypes({:?})", self.err) diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 0331d764b38a1..919e76f1abeaf 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -237,30 +237,18 @@ pub enum Certainty { /// canonical form will be different, making this a distinct /// query. Ambiguous, -} - -impl Certainty { - pub fn is_proven(&self) -> bool { - match self { - Certainty::Proven => true, - Certainty::Ambiguous => false, - } - } + Overflow, } impl<'tcx, R> QueryResponse<'tcx, R> { - pub fn is_proven(&self) -> bool { - self.certainty.is_proven() + pub fn certainty(&self) -> Certainty { + self.certainty } } impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { - pub fn is_proven(&self) -> bool { - self.value.is_proven() - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() + pub fn certainty(&self) -> Certainty { + self.value.certainty() } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1564cf414bd25..9a498a7c87aaa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1907,7 +1907,7 @@ rustc_queries! { /// `infcx.predicate_must_hold()` instead. query evaluate_obligation( goal: CanonicalPredicateGoal<'tcx> - ) -> Result { + ) -> traits::EvaluationResult { desc { "evaluating trait selection obligation `{}`", goal.value.value } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 05382bd887cd9..9a5c6ee557144 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -26,7 +26,7 @@ use smallvec::SmallVec; use std::borrow::Cow; use std::hash::{Hash, Hasher}; -pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; +pub use self::select::{EvaluationCache, EvaluationResult, SelectionCache}; pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; @@ -34,6 +34,9 @@ pub use self::ObligationCauseCode::*; pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner}; +#[derive(Debug)] +pub struct Overflow; + /// Depending on the stage of compilation, we want projection to be /// more or less conservative. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] @@ -571,8 +574,6 @@ pub enum SelectionError<'tcx> { TraitNotObjectSafe(DefId), /// A given constant couldn't be evaluated. NotConstEvaluatable(NotConstEvaluatable), - /// Exceeded the recursion depth during type projection. - Overflow(OverflowError), /// Signaling that an error has already been emitted, to avoid /// multiple errors being shown. ErrorReporting, @@ -585,7 +586,7 @@ pub enum SelectionError<'tcx> { /// - `Ok(None)`: could not definitely determine anything, usually due /// to inconclusive type inference. /// - `Err(e)`: error `e` occurred -pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; +pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; /// Given the successful resolution of an obligation, the `ImplSource` /// indicates where the impl comes from. diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 85ead3171e785..81457b7e74227 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -4,8 +4,7 @@ use self::EvaluationResult::*; -use super::{SelectionError, SelectionResult}; -use rustc_errors::ErrorGuaranteed; +use super::SelectionResult; use crate::ty; @@ -169,7 +168,7 @@ pub enum SelectionCandidate<'tcx> { /// /// The evaluation results are ordered: /// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` -/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` +/// implies `EvaluatedToAmbig` implies `EvaluatedToOverflow` /// - `EvaluatedToErr` implies `EvaluatedToRecur` /// - the "union" of evaluation results is equal to their maximum - /// all the "potential success" candidates can potentially succeed, @@ -197,7 +196,7 @@ pub enum EvaluationResult { /// know the real result. /// /// This can't be trivially cached for the same reason as `EvaluatedToRecur`. - EvaluatedToUnknown, + EvaluatedToOverflow, /// Evaluation failed because we encountered an obligation we are already /// trying to prove on this branch. /// @@ -265,7 +264,7 @@ impl EvaluationResult { | EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig - | EvaluatedToUnknown => true, + | EvaluatedToOverflow => true, EvaluatedToErr | EvaluatedToRecur => false, } @@ -273,41 +272,26 @@ impl EvaluationResult { pub fn is_stack_dependent(self) -> bool { match self { - EvaluatedToUnknown | EvaluatedToRecur => true, + EvaluatedToRecur => true, EvaluatedToOkModuloOpaqueTypes | EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig + | EvaluatedToOverflow | EvaluatedToErr => false, } } -} - -/// Indicates that trait evaluation caused overflow and in which pass. -#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] -pub enum OverflowError { - Error(ErrorGuaranteed), - Canonical, - ErrorReporting, -} - -impl From for OverflowError { - fn from(e: ErrorGuaranteed) -> OverflowError { - OverflowError::Error(e) - } -} -TrivialTypeTraversalAndLiftImpls! { - OverflowError, -} - -impl<'tcx> From for SelectionError<'tcx> { - fn from(overflow_error: OverflowError) -> SelectionError<'tcx> { - match overflow_error { - OverflowError::Error(e) => SelectionError::Overflow(OverflowError::Error(e)), - OverflowError::Canonical => SelectionError::Overflow(OverflowError::Canonical), - OverflowError::ErrorReporting => SelectionError::ErrorReporting, + pub fn is_overflow(self) -> bool { + match self { + EvaluatedToOverflow => true, + EvaluatedToOk + | EvaluatedToOkModuloRegions + | EvaluatedToOkModuloOpaqueTypes + | EvaluatedToAmbig + | EvaluatedToRecur + | EvaluatedToErr => false, } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 49d82b503a4bb..5b86b1f9b2275 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -3,6 +3,7 @@ #![allow(rustc::usage_of_ty_tykind)] use crate::infer::canonical::Canonical; +use crate::traits::Overflow; use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use crate::ty::visit::ValidateBoundVars; use crate::ty::InferTy::*; @@ -2070,10 +2071,10 @@ impl<'tcx> Ty<'tcx> { pub fn ptr_metadata_ty( self, tcx: TyCtxt<'tcx>, - normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, - ) -> (Ty<'tcx>, bool) { - let tail = tcx.struct_tail_with_normalize(self, normalize, || {}); - match tail.kind() { + normalize: impl FnMut(Ty<'tcx>) -> Result, Overflow>, + ) -> Result<(Ty<'tcx>, bool), Overflow> { + let tail = tcx.struct_tail_with_normalize(self, normalize, || {})?; + Ok(match tail.kind() { // Sized types ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) @@ -2116,7 +2117,7 @@ impl<'tcx> Ty<'tcx> { | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail) } - } + }) } /// When we create a closure, we record its kind (i.e., what trait diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f72e236eda133..a78c383e636ff 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1,6 +1,7 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use crate::traits::Overflow; use crate::ty::layout::IntegerExt; use crate::ty::{ self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, @@ -201,7 +202,7 @@ impl<'tcx> TyCtxt<'tcx> { /// if input `ty` is not a structure at all. pub fn struct_tail_without_normalization(self, ty: Ty<'tcx>) -> Ty<'tcx> { let tcx = self; - tcx.struct_tail_with_normalize(ty, |ty| ty, || {}) + tcx.struct_tail_with_normalize(ty, |ty| Ok(ty), || {}).unwrap() } /// Returns the deeply last field of nested structures, or the same type if @@ -217,7 +218,12 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> Ty<'tcx> { let tcx = self; - tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {}) + tcx.struct_tail_with_normalize( + ty, + |ty| Ok(tcx.normalize_erasing_regions(param_env, ty)), + || {}, + ) + .unwrap() } /// Returns the deeply last field of nested structures, or the same type if @@ -233,19 +239,19 @@ impl<'tcx> TyCtxt<'tcx> { pub fn struct_tail_with_normalize( self, mut ty: Ty<'tcx>, - mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, + mut normalize: impl FnMut(Ty<'tcx>) -> Result, Overflow>, // This is currently used to allow us to walk a ValTree // in lockstep with the type in order to get the ValTree branch that // corresponds to an unsized field. mut f: impl FnMut() -> (), - ) -> Ty<'tcx> { + ) -> Result, Overflow> { let recursion_limit = self.recursion_limit(); for iteration in 0.. { if !recursion_limit.value_within_limit(iteration) { - return self.ty_error_with_message( + return Ok(self.ty_error_with_message( DUMMY_SP, &format!("reached the recursion limit finding the struct tail for {}", ty), - ); + )); } match *ty.kind() { ty::Adt(def, substs) => { @@ -269,9 +275,9 @@ impl<'tcx> TyCtxt<'tcx> { ty::Tuple(_) => break, ty::Projection(_) | ty::Opaque(..) => { - let normalized = normalize(ty); + let normalized = normalize(ty)?; if ty == normalized { - return ty; + return Ok(ty); } else { ty = normalized; } @@ -282,7 +288,7 @@ impl<'tcx> TyCtxt<'tcx> { } } } - ty + Ok(ty) } /// Same as applying `struct_tail` on `source` and `target`, but only diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 54c738d838975..10703e612cb19 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -1,8 +1,9 @@ use crate::errors::AutoDerefReachedRecursionLimit; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{self, TraitEngine, TraitEngineExt}; +use crate::traits::{self, SelectionContext, TraitEngineExt}; use rustc_hir as hir; use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::{Normalized, TraitEngine}; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; use rustc_middle::ty::{ToPredicate, TypeVisitable}; use rustc_session::Limit; @@ -139,16 +140,17 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { return None; } - let mut fulfillcx = >::new_in_snapshot(tcx); - let normalized_ty = fulfillcx.normalize_projection_type( - &self.infcx, + let mut fulfillcx = >::new_in_snapshot(tcx); + let mut selcx = SelectionContext::new(&self.infcx); + let Normalized { value: normalized_ty, obligations } = traits::normalize( + &mut selcx, self.param_env, - ty::ProjectionTy { - item_def_id: tcx.lang_items().deref_target()?, - substs: trait_ref.substs, - }, cause, + tcx.mk_projection(tcx.lang_items().deref_target()?, trait_ref.substs), ); + for obl in obligations { + fulfillcx.register_predicate_obligation(&self.infcx, obl); + } let errors = fulfillcx.select_where_possible(&self.infcx); if !errors.is_empty() { // This shouldn't happen, except for evaluate/fulfill mismatches, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 0f2e22604dc7e..a57c26fa32830 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -49,7 +49,7 @@ pub trait InferCtxtExt<'tcx> { /// - the parameter environment /// /// Invokes `evaluate_obligation`, so in the event that evaluating - /// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToUnknown) + /// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToOverflow) /// will be returned. fn type_implements_trait( &self, @@ -126,7 +126,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { recursion_depth: 0, predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx), }; - self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr) + self.evaluate_obligation(&obligation) } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 188f8bb7e2a58..0a20b27b2263b 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -98,7 +98,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { ] { let result = selcx.select(&Obligation::new(ObligationCause::dummy(), orig_env, f(&trait_pred))); - if let Ok(Some(ImplSource::UserDefined(_))) = result { + if let Ok(Ok(ImplSource::UserDefined(_))) = result { debug!( "find_auto_trait_generics({:?}): \ manual impl found, bailing out", @@ -285,7 +285,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let result = select.select(&obligation); match result { - Ok(Some(ref impl_source)) => { + Ok(Ok(ref impl_source)) => { // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`), // we immediately bail out, since it's impossible for us to continue. @@ -318,7 +318,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { return None; } } - Ok(None) => {} + Ok(Err(_overflow)) => {} Err(SelectionError::Unimplemented) => { if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) { already_visited.remove(&pred); @@ -715,6 +715,12 @@ impl<'tcx> AutoTraitFinder<'tcx> { ); return false; } + ProjectAndUnifyResult::Overflow => { + debug!( + "evaluate_nested_obligations: overflow for projection predicate" + ); + return false; + } ProjectAndUnifyResult::Recursive => { debug!("evaluate_nested_obligations: recursive projection predicate"); return false; diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 8f9d5eaac9d1d..aef4493489634 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -4,11 +4,12 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; use crate::traits::query::NoSolution; use crate::traits::{ - ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, - PredicateObligation, SelectionError, TraitEngine, + ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, PredicateObligation, + SelectionError, TraitEngine, }; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_middle::ty::{self, Ty, TypeVisitable}; +use rustc_infer::infer::canonical::Certainty; +use rustc_middle::ty::{self, TypeVisitable}; pub struct FulfillmentContext<'tcx> { obligations: FxIndexSet>, @@ -33,16 +34,6 @@ impl FulfillmentContext<'_> { } impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { - fn normalize_projection_type( - &mut self, - infcx: &InferCtxt<'tcx>, - _param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - _cause: ObligationCause<'tcx>, - ) -> Ty<'tcx> { - infcx.tcx.mk_ty(ty::Projection(projection_ty)) - } - fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'tcx>, @@ -108,35 +99,39 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { match infcx.tcx.evaluate_goal(canonical_goal) { Ok(response) => { - if response.is_proven() { - making_progress = true; - - match infcx.instantiate_query_response_and_region_obligations( - &obligation.cause, - obligation.param_env, - &orig_values, - &response, - ) { - Ok(infer_ok) => next_round.extend( - infer_ok.obligations.into_iter().map(|obligation| { - assert!(!infcx.is_in_snapshot()); - infcx.resolve_vars_if_possible(obligation) - }), - ), + match response.certainty() { + Certainty::Proven => {} + Certainty::Ambiguous => { + next_round.insert(obligation); + continue; + } + Certainty::Overflow => bug!("overflow in chalk fulfill"), + } - Err(_err) => errors.push(FulfillmentError { - obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), - // FIXME - does Chalk have a notation of 'root obligation'? - // This is just for diagnostics, so it's okay if this is wrong - root_obligation: obligation, + making_progress = true; + + match infcx.instantiate_query_response_and_region_obligations( + &obligation.cause, + obligation.param_env, + &orig_values, + &response, + ) { + Ok(infer_ok) => next_round.extend( + infer_ok.obligations.into_iter().map(|obligation| { + assert!(!infcx.is_in_snapshot()); + infcx.resolve_vars_if_possible(obligation) }), - } - } else { - // Ambiguous: retry at next round. - next_round.insert(obligation); + ), + + Err(_err) => errors.push(FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + // FIXME - does Chalk have a notation of 'root obligation'? + // This is just for diagnostics, so it's okay if this is wrong + root_obligation: obligation, + }), } } diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 8a62bf015674a..dc83d997790bc 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -43,8 +43,9 @@ pub fn codegen_select_candidate<'tcx>( Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => return Err(CodegenObligationError::Ambiguity), + Ok(Ok(selection)) => selection, + Ok(Err(true)) => infcx.err_ctxt().report_overflow_error(&obligation, true), + Ok(Err(false)) => return Err(CodegenObligationError::Ambiguity), Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), Err(e) => { bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) @@ -66,15 +67,17 @@ 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.err_ctxt().report_overflow_error_cycle(&cycle); + match err.code { + FulfillmentErrorCode::CodeOverflow => { + infcx.err_ctxt().report_overflow_error(&err.obligation, true) + } + FulfillmentErrorCode::CodeCycle(cycle) => { + infcx.err_ctxt().report_overflow_error_cycle(&cycle) + } + _ => {} } } - return Err(CodegenObligationError::FulfillmentError); } let impl_source = infcx.resolve_vars_if_possible(impl_source); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 3cf2959a9ffc5..08b8fcc483e51 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -267,7 +267,7 @@ fn implicit_negative<'cx, 'tcx>( predicate: p, }) .chain(obligations) - .find(|o| !selcx.predicate_may_hold_fatal(o)); + .find(|o| !selcx.evaluate_root_obligation(&o).may_apply()); if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); 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 786cadaa6cefc..eddbf72eebcc6 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -4,8 +4,8 @@ pub mod suggestions; use super::{ FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, ObligationCause, - ObligationCauseCode, OutputTypeParameterMismatch, Overflow, PredicateObligation, - SelectionContext, SelectionError, TraitNotObjectSafe, + ObligationCauseCode, OutputTypeParameterMismatch, PredicateObligation, SelectionContext, + SelectionError, TraitNotObjectSafe, }; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -30,7 +30,7 @@ use rustc_hir::Node; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::TypeTrace; use rustc_infer::traits::TraitEngine; -use rustc_middle::traits::select::OverflowError; +use rustc_middle::traits::Overflow; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; @@ -1312,14 +1312,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.tcx.sess.delay_span_bug(span, "`ErrorGuaranteed` without an error"); return; } - // Already reported. - Overflow(OverflowError::Error(_)) => { - self.tcx.sess.delay_span_bug(span, "`OverflowError` has been reported"); - return; - } - Overflow(_) => { - bug!("overflow should be handled before the `report_selection_error` path"); - } SelectionError::ErrorReporting => { bug!("ErrorReporting Overflow should not reach `report_selection_err` call") } @@ -1541,6 +1533,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { FulfillmentErrorCode::CodeCycle(ref cycle) => { self.report_overflow_error_cycle(cycle); } + FulfillmentErrorCode::CodeOverflow => { + let predicate = self.resolve_vars_if_possible(error.obligation.predicate); + if !predicate.references_error() { + self.report_overflow_error(&error.obligation, true); + } + } } } @@ -1580,7 +1578,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation.cause.clone(), 0, &mut obligations, - ); + ) + .unwrap_or_else(|Overflow| self.report_overflow_error(obligation, true)); debug!(?obligation.cause, ?obligation.param_env); @@ -2105,12 +2104,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation.param_env, trait_ref.to_poly_trait_predicate(), ); - let mut selcx = SelectionContext::with_query_mode( - &self, - crate::traits::TraitQueryMode::Standard, - ); + let mut selcx = SelectionContext::new(self); match selcx.select_from_obligation(&obligation) { - Ok(None) => { + Ok(Err(false)) => { let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation); let has_non_region_infer = trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer()); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 84daaf97ecfa8..db8364836c028 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1342,9 +1342,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation.param_env, trait_pred_and_suggested_ty, ); - let suggested_ty_would_satisfy_obligation = self - .evaluate_obligation_no_overflow(&new_obligation) - .must_apply_modulo_regions(); + let suggested_ty_would_satisfy_obligation = + self.evaluate_obligation(&new_obligation).must_apply_modulo_regions(); if suggested_ty_would_satisfy_obligation { let sp = self .tcx @@ -2315,10 +2314,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { GeneratorInteriorOrUpvar::Upvar(upvar_span) => { // `Some(ref_ty)` if `target_ty` is `&T` and `T` fails to impl `Sync` let refers_to_non_sync = match target_ty.kind() { - ty::Ref(_, ref_ty, _) => match self.evaluate_obligation(&obligation) { - Ok(eval) if !eval.may_apply() => Some(ref_ty), - _ => None, - }, + ty::Ref(_, ref_ty, _) if self.evaluate_obligation(&obligation).may_apply() => { + Some(ref_ty) + } _ => None, }; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 4905bb69cc5ca..48b4f110a0f7a 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -3,27 +3,25 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; -use rustc_infer::traits::ProjectionCacheKey; -use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation}; +use rustc_infer::traits::{Obligation, Overflow, ProjectionCacheKey}; +use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; -use rustc_middle::ty::{self, Binder, Const, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Binder, Const, TypeVisitable}; use std::marker::PhantomData; use super::const_evaluatable; use super::project::{self, ProjectAndUnifyResult}; use super::select::SelectionContext; use super::wf; -use super::CodeAmbiguity; -use super::CodeProjectionError; -use super::CodeSelectionError; use super::EvaluationResult; +use super::FulfillmentErrorCode::*; +use super::PredicateObligation; use super::Unimplemented; use super::{FulfillmentError, FulfillmentErrorCode}; -use super::{ObligationCause, PredicateObligation}; use crate::traits::project::PolyProjectionObligation; use crate::traits::project::ProjectionCacheKeyExt as _; @@ -127,42 +125,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { } impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { - /// "Normalize" a projection type `::X` by - /// creating a fresh type variable `$0` as well as a projection - /// predicate `::X == $0`. When the - /// inference engine runs, it will attempt to find an impl of - /// `SomeTrait` or a where-clause that lets us unify `$0` with - /// something concrete. If this fails, we'll unify `$0` with - /// `projection_ty` again. - #[instrument(level = "debug", skip(self, infcx, param_env, cause))] - fn normalize_projection_type( - &mut self, - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - ) -> Ty<'tcx> { - debug_assert!(!projection_ty.has_escaping_bound_vars()); - - // FIXME(#20304) -- cache - - let mut selcx = SelectionContext::new(infcx); - let mut obligations = vec![]; - let normalized_ty = project::normalize_projection_type( - &mut selcx, - param_env, - projection_ty, - cause, - 0, - &mut obligations, - ); - self.register_predicate_obligations(infcx, obligations); - - debug!(?normalized_ty); - - normalized_ty.ty().unwrap() - } - fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'tcx>, @@ -190,7 +152,18 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { } } - self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() + let limit = infcx.tcx.recursion_limit(); + self.predicates + .to_errors(|obligation| { + if limit.value_within_limit(obligation.obligation.recursion_depth) { + CodeAmbiguity + } else { + CodeOverflow + } + }) + .into_iter() + .map(to_fulfillment_error) + .collect() } fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { @@ -272,9 +245,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { pending_obligation.stalled_on.truncate(0); + let infcx = self.selcx.infcx(); let obligation = &mut pending_obligation.obligation; debug!(?obligation, "pre-resolve"); + if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) { + return ProcessResult::Unchanged; + } if obligation.predicate.has_non_region_infer() { obligation.predicate = @@ -283,23 +260,35 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let obligation = &pending_obligation.obligation; - let infcx = self.selcx.infcx(); - if obligation.predicate.has_projections() { let mut obligations = Vec::new(); - let predicate = crate::traits::project::try_normalize_with_depth_to( + let predicate = match crate::traits::project::try_normalize_with_depth_to( &mut self.selcx, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, obligation.predicate, &mut obligations, - ); + ) { + Ok(value) => value, + Err(Overflow) => { + // HACK: Emit a nested obligation at the maximum depth to get an + // overflow fulfillment error. + let obligation_at_limit = Obligation::with_depth( + obligation.cause.clone(), + infcx.tcx.recursion_limit().0 + 1, + obligation.param_env, + obligation.predicate, + ); + return ProcessResult::Changed(mk_pending(vec![obligation_at_limit])); + } + }; if predicate != obligation.predicate { obligations.push(obligation.with(predicate)); return ProcessResult::Changed(mk_pending(obligations)); } } + let binder = obligation.predicate.kind(); match binder.no_bound_vars() { None => match binder.skip_binder() { @@ -369,8 +358,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ProcessResult::Changed(vec![]) } - ty::PredicateKind::Projection(ref data) => { - let project_obligation = obligation.with(Binder::dummy(*data)); + ty::PredicateKind::Projection(data) => { + let project_obligation = obligation.with(Binder::dummy(data)); self.process_projection_obligation( obligation, @@ -408,13 +397,21 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { obligation.recursion_depth + 1, arg, obligation.cause.span, + false, ) { - None => { + Err(Overflow) => { + pending_obligation.stalled_on.clear(); + pending_obligation + .stalled_on + .extend(TyOrConstInferVar::maybe_from_generic_arg(arg)); + ProcessResult::Unchanged + } + Ok(None) => { pending_obligation.stalled_on = vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()]; ProcessResult::Unchanged } - Some(os) => ProcessResult::Changed(mk_pending(os)), + Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)), } } @@ -579,6 +576,15 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } + fn update_obligation_depth( + &mut self, + obligation: &Self::Obligation, + child: &mut Self::Obligation, + ) { + child.obligation.recursion_depth = + child.obligation.recursion_depth.max(obligation.obligation.recursion_depth + 1); + } + #[inline(never)] fn process_backedge<'c, I>( &mut self, @@ -620,11 +626,11 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } match self.selcx.select(&trait_obligation) { - Ok(Some(impl_source)) => { + Ok(Ok(impl_source)) => { debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth); ProcessResult::Changed(mk_pending(impl_source.nested_obligations())) } - Ok(None) => { + Ok(Err(_overflow)) => { debug!("selecting trait at depth {} yielded Ok(None)", obligation.recursion_depth); // This is a bit subtle: for the most part, the @@ -659,8 +665,6 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { project_obligation: PolyProjectionObligation<'tcx>, stalled_on: &mut Vec>, ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { - let tcx = self.selcx.tcx(); - if obligation.predicate.is_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. @@ -687,7 +691,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { match project::poly_project_and_unify_type(&mut self.selcx, &project_obligation) { ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)), - ProjectAndUnifyResult::FailedNormalization => { + ProjectAndUnifyResult::Overflow | ProjectAndUnifyResult::FailedNormalization => { stalled_on.clear(); stalled_on.extend(substs_infer_vars( &self.selcx, @@ -697,7 +701,8 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } // Let the caller handle the recursion ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![ - project_obligation.with(project_obligation.predicate.to_predicate(tcx)), + project_obligation + .with(project_obligation.predicate.to_predicate(self.selcx.tcx())), ])), ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { ProcessResult::Error(CodeProjectionError(e)) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 10e48610e3abb..6b411c5386db5 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -59,7 +59,7 @@ pub use self::object_safety::MethodViolationCode; pub use self::object_safety::ObjectSafetyViolation; pub use self::project::{normalize, normalize_projection_type, normalize_to}; pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; -pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; +pub use self::select::{EvaluationResult, IntercrateAmbiguityCause}; pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; @@ -101,19 +101,6 @@ impl SkipLeakCheck { } } -/// The mode that trait queries run in. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum TraitQueryMode { - /// Standard/un-canonicalized queries get accurate - /// spans etc. passed in and hence can do reasonable - /// error reporting on their own. - Standard, - /// Canonicalized queries get dummy spans and hence - /// must generally propagate errors to - /// pre-canonicalization callsites. - Canonical, -} - /// Creates predicate obligations from the generic bounds. #[instrument(level = "debug", skip(cause, param_env))] pub fn predicates_for_generics<'tcx>( @@ -542,9 +529,7 @@ fn is_impossible_method<'tcx>( let infcx = tcx.infer_ctxt().ignoring_regions().build(); for obligation in predicates_for_trait { // Ignore overflow error, to be conservative. - if let Ok(result) = infcx.evaluate_obligation(&obligation) - && !result.may_apply() - { + if infcx.evaluate_obligation(&obligation).may_apply() { return true; } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 572f82117cc0e..dd67894425cef 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -15,10 +15,11 @@ use super::{ ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData, }; use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; +use rustc_middle::traits::Overflow; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; -use crate::traits::error_reporting::TypeErrCtxtExt as _; +use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::select::ProjectionMatchesProjection; use rustc_data_structures::sso::SsoHashSet; @@ -28,17 +29,16 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; -use rustc_middle::traits::select::OverflowError; +use rustc_middle::traits::Reveal; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable}; use rustc_middle::ty::DefIdTree; +use rustc_middle::ty::FallibleTypeFolder; use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; use std::collections::BTreeMap; -pub use rustc_middle::traits::Reveal; - pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; @@ -50,6 +50,9 @@ pub(super) struct InProgress; /// When attempting to resolve `::Name` ... #[derive(Debug)] pub enum ProjectionError<'tcx> { + /// ...we encountered an overflow. + Overflow, + /// ...we found multiple sources of information and couldn't resolve the ambiguity. TooManyCandidates, @@ -57,7 +60,13 @@ pub enum ProjectionError<'tcx> { TraitSelectionError(SelectionError<'tcx>), } -#[derive(PartialEq, Eq, Debug)] +impl<'tcx> From for ProjectionError<'tcx> { + fn from(_: Overflow) -> ProjectionError<'tcx> { + ProjectionError::Overflow + } +} + +#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable, TypeVisitable)] enum ProjectionCandidate<'tcx> { /// From a where-clause in the env or object type ParamEnv(ty::PolyProjectionPredicate<'tcx>), @@ -75,7 +84,7 @@ enum ProjectionCandidate<'tcx> { ImplTraitInTrait(ImplTraitInTraitCandidate<'tcx>), } -#[derive(PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable, TypeVisitable)] enum ImplTraitInTraitCandidate<'tcx> { // The `impl Trait` from a trait function's default body Trait, @@ -177,6 +186,7 @@ pub(super) enum ProjectAndUnifyResult<'tcx> { /// The project cannot be normalized because `poly_project_and_unify_type` /// is called recursively while normalizing the same projection. Recursive, + Overflow, // the projection can be normalized, but is not equal to the expected type. // Returns the type error that arose from the mismatch. MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>), @@ -258,9 +268,10 @@ fn project_and_unify_type<'cx, 'tcx>( obligation.recursion_depth, &mut obligations, ) { - Ok(Some(n)) => n, - Ok(None) => return ProjectAndUnifyResult::FailedNormalization, - Err(InProgress) => return ProjectAndUnifyResult::Recursive, + Ok(Ok(Some(n))) => n, + Ok(Ok(None)) => return ProjectAndUnifyResult::FailedNormalization, + Ok(Err(InProgress)) => return ProjectAndUnifyResult::Recursive, + Err(Overflow) => return ProjectAndUnifyResult::Overflow, }; debug!(?normalized, ?obligations, "project_and_unify_type result"); let actual = obligation.predicate.term; @@ -316,7 +327,8 @@ pub fn normalize_to<'a, 'b, 'tcx, T>( where T: TypeFoldable<'tcx>, { - normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations) + normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations, true) + .expect("non-fatal overflow error") } /// As `normalize`, but with a custom depth. @@ -326,13 +338,14 @@ pub fn normalize_with_depth<'a, 'b, 'tcx, T>( cause: ObligationCause<'tcx>, depth: usize, value: T, -) -> Normalized<'tcx, T> +) -> Result, Overflow> where T: TypeFoldable<'tcx>, { let mut obligations = Vec::new(); - let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); - Normalized { value, obligations } + let value = + normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations, false)?; + Ok(Normalized { value, obligations }) } #[instrument(level = "info", skip(selcx, param_env, cause, obligations))] @@ -343,16 +356,18 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( depth: usize, value: T, obligations: &mut Vec>, -) -> T + fatal_overflow: bool, +) -> Result where T: TypeFoldable<'tcx>, { debug!(obligations.len = obligations.len()); - let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); - let result = ensure_sufficient_stack(|| normalizer.fold(value)); + let mut normalizer = + AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations, fatal_overflow); + let result = ensure_sufficient_stack(|| normalizer.fold(value))?; debug!(?result, obligations.len = normalizer.obligations.len()); debug!(?normalizer.obligations,); - result + Ok(result) } #[instrument(level = "info", skip(selcx, param_env, cause, obligations))] @@ -363,7 +378,7 @@ pub fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>( depth: usize, value: T, obligations: &mut Vec>, -) -> T +) -> Result where T: TypeFoldable<'tcx>, { @@ -375,10 +390,10 @@ where depth, obligations, ); - let result = ensure_sufficient_stack(|| normalizer.fold(value)); + let result = ensure_sufficient_stack(|| normalizer.fold(value))?; debug!(?result, obligations.len = normalizer.obligations.len()); debug!(?normalizer.obligations,); - result + Ok(result) } pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<'tcx>>(value: &T, reveal: Reveal) -> bool { @@ -400,6 +415,10 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> { obligations: &'a mut Vec>, depth: usize, universes: Vec>, + + /// Whether overflow should eagerly be fatal. + fatal_overflow: bool, + /// If true, when a projection is unable to be completed, an inference /// variable will be created and an obligation registered to project to that /// inference variable. Also, constants will be eagerly evaluated. @@ -413,6 +432,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { cause: ObligationCause<'tcx>, depth: usize, obligations: &'a mut Vec>, + fatal_overflow: bool, ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { AssocTypeNormalizer { selcx, @@ -421,6 +441,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { obligations, depth, universes: vec![], + fatal_overflow, eager_inference_replacement: true, } } @@ -439,11 +460,12 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { obligations, depth, universes: vec![], + fatal_overflow: false, eager_inference_replacement: false, } } - fn fold>(&mut self, value: T) -> T { + fn fold>(&mut self, value: T) -> Result { let value = self.selcx.infcx().resolve_vars_if_possible(value); debug!(?value); @@ -454,31 +476,15 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { ); if !needs_normalization(&value, self.param_env.reveal()) { - value + Ok(value) } else { - value.fold_with(self) + value.try_fold_with(self) } } -} - -impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { - self.selcx.tcx() - } - - fn fold_binder>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.universes.push(None); - let t = t.super_fold_with(self); - self.universes.pop(); - t - } - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + fn inner_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Overflow> { if !needs_normalization(&ty, self.param_env.reveal()) { - return ty; + return Ok(ty); } // We try to be a little clever here as a performance optimization in @@ -511,27 +517,21 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { ty::Opaque(def_id, substs) => { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { - Reveal::UserFacing => ty.super_fold_with(self), + Reveal::UserFacing => ty.try_super_fold_with(self), Reveal::All => { let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { - let obligation = Obligation::with_depth( - self.cause.clone(), - recursion_limit.0, - self.param_env, - ty, - ); - self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true); + return Err(Overflow); } - let substs = substs.fold_with(self); + let substs = substs.try_fold_with(self)?; let generic_ty = self.tcx().bound_type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.depth += 1; - let folded_ty = self.fold_ty(concrete_ty); + let folded_ty = self.try_fold_ty(concrete_ty)?; self.depth -= 1; - folded_ty + Ok(folded_ty) } } } @@ -542,7 +542,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // placeholders (see branch below). *Also*, we know that we can // register an obligation to *later* project, since we know // there won't be bound vars there. - let data = data.fold_with(self); + let data = data.try_fold_with(self)?; let normalized_ty = if self.eager_inference_replacement { normalize_projection_type( self.selcx, @@ -551,7 +551,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { self.cause.clone(), self.depth, &mut self.obligations, - ) + )? } else { opt_normalize_projection_type( self.selcx, @@ -560,26 +560,14 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { self.cause.clone(), self.depth, &mut self.obligations, - ) + )? .ok() .flatten() - .unwrap_or_else(|| ty.super_fold_with(self).into()) + .map(|term| term.ty().unwrap()) + .map_or_else(|| ty.try_super_fold_with(self), Ok)? + .into() }; - // For cases like #95134 we would like to catch overflows early - // otherwise they slip away and cause ICE. - let recursion_limit = self.tcx().recursion_limit(); - if !recursion_limit.value_within_limit(self.depth) - // HACK: Don't overflow when running cargo doc see #100991 - && !self.tcx().sess.opts.actually_rustdoc - { - let obligation = Obligation::with_depth( - self.cause.clone(), - recursion_limit.0, - self.param_env, - ty, - ); - self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true); - } + debug!( ?self.depth, ?ty, @@ -587,7 +575,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { obligations.len = ?self.obligations.len(), "AssocTypeNormalizer: normalized type" ); - normalized_ty.ty().unwrap() + Ok(normalized_ty.ty().unwrap()) } ty::Projection(data) => { @@ -606,7 +594,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { let infcx = self.selcx.infcx(); let (data, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); + let data = data.try_fold_with(self)?; let normalized_ty = opt_normalize_projection_type( self.selcx, self.param_env, @@ -614,7 +602,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { self.cause.clone(), self.depth, &mut self.obligations, - ) + )? .ok() .flatten() .map(|term| term.ty().unwrap()) @@ -628,7 +616,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { normalized_ty, ) }) - .unwrap_or_else(|| ty.super_fold_with(self)); + .map_or_else(|| ty.try_super_fold_with(self), Ok)?; debug!( ?self.depth, @@ -637,36 +625,72 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { obligations.len = ?self.obligations.len(), "AssocTypeNormalizer: normalized type" ); - normalized_ty + Ok(normalized_ty) } - _ => ty.super_fold_with(self), + _ => ty.try_super_fold_with(self), + } + } +} + +impl<'a, 'b, 'tcx> FallibleTypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { + type Error = Overflow; + + fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { + self.selcx.tcx() + } + + fn try_fold_binder>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> Result, Overflow> { + self.universes.push(None); + let t = t.try_super_fold_with(self)?; + self.universes.pop(); + Ok(t) + } + + fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Overflow> { + match self.inner_fold_ty(ty) { + Ok(value) => Ok(value), + Err(Overflow) => { + if self.fatal_overflow { + let obligation = + Obligation::with_depth(self.cause.clone(), self.depth, self.param_env, ty); + self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true) + } else { + Err(Overflow) + } + } } } #[instrument(skip(self), level = "debug")] - fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { + fn try_fold_const(&mut self, constant: ty::Const<'tcx>) -> Result, Overflow> { let tcx = self.selcx.tcx(); if tcx.lazy_normalization() || !needs_normalization(&constant, self.param_env.reveal()) { - constant + Ok(constant) } else { - let constant = constant.super_fold_with(self); + let constant = constant.try_super_fold_with(self)?; debug!(?constant, ?self.param_env); - with_replaced_escaping_bound_vars( + Ok(with_replaced_escaping_bound_vars( self.selcx.infcx(), &mut self.universes, constant, |constant| constant.eval(tcx, self.param_env), - ) + )) } } #[inline] - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn try_fold_predicate( + &mut self, + p: ty::Predicate<'tcx>, + ) -> Result, Overflow> { if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { - p.super_fold_with(self) + p.try_super_fold_with(self) } else { - p + Ok(p) } } } @@ -915,7 +939,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.tcx().mk_region(ty::ReLateBound(db, *replace_var)) + self.infcx.tcx.mk_region(ty::ReLateBound(db, *replace_var)) } None => r1, } @@ -942,7 +966,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.tcx().mk_ty(ty::Bound(db, *replace_var)) + self.infcx.tcx.mk_ty(ty::Bound(db, *replace_var)) } None => ty, } @@ -966,7 +990,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.tcx().mk_const(ty::ConstKind::Bound(db, *replace_var), ct.ty()) + self.infcx.tcx.mk_const(ty::ConstKind::Bound(db, *replace_var), ct.ty()) } None => ct, } @@ -989,27 +1013,22 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec>, -) -> Term<'tcx> { - opt_normalize_projection_type( +) -> Result, Overflow> { + if let Ok(Some(term)) = opt_normalize_projection_type( selcx, param_env, projection_ty, cause.clone(), depth, obligations, - ) - .ok() - .flatten() - .unwrap_or_else(move || { - // if we bottom out in ambiguity, create a type variable - // and a deferred predicate to resolve this when more type - // information is available. - - selcx + )? { + Ok(term) + } else { + Ok(selcx .infcx() .infer_projection(param_env, projection_ty, cause, depth + 1, obligations) - .into() - }) + .into()) + } } /// The guts of `normalize`: normalize a specific projection like `( cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec>, -) -> Result>, InProgress> { +) -> Result>, InProgress>, Overflow> { let infcx = selcx.infcx(); // Don't use the projection cache in intercrate mode - // the `infcx` may be re-used between intercrate in non-intercrate @@ -1055,12 +1074,16 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( }; match cache_result { Ok(()) => debug!("no cache"), + Err(ProjectionCacheEntry::Overflow) => { + debug!("found cache entry: overflow"); + return Err(Overflow); + } Err(ProjectionCacheEntry::Ambiguous) => { // If we found ambiguity the last time, that means we will continue // to do so until some type in the key changes (and we know it // hasn't, because we just fully resolved it). debug!("found cache entry: ambiguous"); - return Ok(None); + return Ok(Ok(None)); } Err(ProjectionCacheEntry::InProgress) => { // Under lazy normalization, this can arise when @@ -1080,11 +1103,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( if use_cache { infcx.inner.borrow_mut().projection_cache().recur(cache_key); } - return Err(InProgress); + return Ok(Err(InProgress)); } Err(ProjectionCacheEntry::Recur) => { debug!("recur cache"); - return Err(InProgress); + return Ok(Err(InProgress)); } Err(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => { // This is the hottest path in this function. @@ -1100,13 +1123,13 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // evaluations can causes ICEs (e.g., #43132). debug!(?ty, "found normalized ty"); obligations.extend(ty.obligations); - return Ok(Some(ty.value)); + return Ok(Ok(Some(ty.value))); } Err(ProjectionCacheEntry::Error) => { - debug!("opt_normalize_projection_type: found error"); + debug!("found error"); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); - return Ok(Some(result.value.into())); + return Ok(Ok(Some(result.value.into()))); } } @@ -1121,7 +1144,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // is also non-normalized (consider: it was derived from // an impl, where-clause etc) and hence we must // re-normalize it - let projected_term = selcx.infcx().resolve_vars_if_possible(projected_term); let mut result = if projected_term.has_projections() { @@ -1131,8 +1153,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( cause, depth + 1, &mut projected_obligations, + false, ); - let normalized_ty = normalizer.fold(projected_term); + let normalized_ty = normalizer.fold(projected_term)?; Normalized { value: normalized_ty, obligations: projected_obligations } } else { @@ -1151,7 +1174,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); } obligations.extend(result.obligations); - Ok(Some(result.value)) + Ok(Ok(Some(result.value))) } Ok(Projected::NoProgress(projected_ty)) => { let result = Normalized { value: projected_ty, obligations: vec![] }; @@ -1159,17 +1182,24 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); } // No need to extend `obligations`. - Ok(Some(result.value)) + Ok(Ok(Some(result.value))) + } + Err(ProjectionError::Overflow) => { + debug!("overflow"); + if use_cache { + infcx.inner.borrow_mut().projection_cache().overflow(cache_key); + } + Err(Overflow) } Err(ProjectionError::TooManyCandidates) => { - debug!("opt_normalize_projection_type: too many candidates"); + debug!("too many candidates"); if use_cache { infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); } - Ok(None) + Ok(Ok(None)) } Err(ProjectionError::TraitSelectionError(_)) => { - debug!("opt_normalize_projection_type: ERROR"); + debug!("ERROR"); // if we got an error processing the `T as Trait` part, // just return `ty::err` but add the obligation `T : // Trait`, which when processed will cause the error to be @@ -1180,7 +1210,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( } let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); - Ok(Some(result.value.into())) + Ok(Ok(Some(result.value.into()))) } } } @@ -1260,9 +1290,7 @@ fn project<'cx, 'tcx>( if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) { // This should really be an immediate error, but some existing code // relies on being able to recover from this. - return Err(ProjectionError::TraitSelectionError(SelectionError::Overflow( - OverflowError::Canonical, - ))); + return Err(ProjectionError::Overflow); } if obligation.predicate.references_error() { @@ -1276,11 +1304,11 @@ fn project<'cx, 'tcx>( // Make sure that the following procedures are kept in order. ParamEnv // needs to be first because it has highest priority, and Select checks // the return value of push_candidate which assumes it's ran at last. - assemble_candidates_from_param_env(selcx, obligation, &mut candidates); + assemble_candidates_from_param_env(selcx, obligation, &mut candidates)?; - assemble_candidates_from_trait_def(selcx, obligation, &mut candidates); + assemble_candidates_from_trait_def(selcx, obligation, &mut candidates)?; - assemble_candidates_from_object_ty(selcx, obligation, &mut candidates); + assemble_candidates_from_object_ty(selcx, obligation, &mut candidates)?; if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(_)) = candidates { // Avoid normalization cycle from selection (see @@ -1288,12 +1316,12 @@ fn project<'cx, 'tcx>( // FIXME(lazy_normalization): Lazy normalization should save us from // having to special case this. } else { - assemble_candidates_from_impls(selcx, obligation, &mut candidates); + assemble_candidates_from_impls(selcx, obligation, &mut candidates)?; }; match candidates { ProjectionCandidateSet::Single(candidate) => { - Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate))) + Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate)?)) } ProjectionCandidateSet::None => Ok(Projected::NoProgress( // FIXME(associated_const_generics): this may need to change in the future? @@ -1345,17 +1373,20 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( let _ = selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) { - Ok(Some(super::ImplSource::UserDefined(data))) => { + Ok(Ok(super::ImplSource::UserDefined(data))) => { candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait( ImplTraitInTraitCandidate::Impl(data), )); Ok(()) } - Ok(None) => { + Ok(Err(true)) => { + todo!("{:?}", obligation) + } + Ok(Err(false)) => { candidate_set.mark_ambiguous(); return Err(()); } - Ok(Some(_)) => { + Ok(Ok(_)) => { // Don't know enough about the impl to provide a useful signature return Err(()); } @@ -1375,7 +1406,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>, -) { +) -> Result<(), Overflow> { assemble_candidates_from_predicates( selcx, obligation, @@ -1383,7 +1414,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>( ProjectionCandidate::ParamEnv, obligation.param_env.caller_bounds().iter(), false, - ); + ) } /// In the case of a nested projection like `<::FooT as Bar>::BarT`, we may find @@ -1400,7 +1431,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>, -) { +) -> Result<(), Overflow> { debug!("assemble_candidates_from_trait_def(..)"); let tcx = selcx.tcx(); @@ -1413,9 +1444,9 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. candidate_set.mark_ambiguous(); - return; + return Ok(()); } - _ => return, + _ => return Ok(()), }; assemble_candidates_from_predicates( @@ -1425,7 +1456,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( ProjectionCandidate::TraitDef, bounds.iter(), true, - ); + ) } /// In the case of a trait object like @@ -1441,7 +1472,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>, -) { +) -> Result<(), Overflow> { debug!("assemble_candidates_from_object_ty(..)"); let tcx = selcx.tcx(); @@ -1454,9 +1485,9 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( // If the self-type is an inference variable, then it MAY wind up // being an object type, so induce an ambiguity. candidate_set.mark_ambiguous(); - return; + return Ok(()); } - _ => return, + _ => return Ok(()), }; let env_predicates = data .projection_bounds() @@ -1470,7 +1501,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( ProjectionCandidate::Object, env_predicates, false, - ); + ) } #[instrument( @@ -1484,7 +1515,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionCandidate<'tcx>, env_predicates: impl Iterator>, potentially_unnormalized_candidates: bool, -) { +) -> Result<(), Overflow> { let infcx = selcx.infcx(); for predicate in env_predicates { let bound_predicate = predicate.kind(); @@ -1500,7 +1531,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( data, potentially_unnormalized_candidates, ) - }); + })?; match is_match { ProjectionMatchesProjection::Yes => { @@ -1512,7 +1543,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( // HACK: Pick the first trait def candidate for a fully // inferred predicate. This is to allow duplicates that // differ only in normalization. - return; + return Ok(()); } } ProjectionMatchesProjection::Ambiguous => { @@ -1522,6 +1553,8 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( } } } + + Ok(()) } #[instrument(level = "debug", skip(selcx, obligation, candidate_set))] @@ -1529,27 +1562,33 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>, -) { +) -> Result<(), Overflow> { // Can't assemble candidate from impl for RPITIT if selcx.tcx().def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder { - return; + return Ok(()); } // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx())); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - let _ = selcx.infcx().commit_if_ok(|_| { + // FIXME: This commit is pretty damn cursed xx. + // + // We need it as the returned candidate references inference variables created in this snapshot. + selcx.infcx().commit_if_ok(|_| { let impl_source = match selcx.select(&trait_obligation) { - Ok(Some(impl_source)) => impl_source, - Ok(None) => { + Ok(Ok(impl_source)) => impl_source, + Ok(Err(true)) => { + return Err(Overflow); + } + Ok(Err(false)) => { candidate_set.mark_ambiguous(); - return Err(()); + return Ok(()); } Err(e) => { debug!(error = ?e, "selection error"); candidate_set.mark_error(e); - return Err(()); + return Ok(()); } }; @@ -1582,8 +1621,14 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // NOTE: This should be kept in sync with the similar code in // `rustc_ty_utils::instance::resolve_associated_item()`. let node_item = - assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) - .map_err(|ErrorGuaranteed { .. }| ())?; + match assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) + { + Ok(def) => def, + Err(ErrorGuaranteed { .. }) => { + candidate_set.mark_error(SelectionError::ErrorReporting); + return Ok(()); + } + }; if node_item.is_final() { // Non-specializable items are always projectable. @@ -1667,10 +1712,10 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation.recursion_depth + 1, ty, ) - .value + .map(|n| n.value) }, || {}, - ); + )?; match tail.kind() { ty::Bool @@ -1775,43 +1820,39 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation.cause.span, &format!("Cannot project an associated type from `{:?}`", impl_source), ); - return Err(()); + return Ok(()); } }; if eligible { - if candidate_set.push_candidate(ProjectionCandidate::Select(impl_source)) { - Ok(()) - } else { - Err(()) - } - } else { - Err(()) + candidate_set.push_candidate(ProjectionCandidate::Select(impl_source)); } - }); + + Ok(()) + }) } fn confirm_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, candidate: ProjectionCandidate<'tcx>, -) -> Progress<'tcx> { +) -> Result, Overflow> { debug!(?obligation, ?candidate, "confirm_candidate"); let mut progress = match candidate { ProjectionCandidate::ParamEnv(poly_projection) | ProjectionCandidate::Object(poly_projection) => { - confirm_param_env_candidate(selcx, obligation, poly_projection, false) + confirm_param_env_candidate(selcx, obligation, poly_projection, false)? } ProjectionCandidate::TraitDef(poly_projection) => { - confirm_param_env_candidate(selcx, obligation, poly_projection, true) + confirm_param_env_candidate(selcx, obligation, poly_projection, true)? } ProjectionCandidate::Select(impl_source) => { - confirm_select_candidate(selcx, obligation, impl_source) + confirm_select_candidate(selcx, obligation, impl_source)? } ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Impl(data)) => { - confirm_impl_trait_in_trait_candidate(selcx, obligation, data) + confirm_impl_trait_in_trait_candidate(selcx, obligation, data)? } // If we're projecting an RPITIT for a default trait body, that's just // the same def-id, but as an opaque type (with regular RPIT semantics). @@ -1833,14 +1874,14 @@ fn confirm_candidate<'cx, 'tcx>( progress.term = progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx())); } - progress + Ok(progress) } fn confirm_select_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, impl_source: Selection<'tcx>, -) -> Progress<'tcx> { +) -> Result, Overflow> { match impl_source { super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data), @@ -1871,7 +1912,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, impl_source: ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { +) -> Result, Overflow> { let gen_sig = impl_source.substs.as_generator().poly_sig(); let Normalized { value: gen_sig, obligations } = normalize_with_depth( selcx, @@ -1879,7 +1920,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( obligation.cause.clone(), obligation.recursion_depth + 1, gen_sig, - ); + )?; debug!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate"); @@ -1912,16 +1953,16 @@ fn confirm_generator_candidate<'cx, 'tcx>( } }); - confirm_param_env_candidate(selcx, obligation, predicate, false) + Ok(confirm_param_env_candidate(selcx, obligation, predicate, false)? .with_addl_obligations(impl_source.nested) - .with_addl_obligations(obligations) + .with_addl_obligations(obligations)) } fn confirm_discriminant_kind_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, _: ImplSourceDiscriminantKindData, -) -> Progress<'tcx> { +) -> Result, Overflow> { let tcx = selcx.tcx(); let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); @@ -1946,7 +1987,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, _: ImplSourcePointeeData, -) -> Progress<'tcx> { +) -> Result, Overflow> { let tcx = selcx.tcx(); let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); @@ -1959,8 +2000,9 @@ fn confirm_pointee_candidate<'cx, 'tcx>( obligation.recursion_depth + 1, ty, &mut obligations, + false, ) - }); + })?; if check_is_sized { let sized_predicate = ty::Binder::dummy(ty::TraitRef::new( tcx.require_lang_item(LangItem::Sized, None), @@ -1983,15 +2025,15 @@ fn confirm_pointee_candidate<'cx, 'tcx>( term: metadata_ty.into(), }; - confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) - .with_addl_obligations(obligations) + Ok(confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)? + .with_addl_obligations(obligations)) } fn confirm_fn_pointer_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, fn_pointer_impl_source: ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { +) -> Result, Overflow> { let fn_type = selcx.infcx().shallow_resolve(fn_pointer_impl_source.fn_ty); let sig = fn_type.fn_sig(selcx.tcx()); let Normalized { value: sig, obligations } = normalize_with_depth( @@ -2000,18 +2042,18 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>( obligation.cause.clone(), obligation.recursion_depth + 1, sig, - ); + )?; - confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) + Ok(confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)? .with_addl_obligations(fn_pointer_impl_source.nested) - .with_addl_obligations(obligations) + .with_addl_obligations(obligations)) } fn confirm_closure_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, impl_source: ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { +) -> Result, Overflow> { let closure_sig = impl_source.substs.as_closure().sig(); let Normalized { value: closure_sig, obligations } = normalize_with_depth( selcx, @@ -2019,13 +2061,13 @@ fn confirm_closure_candidate<'cx, 'tcx>( obligation.cause.clone(), obligation.recursion_depth + 1, closure_sig, - ); + )?; debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate"); - confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No) + Ok(confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)? .with_addl_obligations(impl_source.nested) - .with_addl_obligations(obligations) + .with_addl_obligations(obligations)) } fn confirm_callable_candidate<'cx, 'tcx>( @@ -2033,7 +2075,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, fn_sig: ty::PolyFnSig<'tcx>, flag: util::TupleArgumentsFlag, -) -> Progress<'tcx> { +) -> Result, Overflow> { let tcx = selcx.tcx(); debug!(?obligation, ?fn_sig, "confirm_callable_candidate"); @@ -2064,7 +2106,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, poly_cache_entry: ty::PolyProjectionPredicate<'tcx>, potentially_unnormalized_candidate: bool, -) -> Progress<'tcx> { +) -> Result, Overflow> { let infcx = selcx.infcx(); let cause = &obligation.cause; let param_env = obligation.param_env; @@ -2086,8 +2128,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>( obligation.recursion_depth + 1, obligation_projection, &mut nested_obligations, + false, ) - }); + })?; let cache_projection = if potentially_unnormalized_candidate { ensure_sufficient_stack(|| { normalize_with_depth_to( @@ -2097,8 +2140,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>( obligation.recursion_depth + 1, cache_projection, &mut nested_obligations, + false, ) - }) + })? } else { cache_projection }; @@ -2108,10 +2152,10 @@ fn confirm_param_env_candidate<'cx, 'tcx>( match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) { Ok(InferOk { value: _, obligations }) => { nested_obligations.extend(obligations); - assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); + assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations)?; // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take // a term instead. - Progress { term: cache_entry.term, obligations: nested_obligations } + Ok(Progress { term: cache_entry.term, obligations: nested_obligations }) } Err(e) => { let msg = format!( @@ -2120,7 +2164,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( ); debug!("confirm_param_env_candidate: {}", msg); let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg); - Progress { term: err.into(), obligations: vec![] } + Ok(Progress { term: err.into(), obligations: vec![] }) } } } @@ -2129,7 +2173,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, impl_impl_source: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { +) -> Result, Overflow> { let tcx = selcx.tcx(); let ImplSourceUserDefinedData { impl_def_id, substs, mut nested } = impl_impl_source; @@ -2138,7 +2182,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let param_env = obligation.param_env; let Ok(assoc_ty) = assoc_def(selcx, impl_def_id, assoc_item_id) else { - return Progress { term: tcx.ty_error().into(), obligations: nested }; + return Ok(Progress { term: tcx.ty_error().into(), obligations: nested }); }; if !assoc_ty.item.defaultness(tcx).has_value() { @@ -2150,7 +2194,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( "confirm_impl_candidate: no associated type {:?} for {:?}", assoc_ty.item.name, obligation.predicate ); - return Progress { term: tcx.ty_error().into(), obligations: nested }; + return Ok(Progress { term: tcx.ty_error().into(), obligations: nested }); } // If we're trying to normalize ` as X>::A` using //`impl X for Vec { type A = Box; }`, then: @@ -2172,16 +2216,16 @@ fn confirm_impl_candidate<'cx, 'tcx>( } else { ty.map_bound(|ty| ty.into()) }; - if !check_substs_compatible(tcx, &assoc_ty.item, substs) { + Ok(if !check_substs_compatible(tcx, &assoc_ty.item, substs) { let err = tcx.ty_error_with_message( obligation.cause.span, "impl item and trait item have different parameters", ); Progress { term: err.into(), obligations: nested } } else { - assoc_ty_own_obligations(selcx, obligation, &mut nested); + assoc_ty_own_obligations(selcx, obligation, &mut nested)?; Progress { term: term.subst(tcx, substs), obligations: nested } - } + }) } // Verify that the trait item and its implementation have compatible substs lists @@ -2229,26 +2273,26 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, data: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { +) -> Result, Overflow> { let tcx = selcx.tcx(); let mut obligations = data.nested; let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id); let Ok(leaf_def) = assoc_def(selcx, data.impl_def_id, trait_fn_def_id) else { - return Progress { term: tcx.ty_error().into(), obligations }; + return Ok(Progress { term: tcx.ty_error().into(), obligations }); }; if !leaf_def.item.defaultness(tcx).has_value() { - return Progress { term: tcx.ty_error().into(), obligations }; + return Ok(Progress { term: tcx.ty_error().into(), obligations }); } // Use the default `impl Trait` for the trait, e.g., for a default trait body if leaf_def.item.container == ty::AssocItemContainer::TraitContainer { - return Progress { + return Ok(Progress { term: tcx .mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs) .into(), obligations, - }; + }); } // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque}, @@ -2268,7 +2312,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( obligation.cause.span, "impl method and trait method have different parameters", ); - return Progress { term: err.into(), obligations }; + return Ok(Progress { term: err.into(), obligations }); } let impl_fn_def_id = leaf_def.item.def_id; @@ -2285,7 +2329,8 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( obligation.recursion_depth + 1, tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs), &mut obligations, - ); + false, + )?; obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map( |(pred, span)| { Obligation::with_depth( @@ -2305,19 +2350,21 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( }, )); - let ty = super::normalize_to( + let ty = normalize_with_depth_to( selcx, obligation.param_env, cause.clone(), + obligation.recursion_depth + 1, tcx.bound_trait_impl_trait_tys(impl_fn_def_id) .map_bound(|tys| { tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id]) }) .subst(tcx, impl_fn_substs), &mut obligations, - ); + false, + )?; - Progress { term: ty.into(), obligations } + Ok(Progress { term: ty.into(), obligations }) } // Get obligations corresponding to the predicates from the where-clause of the @@ -2326,7 +2373,7 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, nested: &mut Vec>, -) { +) -> Result<(), Overflow> { let tcx = selcx.tcx(); for predicate in tcx .predicates_of(obligation.predicate.item_def_id) @@ -2340,7 +2387,8 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( obligation.recursion_depth + 1, predicate, nested, - ); + false, + )?; nested.push(Obligation::with_depth( obligation.cause.clone(), obligation.recursion_depth + 1, @@ -2348,6 +2396,7 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( normalized, )); } + Ok(()) } /// Locate the definition of an associated type in the specialization hierarchy, diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index c84f128ddf78e..17b7482a7da68 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -2,9 +2,7 @@ use rustc_middle::ty; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; -use crate::traits::{ - EvaluationResult, OverflowError, PredicateObligation, SelectionContext, TraitQueryMode, -}; +use crate::traits::{EvaluationResult, PredicateObligation}; pub trait InferCtxtExt<'tcx> { fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool; @@ -16,26 +14,14 @@ pub trait InferCtxtExt<'tcx> { fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool; - fn evaluate_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> Result; - - // Helper function that canonicalizes and runs the query. If an - // overflow results, we re-run it in the local context so we can - // report a nice error. - /*crate*/ - fn evaluate_obligation_no_overflow( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> EvaluationResult; + fn evaluate_obligation(&self, obligation: &PredicateObligation<'tcx>) -> EvaluationResult; } impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) /// in the given `ParamEnv`. fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { - self.evaluate_obligation_no_overflow(obligation).may_apply() + self.evaluate_obligation(obligation).may_apply() } /// Evaluates whether the predicate can be satisfied in the given @@ -48,7 +34,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, ) -> bool { - self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions() + self.evaluate_obligation(obligation).must_apply_considering_regions() } /// Evaluates whether the predicate can be satisfied in the given @@ -57,14 +43,11 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// /// This version ignores all outlives constraints. fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool { - self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions() + self.evaluate_obligation(obligation).must_apply_modulo_regions() } /// Evaluate a given predicate, capturing overflow and propagating it back. - fn evaluate_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> Result { + fn evaluate_obligation(&self, obligation: &PredicateObligation<'tcx>) -> EvaluationResult { let mut _orig_values = OriginalQueryValues::default(); let param_env = match obligation.predicate.kind().skip_binder() { @@ -81,38 +64,6 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let c_pred = self .canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values); - // Run canonical query. If overflow occurs, rerun from scratch but this time - // in standard trait query mode so that overflow is handled appropriately - // within `SelectionContext`. self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) } - - // Helper function that canonicalizes and runs the query. If an - // overflow results, we re-run it in the local context so we can - // report a nice error. - fn evaluate_obligation_no_overflow( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> EvaluationResult { - match self.evaluate_obligation(obligation) { - Ok(result) => result, - Err(OverflowError::Canonical) => { - let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard); - selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r { - OverflowError::Canonical => { - span_bug!( - obligation.cause.span, - "Overflow should be caught earlier in standard query mode: {:?}, {:?}", - obligation, - r, - ) - } - OverflowError::ErrorReporting => EvaluationResult::EvaluatedToErr, - OverflowError::Error(_) => EvaluationResult::EvaluatedToErr, - }) - } - Err(OverflowError::ErrorReporting) => EvaluationResult::EvaluatedToErr, - Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr, - } - } } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index a7932b332c94b..eb73a08b4016c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -10,6 +10,7 @@ use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderR use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_infer::infer::canonical::Certainty; use rustc_infer::traits::Normalized; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable}; @@ -252,17 +253,21 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); let result = tcx.normalize_projection_ty(c_data)?; - // We don't expect ambiguity. - if result.is_ambiguous() { - // Rustdoc normalizes possibly not well-formed types, so only - // treat this as a bug if we're not in rustdoc. - if !tcx.sess.opts.actually_rustdoc { - tcx.sess.delay_span_bug( - DUMMY_SP, - format!("unexpected ambiguity: {:?} {:?}", c_data, result), - ); + match result.certainty() { + Certainty::Proven => {} + Certainty::Ambiguous => { + if !tcx.sess.opts.actually_rustdoc { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); + } + return Err(NoSolution); } - return Err(NoSolution); + Certainty::Overflow => self.infcx.err_ctxt().report_overflow_error( + &Obligation::new(ObligationCause::dummy(), self.param_env, ty), + true, + ), } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( @@ -303,17 +308,23 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); let result = tcx.normalize_projection_ty(c_data)?; - // We don't expect ambiguity. - if result.is_ambiguous() { - // Rustdoc normalizes possibly not well-formed types, so only - // treat this as a bug if we're not in rustdoc. - if !tcx.sess.opts.actually_rustdoc { - tcx.sess.delay_span_bug( - DUMMY_SP, - format!("unexpected ambiguity: {:?} {:?}", c_data, result), - ); + + match result.certainty() { + Certainty::Proven => {} + Certainty::Ambiguous => { + // We don't expect ambiguity. + if !tcx.sess.opts.actually_rustdoc { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); + } + return Err(NoSolution); } - return Err(NoSolution); + Certainty::Overflow => self.infcx.err_ctxt().report_overflow_error( + &Obligation::new(ObligationCause::dummy(), self.param_env, ty), + true, + ), } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs index 8cf500a466bf2..7b730e468a49a 100644 --- a/compiler/rustc_trait_selection/src/traits/relationships.rs +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -42,7 +42,7 @@ pub(crate) fn update<'tcx, T>( .to_predicate(infcx.tcx), ); // Don't report overflow errors. Otherwise equivalent to may_hold. - if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) && result.may_apply() { + if infcx.evaluate_obligation(&o).may_apply() { engine.relationships().entry(ty).or_default().self_in_trait = true; } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3671a0d87df57..6521833bcaa47 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -5,38 +5,46 @@ //! candidates. See the [rustc dev guide] for more details. //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly +use crate::traits; +use crate::traits::coherence::Conflict; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::Unimplemented; +use crate::traits::{util, SelectionResult}; use hir::LangItem; use rustc_errors::DelayDm; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_infer::traits::ObligationCause; -use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_infer::traits::{EvaluationResult, ObligationCause, Overflow}; +use rustc_infer::traits::{Obligation, TraitObligation}; use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable}; use rustc_target::spec::abi::Abi; -use crate::traits; -use crate::traits::coherence::Conflict; -use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{util, SelectionResult}; -use crate::traits::{ErrorReporting, Overflow, Unimplemented}; - use super::BuiltinImplConditions; use super::IntercrateAmbiguityCause; -use super::OverflowError; use super::SelectionCandidate::{self, *}; use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack}; +/// `?` except that it targets the inner `Option`, i.e. returns `Ok(None)`. +macro_rules! try_nested { + ($e:expr) => { + match $e { + Some(ok) => ok, + None => return Ok(None), + } + }; +} + impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { #[instrument(level = "debug", skip(self), ret)] pub(super) fn candidate_from_obligation<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - // Watch out for overflow. This intentionally bypasses (and does - // not update) the cache. - self.check_recursion_limit(&stack.obligation, &stack.obligation)?; + if !self.infcx.tcx.recursion_limit().value_within_limit(stack.obligation.recursion_depth) { + return Ok(Err(true)); + } // Check the cache. Note that we freshen the trait-ref // separately rather than using `stack.fresh_trait_ref` -- @@ -85,7 +93,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut no_candidates_apply = true; for c in candidate_set.vec.iter() { - if self.evaluate_candidate(stack, &c)?.may_apply() { + if self.evaluate_candidate(stack, &c).may_apply() { no_candidates_apply = false; break; } @@ -113,14 +121,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } - return Ok(None); + return Ok(Err(false)); } - let candidate_set = self.assemble_candidates(stack)?; + let candidate_set = match self.assemble_candidates(stack) { + Ok(result) => result, + Err(Overflow) => return Ok(Err(true)), + }; if candidate_set.ambiguous { debug!("candidate set contains ambig"); - return Ok(None); + return Ok(Err(false)); } let candidates = candidate_set.vec; @@ -160,17 +171,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // is needed for specialization. Propagate overflow if it occurs. let mut candidates = candidates .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { - Ok(eval) if eval.may_apply() => { - Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) - } - Ok(_) => Ok(None), - Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)), - Err(OverflowError::ErrorReporting) => Err(ErrorReporting), - Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))), + .map(|c| { + let evaluation = self.evaluate_candidate(stack, &c); + EvaluatedCandidate { candidate: c, evaluation } }) - .flat_map(Result::transpose) - .collect::, _>>()?; + .filter(|c| c.evaluation.may_apply()) + .collect::>(); debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len()); @@ -199,8 +205,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If there are *STILL* multiple candidates, give up // and report ambiguity. if i > 1 { - debug!("multiple matches, ambig"); - return Ok(None); + let due_to_overflow = candidates + .iter() + .any(|c| c.evaluation == EvaluationResult::EvaluatedToOverflow); + if due_to_overflow { + debug!("multiple matches, overflow"); + return Ok(Err(true)); + } else { + debug!("multiple matches, ambig"); + return Ok(Err(false)); + } } } } @@ -222,7 +236,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // to have emitted at least one. if stack.obligation.predicate.references_error() { debug!(?stack.obligation.predicate, "found error type in predicate, treating as ambiguous"); - return Ok(None); + return Ok(Err(false)); } return Err(Unimplemented); } @@ -235,7 +249,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub(super) fn assemble_candidates<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, - ) -> Result, SelectionError<'tcx>> { + ) -> Result, Overflow> { let TraitObligationStack { obligation, .. } = *stack; let obligation = &Obligation { param_env: obligation.param_env, @@ -295,7 +309,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let sized_conditions = self.sized_conditions(obligation); self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); } else if lang_items.unsize_trait() == Some(def_id) { - self.assemble_candidates_for_unsizing(obligation, &mut candidates); + self.assemble_candidates_for_unsizing(obligation, &mut candidates)?; } else if lang_items.destruct_trait() == Some(def_id) { self.assemble_const_destruct_candidates(obligation, &mut candidates); } else if lang_items.transmute_trait() == Some(def_id) { @@ -320,7 +334,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_from_object_ty(obligation, &mut candidates); } - self.assemble_candidates_from_projected_tys(obligation, &mut candidates); + self.assemble_candidates_from_projected_tys(obligation, &mut candidates)?; self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; // Auto implementations have lower priority, so we only // consider triggering a default if there is no other impl that can apply. @@ -337,7 +351,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, - ) { + ) -> Result<(), Overflow> { // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. match obligation.predicate.skip_binder().trait_ref.self_ty().kind() { @@ -348,16 +362,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { "Self=_ should have been handled by assemble_candidates" ); } - _ => return, + _ => return Ok(()), } let result = self .infcx - .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); + .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation))?; candidates .vec .extend(result.into_iter().map(|(idx, constness)| ProjectionCandidate(idx, constness))); + Ok(()) } /// Given an obligation like ``, searches the obligations that the caller @@ -369,7 +384,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { + ) -> Result<(), Overflow> { debug!(?stack.obligation); let all_bounds = stack @@ -387,8 +402,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for bound in matching_bounds { // FIXME(oli-obk): it is suspicious that we are dropping the constness and // polarity here. - let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?; - if wc.may_apply() { + let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref)); + if wc.is_overflow() { + return Err(Overflow); + } else if wc.may_apply() { candidates.vec.push(ParamCandidate(bound)); } } @@ -705,15 +722,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, cause: &ObligationCause<'tcx>, - ) -> Option<(Ty<'tcx>, DefId)> { + ) -> Result, DefId)>, Overflow> { let tcx = self.tcx(); if tcx.features().trait_upcasting { - return None; + return Ok(None); } // let trait_ref = ty::TraitRef { - def_id: tcx.lang_items().deref_trait()?, + def_id: try_nested!(tcx.lang_items().deref_trait()), substs: tcx.mk_substs_trait(ty, &[]), }; @@ -723,14 +740,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), ); if !self.infcx.predicate_may_hold(&obligation) { - return None; + return Ok(None); } let ty = traits::normalize_projection_type( self, param_env, ty::ProjectionTy { - item_def_id: tcx.lang_items().deref_target()?, + item_def_id: try_nested!(tcx.lang_items().deref_target()), substs: trait_ref.substs, }, cause.clone(), @@ -738,15 +755,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We're *intentionally* throwing these away, // since we don't actually use them. &mut vec![], - ) + )? .ty() .unwrap(); - if let ty::Dynamic(data, ..) = ty.kind() { - Some((ty, data.principal_def_id()?)) + Ok(if let ty::Dynamic(data, ..) = ty.kind() { + data.principal_def_id().map(|def| (ty, def)) } else { None - } + }) } /// Searches for unsizing that might apply to `obligation`. @@ -754,7 +771,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, - ) { + ) -> Result<(), Overflow> { // We currently never consider higher-ranked obligations e.g. // `for<'a> &'a T: Unsize` to be implemented. This is not // because they are a priori invalid, and we could potentially add support @@ -771,7 +788,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // obligation above. Should be possible to extend this in the future. let Some(source) = obligation.self_ty().no_bound_vars() else { // Don't add any candidates if there are bound regions. - return; + return Ok(()); }; let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); @@ -811,7 +828,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { source, obligation.param_env, &obligation.cause, - ) + )? { if deref_output_trait_did == target_trait_did { self.tcx().struct_span_lint_hir( @@ -824,7 +841,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { )), |lint| lint, ); - return; + return Ok(()); } } @@ -873,6 +890,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => {} }; + + Ok(()) } #[instrument(level = "debug", skip(self, obligation, candidates))] diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 28b4bae7cbecf..7c114934f2dec 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -11,6 +11,7 @@ use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; +use rustc_infer::traits::Overflow; use rustc_middle::ty::{ self, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, @@ -36,21 +37,41 @@ use super::SelectionContext; use std::iter; use std::ops::ControlFlow; +/// `?` except that it targets the inner `Result`, i.e. returns `Ok(Err(e))`. +macro_rules! try_nested { + ($e:expr) => { + match $e { + Ok(ok) => ok, + Err(e) => return Ok(Err(e)), + } + }; +} + +macro_rules! propagate_err { + ($e:expr) => { + match $e { + Ok(Ok(ok)) => ok, + Ok(Err(e)) => return Ok(Err(e)), + Err(e) => return Err(e), + } + }; +} + impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { #[instrument(level = "debug", skip(self))] pub(super) fn confirm_candidate( &mut self, obligation: &TraitObligation<'tcx>, candidate: SelectionCandidate<'tcx>, - ) -> Result, SelectionError<'tcx>> { + ) -> Result, SelectionError<'tcx>>, Overflow> { let mut impl_src = match candidate { BuiltinCandidate { has_nested } => { - let data = self.confirm_builtin_candidate(obligation, has_nested); + let data = self.confirm_builtin_candidate(obligation, has_nested)?; ImplSource::Builtin(data) } TransmutabilityCandidate => { - let data = self.confirm_transmutability_candidate(obligation)?; + let data = try_nested!(self.confirm_transmutability_candidate(obligation)); ImplSource::Builtin(data) } @@ -61,36 +82,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ImplCandidate(impl_def_id) => { - ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id)) + ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id)?) } AutoImplCandidate => { - let data = self.confirm_auto_impl_candidate(obligation); + let data = self.confirm_auto_impl_candidate(obligation)?; ImplSource::AutoImpl(data) } ProjectionCandidate(idx, constness) => { - let obligations = self.confirm_projection_candidate(obligation, idx)?; + let obligations = + propagate_err!(self.confirm_projection_candidate(obligation, idx)); ImplSource::Param(obligations, constness) } ObjectCandidate(idx) => { - let data = self.confirm_object_candidate(obligation, idx)?; + let data = propagate_err!(self.confirm_object_candidate(obligation, idx)); ImplSource::Object(data) } ClosureCandidate => { - let vtable_closure = self.confirm_closure_candidate(obligation)?; + let vtable_closure = propagate_err!(self.confirm_closure_candidate(obligation)); ImplSource::Closure(vtable_closure) } GeneratorCandidate => { - let vtable_generator = self.confirm_generator_candidate(obligation)?; + let vtable_generator = propagate_err!(self.confirm_generator_candidate(obligation)); ImplSource::Generator(vtable_generator) } FnPointerCandidate { .. } => { - let data = self.confirm_fn_pointer_candidate(obligation)?; + let data = propagate_err!(self.confirm_fn_pointer_candidate(obligation)); ImplSource::FnPointer(data) } @@ -101,7 +123,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData), TraitAliasCandidate => { - let data = self.confirm_trait_alias_candidate(obligation); + let data = self.confirm_trait_alias_candidate(obligation)?; ImplSource::TraitAlias(data) } @@ -113,12 +135,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } BuiltinUnsizeCandidate => { - let data = self.confirm_builtin_unsize_candidate(obligation)?; + let data = propagate_err!(self.confirm_builtin_unsize_candidate(obligation)); ImplSource::Builtin(data) } TraitUpcastingUnsizeCandidate(idx) => { - let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?; + let data = + try_nested!(self.confirm_trait_upcasting_unsize_candidate(obligation, idx)); ImplSource::TraitUpcasting(data) } @@ -136,14 +159,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); } - Ok(impl_src) + Ok(Ok(impl_src)) } fn confirm_projection_candidate( &mut self, obligation: &TraitObligation<'tcx>, idx: usize, - ) -> Result>, SelectionError<'tcx>> { + ) -> Result>, SelectionError<'tcx>>, Overflow> { let tcx = self.tcx(); let trait_predicate = self.infcx.shallow_resolve(obligation.predicate); @@ -171,15 +194,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, candidate, &mut obligations, - ); + false, + )?; - obligations.extend(self.infcx.commit_if_ok(|_| { + obligations.extend(try_nested!(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) .sup(placeholder_trait_predicate, candidate) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) - })?); + }))); if let ty::Projection(..) = placeholder_self_ty.kind() { let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates; @@ -192,7 +216,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, predicate, &mut obligations, - ); + false, + )?; obligations.push(Obligation::with_depth( obligation.cause.clone(), obligation.recursion_depth + 1, @@ -202,7 +227,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - Ok(obligations) + Ok(Ok(obligations)) } fn confirm_param_candidate( @@ -232,7 +257,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, has_nested: bool, - ) -> ImplSourceBuiltinData> { + ) -> Result>, Overflow> { debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); let lang_items = self.tcx().lang_items(); @@ -260,14 +285,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_def, nested, ) - }) + })? } else { vec![] }; debug!(?obligations); - ImplSourceBuiltinData { nested: obligations } + Ok(ImplSourceBuiltinData { nested: obligations }) } fn confirm_transmutability_candidate( @@ -315,7 +340,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_auto_impl_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> ImplSourceAutoImplData> { + ) -> Result>, Overflow> { debug!(?obligation, "confirm_auto_impl_candidate"); let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty()); @@ -329,21 +354,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, trait_def_id: DefId, nested: ty::Binder<'tcx, Vec>>, - ) -> ImplSourceAutoImplData> { + ) -> Result>, Overflow> { debug!(?nested, "vtable_auto_impl"); ensure_sufficient_stack(|| { let cause = obligation.derived_cause(BuiltinDerivedObligation); let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref); - let trait_obligations: Vec> = self.impl_or_trait_obligations( + let trait_obligations = self.impl_or_trait_obligations( &cause, obligation.recursion_depth + 1, obligation.param_env, trait_def_id, &trait_ref.substs, obligation.predicate, - ); + )?; let mut obligations = self.collect_predicates_for_types( obligation.param_env, @@ -351,7 +376,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, trait_def_id, nested, - ); + )?; // Adds the predicates from the trait. Note that this contains a `Self: Trait` // predicate as usual. It won't have any effect since auto traits are coinductive. @@ -359,7 +384,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligations, "vtable_auto_impl"); - ImplSourceAutoImplData { trait_def_id, nested: obligations } + Ok(ImplSourceAutoImplData { trait_def_id, nested: obligations }) }) } @@ -367,12 +392,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, impl_def_id: DefId, - ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { + ) -> Result>, Overflow> { debug!(?obligation, ?impl_def_id, "confirm_impl_candidate"); // First, create the substitutions by matching the impl again, // this time not in a probe. - let substs = self.rematch_impl(impl_def_id, obligation); + let substs = self.rematch_impl(impl_def_id, obligation)?; debug!(?substs, "impl substs"); ensure_sufficient_stack(|| { self.vtable_impl( @@ -394,7 +419,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, - ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { + ) -> Result>, Overflow> { debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl"); let mut impl_obligations = self.impl_or_trait_obligations( @@ -404,7 +429,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id, &substs.value, parent_trait_pred, - ); + )?; debug!(?impl_obligations, "vtable_impl"); @@ -415,14 +440,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // e.g., `impl> Foo<::T> for V` impl_obligations.extend(substs.obligations); - ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations } + Ok(ImplSourceUserDefinedData { + impl_def_id, + substs: substs.value, + nested: impl_obligations, + }) } fn confirm_object_candidate( &mut self, obligation: &TraitObligation<'tcx>, index: usize, - ) -> Result>, SelectionError<'tcx>> { + ) -> Result< + Result>, SelectionError<'tcx>>, + Overflow, + > { let tcx = self.tcx(); debug!(?obligation, ?index, "confirm_object_candidate"); @@ -456,15 +488,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, unnormalized_upcast_trait_ref, &mut nested, - ); + false, + )?; - nested.extend(self.infcx.commit_if_ok(|_| { + nested.extend(try_nested!(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) .sup(obligation_trait_ref, upcast_trait_ref) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) - })?); + }))); // Check supertraits hold. This is so that their associated type bounds // will be checked in the code below. @@ -481,7 +514,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, super_trait, &mut nested, - ); + false, + )?; nested.push(Obligation::new( obligation.cause.clone(), obligation.param_env, @@ -505,7 +539,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.span, "GATs in trait object shouldn't have been considered", ); - return Err(SelectionError::Unimplemented); + return Ok(Err(SelectionError::Unimplemented)); } // This maybe belongs in wf, but that can't (doesn't) handle @@ -580,7 +614,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, subst_bound, &mut nested, - ); + false, + )?; nested.push(Obligation::new( obligation.cause.clone(), obligation.param_env, @@ -596,14 +631,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)), ); - Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested }) + Ok(Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested })) } fn confirm_fn_pointer_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> Result>, SelectionError<'tcx>> - { + ) -> Result< + Result>, SelectionError<'tcx>>, + Overflow, + > { debug!(?obligation, "confirm_fn_pointer_candidate"); // Okay to skip binder; it is reintroduced below. @@ -618,7 +655,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) .map_bound(|(trait_ref, _)| trait_ref); - let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let mut nested = propagate_err!(self.confirm_poly_trait_refs(obligation, trait_ref)); // Confirm the `type Output: Sized;` bound that is present on `FnOnce` let cause = obligation.derived_cause(BuiltinDerivedObligation); @@ -638,7 +675,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth, output_ty, &mut nested, - ); + false, + )?; let tr = ty::Binder::dummy(ty::TraitRef::new( self.tcx().require_lang_item(LangItem::Sized, None), self.tcx().mk_substs_trait(output_ty, &[]), @@ -649,13 +687,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tr.to_poly_trait_predicate().to_predicate(self.tcx()), )); - Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested }) + Ok(Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested })) } fn confirm_trait_alias_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> { + ) -> Result>, Overflow> { debug!(?obligation, "confirm_trait_alias_candidate"); let alias_def_id = obligation.predicate.def_id(); @@ -671,18 +709,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_def_id, &substs, obligation.predicate, - ); + )?; debug!(?trait_def_id, ?trait_obligations, "trait alias obligations"); - ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations } + Ok(ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }) } fn confirm_generator_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> Result>, SelectionError<'tcx>> - { + ) -> Result< + Result>, SelectionError<'tcx>>, + Overflow, + > { // Okay to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope // type/region parameters. @@ -695,17 +735,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = propagate_err!(self.confirm_poly_trait_refs(obligation, trait_ref)); debug!(?trait_ref, ?nested, "generator candidate obligations"); - Ok(ImplSourceGeneratorData { generator_def_id, substs, nested }) + Ok(Ok(ImplSourceGeneratorData { generator_def_id, substs, nested })) } #[instrument(skip(self), level = "debug")] fn confirm_closure_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> Result>, SelectionError<'tcx>> { + ) -> Result< + Result>, SelectionError<'tcx>>, + Overflow, + > { let kind = self .tcx() .fn_trait_kind_from_lang_item(obligation.predicate.def_id()) @@ -720,7 +763,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs); - let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let mut nested = propagate_err!(self.confirm_poly_trait_refs(obligation, trait_ref)); debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); @@ -735,7 +778,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { )); } - Ok(ImplSourceClosureData { closure_def_id, substs, nested }) + Ok(Ok(ImplSourceClosureData { closure_def_id, substs, nested })) } /// In the case of closure types and fn pointers, @@ -768,7 +811,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, expected_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result>, SelectionError<'tcx>> { + ) -> Result>, SelectionError<'tcx>>, Overflow> { let obligation_trait_ref = obligation.predicate.to_poly_trait_ref(); // Normalize the obligation and expected trait refs together, because why not let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } = @@ -780,16 +823,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, (obligation_trait_ref, expected_trait_ref), ) - }); + })?; - self.infcx + Ok(self + .infcx .at(&obligation.cause, obligation.param_env) .sup(obligation_trait_ref, expected_trait_ref) .map(|InferOk { mut obligations, .. }| { obligations.extend(nested); obligations }) - .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) + .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))) } fn confirm_trait_upcasting_unsize_candidate( @@ -905,7 +949,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_builtin_unsize_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> Result>, SelectionError<'tcx>> { + ) -> Result< + Result>, SelectionError<'tcx>>, + Overflow, + > { let tcx = self.tcx(); // `assemble_candidates_for_unsizing` should ensure there are no late-bound @@ -942,11 +989,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .sup(target, source_trait) - .map_err(|_| Unimplemented)?; + let InferOk { obligations, .. } = try_nested!( + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(target, source_trait) + .map_err(|_| Unimplemented) + ); nested.extend(obligations); // Register one obligation for 'a: 'b. @@ -968,7 +1016,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (_, &ty::Dynamic(ref data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { - return Err(TraitNotObjectSafe(did)); + return Ok(Err(TraitNotObjectSafe(did))); } let cause = ObligationCause::new( @@ -1013,11 +1061,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `[T; n]` -> `[T]` (&ty::Array(a, _), &ty::Slice(b)) => { - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(b, a) - .map_err(|_| Unimplemented)?; + let InferOk { obligations, .. } = try_nested!( + self.infcx + .at(&obligation.cause, obligation.param_env) + .eq(b, a) + .map_err(|_| Unimplemented) + ); nested.extend(obligations); } @@ -1043,8 +1092,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // looks at declared field types, not anything substituted. // The last field of the structure has to exist and contain type/const parameters. - let (tail_field, prefix_fields) = - def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?; + let Some((tail_field, prefix_fields)) = def.non_enum_variant().fields.split_last() + else { + return Ok(Err(Unimplemented)); + }; let tail_field_ty = tcx.bound_type_of(tail_field.did); let mut unsizing_params = GrowableBitSet::new_empty(); @@ -1065,7 +1116,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if unsizing_params.is_empty() { - return Err(Unimplemented); + return Ok(Err(Unimplemented)); } // Extract `TailField` and `TailField` from `Struct` and `Struct`, @@ -1078,7 +1129,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, tail_field_ty.subst(tcx, substs_a), &mut nested, - ); + false, + )?; let target_tail = normalize_with_depth_to( self, obligation.param_env, @@ -1086,7 +1138,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, tail_field_ty.subst(tcx, substs_b), &mut nested, - ); + false, + )?; // Check that the source struct with the target's // unsizing parameters is equal to the target. @@ -1094,11 +1147,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if unsizing_params.contains(i as u32) { substs_b[i] } else { k } })); let new_struct = tcx.mk_adt(def, substs); - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, new_struct) - .map_err(|_| Unimplemented)?; + let InferOk { obligations, .. } = try_nested!( + self.infcx + .at(&obligation.cause, obligation.param_env) + .eq(target, new_struct) + .map_err(|_| Unimplemented) + ); nested.extend(obligations); // Construct the nested `TailField: Unsize>` predicate. @@ -1118,17 +1172,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { assert_eq!(tys_a.len(), tys_b.len()); // The last field of the tuple has to exist. - let (&a_last, a_mid) = tys_a.split_last().ok_or(Unimplemented)?; + let Some((&a_last, a_mid)) = tys_a.split_last() else { + return Ok(Err(Unimplemented)); + }; let &b_last = tys_b.last().unwrap(); // Check that the source tuple with the target's // last element is equal to the target. let new_tuple = tcx.mk_tup(a_mid.iter().copied().chain(iter::once(b_last))); - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, new_tuple) - .map_err(|_| Unimplemented)?; + let InferOk { obligations, .. } = try_nested!( + self.infcx + .at(&obligation.cause, obligation.param_env) + .eq(target, new_tuple) + .map_err(|_| Unimplemented) + ); nested.extend(obligations); // Construct the nested `T: Unsize` predicate. @@ -1148,14 +1205,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!(), }; - Ok(ImplSourceBuiltinData { nested }) + Ok(Ok(ImplSourceBuiltinData { nested })) } fn confirm_const_destruct_candidate( &mut self, obligation: &TraitObligation<'tcx>, impl_def_id: Option, - ) -> Result>, SelectionError<'tcx>> { + ) -> Result>, Overflow> { // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop` if !obligation.is_const() { return Ok(ImplSourceConstDestructData { nested: vec![] }); @@ -1178,7 +1235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_pred.trait_ref.def_id = drop_trait; trait_pred }); - let substs = self.rematch_impl(impl_def_id, &new_obligation); + let substs = self.rematch_impl(impl_def_id, &new_obligation)?; debug!(?substs, "impl substs"); let cause = obligation.derived_cause(|derived| { @@ -1197,7 +1254,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { new_obligation.param_env, obligation.predicate, ) - }); + })?; nested.extend(obligations.nested); } @@ -1266,7 +1323,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) .to_predicate(tcx), &mut nested, - ); + false, + )?; nested.push(Obligation::with_depth( cause.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3a899c03b4c94..d3eff38ad9775 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -20,20 +20,19 @@ use super::util; use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; use super::wf; use super::{ - ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, - ObligationCause, ObligationCauseCode, Overflow, PredicateObligation, Selection, SelectionError, - SelectionResult, TraitObligation, TraitQueryMode, + ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, ObligationCause, + ObligationCauseCode, PredicateObligation, Selection, SelectionResult, TraitObligation, }; +use rustc_middle::traits::Overflow; use crate::infer::{InferCtxt, InferOk, TypeFreshener}; -use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{Diagnostic, ErrorGuaranteed}; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; @@ -50,7 +49,7 @@ use rustc_span::symbol::sym; use std::cell::{Cell, RefCell}; use std::cmp; -use std::fmt::{self, Display}; +use std::fmt; use std::iter; pub use rustc_middle::traits::select::*; @@ -135,11 +134,6 @@ pub struct SelectionContext<'cx, 'tcx> { /// lead to false overflow results (#47139) and because always /// computing it may negatively impact performance. intercrate_ambiguity_causes: Option>, - - /// The mode that trait queries run in, which informs our error handling - /// policy. In essence, canonicalized queries need their errors propagated - /// rather than immediately reported because we do not have accurate spans. - query_mode: TraitQueryMode, } // A stack that walks back up the stack frame. @@ -227,7 +221,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { freshener: infcx.freshener_keep_static(), intercrate: false, intercrate_ambiguity_causes: None, - query_mode: TraitQueryMode::Standard, } } @@ -235,14 +228,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { SelectionContext { intercrate: true, ..SelectionContext::new(infcx) } } - pub fn with_query_mode( - infcx: &'cx InferCtxt<'tcx>, - query_mode: TraitQueryMode, - ) -> SelectionContext<'cx, 'tcx> { - debug!(?query_mode, "with_query_mode"); - SelectionContext { query_mode, ..SelectionContext::new(infcx) } - } - /// Enables tracking of intercrate ambiguity causes. See /// the documentation of [`Self::intercrate_ambiguity_causes`] for more. pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { @@ -295,28 +280,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { let candidate = match self.select_from_obligation(obligation) { - Err(SelectionError::Overflow(OverflowError::Canonical)) => { - // In standard mode, overflow must have been caught and reported - // earlier. - assert!(self.query_mode == TraitQueryMode::Canonical); - return Err(SelectionError::Overflow(OverflowError::Canonical)); + Ok(Ok(candidate)) => candidate, + Ok(Err(overflow)) => { + return Ok(Err(overflow)); } Err(e) => { return Err(e); } - Ok(None) => { - return Ok(None); - } - Ok(Some(candidate)) => candidate, }; match self.confirm_candidate(obligation, candidate) { - Err(SelectionError::Overflow(OverflowError::Canonical)) => { - assert!(self.query_mode == TraitQueryMode::Canonical); - Err(SelectionError::Overflow(OverflowError::Canonical)) - } - Err(e) => Err(e), - Ok(candidate) => Ok(Some(candidate)), + Ok(Ok(candidate)) => Ok(Ok(candidate)), + Ok(Err(e)) => Err(e), + Err(Overflow) => Ok(Err(true)), } } @@ -342,26 +318,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // The result is "true" if the obligation *may* hold and "false" if // we can be sure it does not. - /// Evaluates whether the obligation `obligation` can be satisfied (by any means). - pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool { - debug!(?obligation, "predicate_may_hold_fatal"); - - // This fatal query is a stopgap that should only be used in standard mode, - // where we do not expect overflow to be propagated. - assert!(self.query_mode == TraitQueryMode::Standard); - - self.evaluate_root_obligation(obligation) - .expect("Overflow should be caught earlier in standard query mode") - .may_apply() - } - /// Evaluates whether the obligation `obligation` can be satisfied /// and returns an `EvaluationResult`. This is meant for the /// *initial* call. pub fn evaluate_root_obligation( &mut self, obligation: &PredicateObligation<'tcx>, - ) -> Result { + ) -> EvaluationResult { self.evaluation_probe(|this| { this.evaluate_predicate_recursively( TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), @@ -372,23 +335,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn evaluation_probe( &mut self, - op: impl FnOnce(&mut Self) -> Result, - ) -> Result { - self.infcx.probe(|snapshot| -> Result { - let result = op(self)?; + op: impl FnOnce(&mut Self) -> EvaluationResult, + ) -> EvaluationResult { + self.infcx.probe(|snapshot| { + let result = op(self); match self.infcx.leak_check(true, snapshot) { Ok(()) => {} - Err(_) => return Ok(EvaluatedToErr), + Err(_) => return EvaluatedToErr, } if self.infcx.opaque_types_added_in_snapshot(snapshot) { - return Ok(result.max(EvaluatedToOkModuloOpaqueTypes)); + return result.max(EvaluatedToOkModuloOpaqueTypes); } match self.infcx.region_constraints_added_in_snapshot(snapshot) { - None => Ok(result), - Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), + None => result, + Some(_) => result.max(EvaluatedToOkModuloRegions), } }) } @@ -401,22 +364,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: TraitObligationStackList<'o, 'tcx>, predicates: I, - ) -> Result + ) -> EvaluationResult where I: IntoIterator> + std::fmt::Debug, { let mut result = EvaluatedToOk; - for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; + for mut obligation in predicates { + obligation.recursion_depth = obligation.recursion_depth.max(stack.depth() + 1); + let eval = self.evaluate_predicate_recursively(stack, obligation); if let EvaluatedToErr = eval { // fast-path - EvaluatedToErr is the top of the lattice, // so we don't need to look on the other predicates. - return Ok(EvaluatedToErr); + return EvaluatedToErr; } else { result = cmp::max(result, eval); } } - Ok(result) + result } #[instrument( @@ -429,14 +393,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: PredicateObligation<'tcx>, - ) -> Result { - // `previous_stack` stores a `TraitObligation`, while `obligation` is - // a `PredicateObligation`. These are distinct types, so we can't - // use any `Option` combinator method that would force them to be - // the same. - match previous_stack.head() { - Some(h) => self.check_recursion_limit(&obligation, h.obligation)?, - None => self.check_recursion_limit(&obligation, &obligation)?, + ) -> EvaluationResult { + if !self.infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) { + return EvaluatedToOverflow; } ensure_sufficient_stack(|| { @@ -453,15 +412,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( + Ok(Ok(InferOk { obligations, .. })) => self + .evaluate_predicates_recursively( previous_stack, obligations.into_iter(), - ) - } - Ok(Err(_)) => Ok(EvaluatedToErr), - Err(..) => Ok(EvaluatedToAmbig), + ), + Ok(Err(_)) => EvaluatedToErr, + Err(..) => EvaluatedToAmbig, } } @@ -469,15 +426,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( + Ok(Ok(InferOk { obligations, .. })) => self + .evaluate_predicates_recursively( previous_stack, obligations.into_iter(), - ) - } - Ok(Err(_)) => Ok(EvaluatedToErr), - Err(..) => Ok(EvaluatedToAmbig), + ), + Ok(Err(_)) => EvaluatedToErr, + Err(..) => EvaluatedToAmbig, } } @@ -531,12 +486,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx)); if self.coinductive_match(cycle) { stack.update_reached_depth(stack_arg.1); - return Ok(EvaluatedToOk); + return EvaluatedToOk; } else { - return Ok(EvaluatedToRecur); + return EvaluatedToRecur; } } - return Ok(EvaluatedToOk); + return EvaluatedToOk; } match wf::obligations( @@ -546,8 +501,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, arg, obligation.cause.span, + false, ) { - Some(mut obligations) => { + Ok(Some(mut obligations)) => { self.add_depth(obligations.iter_mut(), obligation.recursion_depth); cache.wf_args.borrow_mut().push((arg, previous_stack.depth())); @@ -555,17 +511,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_predicates_recursively(previous_stack, obligations); cache.wf_args.borrow_mut().pop(); - let result = result?; - if !result.must_apply_modulo_regions() { cache.on_failure(dfn); } cache.on_completion(dfn); - Ok(result) + result } - None => Ok(EvaluatedToAmbig), + Ok(None) => EvaluatedToAmbig, + Err(Overflow) => EvaluatedToOverflow, } } @@ -575,22 +530,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // would either be late-bound or local), so it is guaranteed // to outlive any other lifetime if pred.0.is_global() && !pred.0.has_late_bound_regions() { - Ok(EvaluatedToOk) + EvaluatedToOk } else { - Ok(EvaluatedToOkModuloRegions) + EvaluatedToOkModuloRegions } } ty::PredicateKind::RegionOutlives(..) => { // We do not consider region relationships when evaluating trait matches. - Ok(EvaluatedToOkModuloRegions) + EvaluatedToOkModuloRegions } ty::PredicateKind::ObjectSafe(trait_def_id) => { if self.tcx().is_object_safe(trait_def_id) { - Ok(EvaluatedToOk) + EvaluatedToOk } else { - Ok(EvaluatedToErr) + EvaluatedToErr } } @@ -614,7 +569,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .projection_cache() .is_complete(key) { - break 'compute_res Ok(cached_res); + break 'compute_res cached_res; } } @@ -626,8 +581,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { previous_stack, subobligations, ); - if let Ok(eval_rslt) = res - && (eval_rslt == EvaluatedToOk || eval_rslt == EvaluatedToOkModuloRegions) + if res.must_apply_modulo_regions() && let Some(key) = ProjectionCacheKey::from_poly_projection_predicate( self, data, @@ -641,14 +595,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .inner .borrow_mut() .projection_cache() - .complete(key, eval_rslt); + .complete(key, res); } res } } - ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig), - ProjectAndUnifyResult::Recursive => Ok(EvaluatedToRecur), - ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr), + ProjectAndUnifyResult::FailedNormalization => EvaluatedToAmbig, + ProjectAndUnifyResult::Overflow => EvaluatedToOverflow, + ProjectAndUnifyResult::Recursive => EvaluatedToRecur, + ProjectAndUnifyResult::MismatchedProjectionTypes(_) => EvaluatedToErr, } } @@ -656,12 +611,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.infcx.closure_kind(closure_substs) { Some(closure_kind) => { if closure_kind.extends(kind) { - Ok(EvaluatedToOk) + EvaluatedToOk } else { - Ok(EvaluatedToErr) + EvaluatedToErr } } - None => Ok(EvaluatedToAmbig), + None => EvaluatedToAmbig, } } @@ -672,10 +627,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.span, ) { - Ok(()) => Ok(EvaluatedToOk), - Err(NotConstEvaluatable::MentionsInfer) => Ok(EvaluatedToAmbig), - Err(NotConstEvaluatable::MentionsParam) => Ok(EvaluatedToErr), - Err(_) => Ok(EvaluatedToErr), + Ok(()) => EvaluatedToOk, + Err(NotConstEvaluatable::MentionsInfer) => EvaluatedToAmbig, + Err(NotConstEvaluatable::MentionsParam) => EvaluatedToErr, + Err(_) => EvaluatedToErr, } } @@ -694,7 +649,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (c1.kind(), c2.kind()) { if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) { - return Ok(EvaluatedToOk); + return EvaluatedToOk; } } @@ -721,18 +676,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&obligation.cause, obligation.param_env) .eq(c1, c2) { - Ok(_) => Ok(EvaluatedToOk), - Err(_) => Ok(EvaluatedToErr), + Ok(_) => EvaluatedToOk, + Err(_) => EvaluatedToErr, } } (Err(ErrorHandled::Reported(_)), _) - | (_, Err(ErrorHandled::Reported(_))) => Ok(EvaluatedToErr), + | (_, Err(ErrorHandled::Reported(_))) => EvaluatedToErr, (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { if c1.has_non_region_infer() || c2.has_non_region_infer() { - Ok(EvaluatedToAmbig) + EvaluatedToAmbig } else { // Two different constants using generic parameters ~> error. - Ok(EvaluatedToErr) + EvaluatedToErr } } } @@ -749,7 +704,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>, - ) -> Result { + ) -> EvaluationResult { if !self.intercrate && obligation.is_global() && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst()) @@ -776,13 +731,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // then we know it holds without cycles. if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) { debug!("CACHE HIT"); - return Ok(result); + return result; } if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) { debug!("PROVISIONAL CACHE HIT"); stack.update_reached_depth(result.reached_depth); - return Ok(result.result); + return result.result; } // Check if this is a match for something already on the @@ -791,11 +746,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // cache (which is meant for things that have completed but // for a "backedge" -- this result *is* the backedge). if let Some(cycle_result) = self.check_evaluation_cycle(&stack) { - return Ok(cycle_result); + return cycle_result; } let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); - let result = result?; if !result.must_apply_modulo_regions() { stack.cache().on_failure(stack.dfn); @@ -817,7 +771,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result); } - Ok(result) + result } /// If there is any previous entry on the stack that precisely @@ -882,10 +836,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn evaluate_stack<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> Result { + fn evaluate_stack<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> EvaluationResult { // In intercrate mode, whenever any of the generics are unbound, // there can always be an impl. Even if there are no impls in // this crate, perhaps the type would be unified with @@ -924,15 +875,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) { debug!("evaluate_stack --> unbound argument, recursive --> giving up",); - return Ok(EvaluatedToUnknown); + return EvaluatedToOverflow; } match self.candidate_from_obligation(stack) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c), - Ok(None) => Ok(EvaluatedToAmbig), - Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical), - Err(ErrorReporting) => Err(OverflowError::ErrorReporting), - Err(..) => Ok(EvaluatedToErr), + Ok(Ok(c)) => self.evaluate_candidate(stack, &c), + Ok(Err(true)) => EvaluatedToOverflow, + Ok(Err(false)) => EvaluatedToAmbig, + Err(..) => EvaluatedToErr, } } @@ -974,20 +924,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, - ) -> Result { + ) -> EvaluationResult { let mut result = self.evaluation_probe(|this| { let candidate = (*candidate).clone(); match this.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => { + Ok(Ok(selection)) => { debug!(?selection); this.evaluate_predicates_recursively( stack.list(), selection.nested_obligations().into_iter(), ) } - Err(..) => Ok(EvaluatedToErr), + Ok(Err(..)) => EvaluatedToErr, + Err(Overflow) => EvaluatedToOverflow, } - })?; + }); // If we erased any lifetimes, then we want to use // `EvaluatedToOkModuloRegions` instead of `EvaluatedToOk` @@ -1001,7 +952,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { result = result.max(EvaluatedToOkModuloRegions); } - Ok(result) + result } fn check_evaluation_cache( @@ -1073,7 +1024,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// /// To ensure that obligation_depth never decreases, we force all subobligations /// to have at least the depth of the original obligation. - fn add_depth>>( + pub fn add_depth>>( &self, it: I, min_depth: usize, @@ -1081,42 +1032,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); } - fn check_recursion_depth>( - &self, - depth: usize, - error_obligation: &Obligation<'tcx, T>, - ) -> Result<(), OverflowError> { - if !self.infcx.tcx.recursion_limit().value_within_limit(depth) { - match self.query_mode { - TraitQueryMode::Standard => { - if self.infcx.is_tainted_by_errors() { - return Err(OverflowError::Error( - ErrorGuaranteed::unchecked_claim_error_was_emitted(), - )); - } - self.infcx.err_ctxt().report_overflow_error(error_obligation, true); - } - TraitQueryMode::Canonical => { - return Err(OverflowError::Canonical); - } - } - } - Ok(()) - } - - /// Checks that the recursion limit has not been exceeded. - /// - /// The weird return type of this function allows it to be used with the `try` (`?`) - /// operator within certain functions. - #[inline(always)] - fn check_recursion_limit, V: Display + TypeFoldable<'tcx>>( - &self, - obligation: &Obligation<'tcx, T>, - error_obligation: &Obligation<'tcx, V>, - ) -> Result<(), OverflowError> { - self.check_recursion_depth(obligation.recursion_depth, error_obligation) - } - fn in_task(&mut self, op: OP) -> (R, DepNodeIndex) where OP: FnOnce(&mut Self) -> R, @@ -1207,10 +1122,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } } - return Ok(None); + return Ok(Err(false)); } } - Ok(Some(candidate)) + Ok(Ok(candidate)) } fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> { @@ -1307,7 +1222,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return false; } match result { - Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(), + Ok(Ok(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(), _ => true, } } @@ -1331,9 +1246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if self.can_use_global_caches(param_env) { - if let Err(Overflow(OverflowError::Canonical)) = candidate { - // Don't cache overflow globally; we only produce this in certain modes. - } else if !pred.needs_infer() { + if !pred.needs_infer() { if !candidate.needs_infer() { debug!(?pred, ?candidate, "insert_candidate_cache global"); // This may overwrite the cache with the same value. @@ -1357,7 +1270,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_projection_obligation_against_definition_bounds( &mut self, obligation: &TraitObligation<'tcx>, - ) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 2]> { + ) -> Result, Overflow> { let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate); @@ -1383,19 +1296,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // unnecessary ambiguity. let mut distinct_normalized_bounds = FxHashSet::default(); - bounds - .iter() - .enumerate() - .filter_map(|(idx, bound)| { - let bound_predicate = bound.kind(); - if let ty::PredicateKind::Trait(pred) = bound_predicate.skip_binder() { - let bound = bound_predicate.rebind(pred.trait_ref); - if self.infcx.probe(|_| { + let mut result = smallvec::SmallVec::new(); + for (idx, bound) in bounds.iter().enumerate() { + let bound_predicate = bound.kind(); + if let ty::PredicateKind::Trait(pred) = bound_predicate.skip_binder() { + let bound = bound_predicate.rebind(pred.trait_ref); + if self.infcx.probe(|_| { + Ok( match self.match_normalize_trait_ref( obligation, bound, placeholder_trait_predicate.trait_ref, - ) { + )? { Ok(None) => true, Ok(Some(normalized_trait)) if distinct_normalized_bounds.insert(normalized_trait) => @@ -1403,14 +1315,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { true } _ => false, - } - }) { - return Some((idx, pred.constness)); - } + }, + ) + })? { + result.push((idx, pred.constness)); } - None - }) - .collect() + } + } + Ok(result) } /// Equates the trait in `obligation` with trait bound. If the two traits @@ -1421,11 +1333,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, trait_bound: ty::PolyTraitRef<'tcx>, placeholder_trait_ref: ty::TraitRef<'tcx>, - ) -> Result>, ()> { + ) -> Result>, ()>, Overflow> { debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); if placeholder_trait_ref.def_id != trait_bound.def_id() { // Avoid unnecessary normalization - return Err(()); + return Ok(Err(())); } let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| { @@ -1436,8 +1348,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, trait_bound, ) - }); - self.infcx + })?; + Ok(self + .infcx .at(&obligation.cause, obligation.param_env) .define_opaque_types(false) .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) @@ -1450,18 +1363,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None } }) - .map_err(|_| ()) + .map_err(|_| ())) } fn where_clause_may_apply<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result { + ) -> EvaluationResult { self.evaluation_probe(|this| { match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations), - Err(()) => Ok(EvaluatedToErr), + Err(()) => EvaluatedToErr, } }) } @@ -1477,7 +1390,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &ProjectionTyObligation<'tcx>, env_predicate: PolyProjectionPredicate<'tcx>, potentially_unnormalized_candidates: bool, - ) -> ProjectionMatchesProjection { + ) -> Result { let mut nested_obligations = Vec::new(); let infer_predicate = self.infcx.replace_bound_vars_with_fresh_vars( obligation.cause.span, @@ -1493,8 +1406,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, infer_predicate.projection_ty, &mut nested_obligations, + false, ) - }) + })? } else { infer_predicate.projection_ty }; @@ -1509,10 +1423,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), nested_obligations.into_iter().chain(obligations), ) - .map_or(false, |res| res.may_apply()) + .may_apply() }); - if is_match { + Ok(if is_match { let generics = self.tcx().generics_of(obligation.predicate.item_def_id); // FIXME(generic-associated-types): Addresses aggressive inference in #92917. // If this type is a GAT, and of the GAT substs resolve to something new, @@ -1529,7 +1443,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } else { ProjectionMatchesProjection::No - } + }) } /////////////////////////////////////////////////////////////////////////// @@ -2050,7 +1964,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth: usize, trait_def_id: DefId, types: ty::Binder<'tcx, Vec>>, - ) -> Vec> { + ) -> Result>, Overflow> { // Because the types were potentially derived from // higher-ranked obligations they may reference late-bound // regions. For example, `for<'a> Foo<&'a i32> : Copy` would @@ -2064,38 +1978,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `for<'a> &'a i32` becomes `&0 i32`. // 2. Produce something like `&'0 i32 : Copy` // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy` + let mut obligations = Vec::new(); + for ty in types.as_ref().skip_binder().iter() { + let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); + let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); + let Normalized { value: normalized_ty, obligations: normalize_obl } = + ensure_sufficient_stack(|| { + project::normalize_with_depth( + self, + param_env, + cause.clone(), + recursion_depth, + placeholder_ty, + ) + })?; + obligations.extend(normalize_obl); + let placeholder_obligation = predicate_for_trait_def( + self.tcx(), + param_env, + cause.clone(), + trait_def_id, + recursion_depth, + normalized_ty, + &[], + ); + obligations.push(placeholder_obligation) + } - types - .as_ref() - .skip_binder() // binder moved -\ - .iter() - .flat_map(|ty| { - let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/ - - let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); - let Normalized { value: normalized_ty, mut obligations } = - ensure_sufficient_stack(|| { - project::normalize_with_depth( - self, - param_env, - cause.clone(), - recursion_depth, - placeholder_ty, - ) - }); - let placeholder_obligation = predicate_for_trait_def( - self.tcx(), - param_env, - cause.clone(), - trait_def_id, - recursion_depth, - normalized_ty, - &[], - ); - obligations.push(placeholder_obligation); - obligations - }) - .collect() + Ok(obligations) } /////////////////////////////////////////////////////////////////////////// @@ -2112,10 +2022,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, impl_def_id: DefId, obligation: &TraitObligation<'tcx>, - ) -> Normalized<'tcx, SubstsRef<'tcx>> { + ) -> Result>, Overflow> { let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap(); - match self.match_impl(impl_def_id, impl_trait_ref, obligation) { - Ok(substs) => substs, + match self.match_impl(impl_def_id, impl_trait_ref, obligation)? { + Ok(substs) => Ok(substs), Err(()) => { self.infcx.tcx.sess.delay_span_bug( obligation.cause.span, @@ -2132,7 +2042,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { lt_op: |l| l, ct_op: |c| c, }); - Normalized { value, obligations: vec![] } + Ok(Normalized { value, obligations: vec![] }) } } } @@ -2143,7 +2053,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id: DefId, impl_trait_ref: EarlyBinder>, obligation: &TraitObligation<'tcx>, - ) -> Result>, ()> { + ) -> Result>, ()>, Overflow> { let placeholder_obligation = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; @@ -2163,7 +2073,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, impl_trait_ref, ) - }); + })?; debug!(?impl_trait_ref, ?placeholder_obligation_trait_ref); @@ -2173,22 +2083,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ObligationCauseCode::MatchImpl(obligation.cause.clone(), impl_def_id), ); - let InferOk { obligations, .. } = self + let InferOk { obligations, .. } = match self .infcx .at(&cause, obligation.param_env) .define_opaque_types(false) .eq(placeholder_obligation_trait_ref, impl_trait_ref) - .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?; + { + Ok(ok) => ok, + Err(e) => { + debug!("match_impl: failed eq_trait_refs due to `{e}`"); + return Ok(Err(())); + } + }; nested_obligations.extend(obligations); if !self.intercrate && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation { debug!("reservation impls only apply in intercrate mode"); - return Err(()); + return Ok(Err(())); } - Ok(Normalized { value: impl_substs, obligations: nested_obligations }) + Ok(Ok(Normalized { value: impl_substs, obligations: nested_obligations })) } fn fast_reject_trait_refs( @@ -2327,7 +2243,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { def_id: DefId, // of impl or trait substs: SubstsRef<'tcx>, // for impl or trait parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, - ) -> Vec> { + ) -> Result>, Overflow> { let tcx = self.tcx(); // To allow for one-pass evaluation of the nested obligation, @@ -2364,11 +2280,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth, predicates.rebind(*predicate).subst(tcx, substs), &mut obligations, - ); + false, + )?; obligations.push(Obligation { cause, recursion_depth, param_env, predicate }); } - obligations + Ok(obligations) } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fc0a9f6900336..298ffee86997c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -3,6 +3,7 @@ use crate::traits; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_infer::traits::Overflow; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeVisitable}; use rustc_span::Span; @@ -21,7 +22,8 @@ pub fn obligations<'tcx>( recursion_depth: usize, arg: GenericArg<'tcx>, span: Span, -) -> Option>> { + fatal_overflow: bool, +) -> Result>>, Overflow> { // Handle the "livelock" case (see comment above) by bailing out if necessary. let arg = match arg.unpack() { GenericArgKind::Type(ty) => { @@ -30,7 +32,7 @@ pub fn obligations<'tcx>( let resolved_ty = infcx.shallow_resolve(ty); if resolved_ty == ty { // No progress, bail out to prevent "livelock". - return None; + return Ok(None); } else { resolved_ty } @@ -45,7 +47,7 @@ pub fn obligations<'tcx>( let resolved = infcx.shallow_resolve(ct); if resolved == ct { // No progress. - return None; + return Ok(None); } else { resolved } @@ -55,7 +57,7 @@ pub fn obligations<'tcx>( .into() } // There is nothing we have to do for lifetimes. - GenericArgKind::Lifetime(..) => return Some(Vec::new()), + GenericArgKind::Lifetime(..) => return Ok(Some(Vec::new())), }; let mut wf = WfPredicates { @@ -66,13 +68,14 @@ pub fn obligations<'tcx>( out: vec![], recursion_depth, item: None, + fatal_overflow, }; wf.compute(arg); debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); - let result = wf.normalize(infcx); + let result = wf.normalize(infcx)?; debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", arg, body_id, result); - Some(result) + Ok(Some(result)) } /// Returns the obligations that make this trait reference @@ -95,10 +98,11 @@ pub fn trait_obligations<'tcx>( out: vec![], recursion_depth: 0, item: Some(item), + fatal_overflow: true, }; wf.compute_trait_pred(trait_pred, Elaborate::All); debug!(obligations = ?wf.out); - wf.normalize(infcx) + wf.normalize(infcx).unwrap() } #[instrument(skip(infcx), ret)] @@ -117,6 +121,7 @@ pub fn predicate_obligations<'tcx>( out: vec![], recursion_depth: 0, item: None, + fatal_overflow: true, }; // It's ok to skip the binder here because wf code is prepared for it @@ -160,7 +165,7 @@ pub fn predicate_obligations<'tcx>( } } - wf.normalize(infcx) + wf.normalize(infcx).unwrap() } struct WfPredicates<'tcx> { @@ -171,6 +176,7 @@ struct WfPredicates<'tcx> { out: Vec>, recursion_depth: usize, item: Option<&'tcx hir::Item<'tcx>>, + fatal_overflow: bool, } /// Controls whether we "elaborate" supertraits and so forth on the WF @@ -272,7 +278,10 @@ impl<'tcx> WfPredicates<'tcx> { traits::ObligationCause::new(self.span, self.body_id, code) } - fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec> { + fn normalize( + self, + infcx: &InferCtxt<'tcx>, + ) -> Result>, Overflow> { let cause = self.cause(traits::WellFormed(None)); let param_env = self.param_env; let mut obligations = Vec::with_capacity(self.out.len()); @@ -289,11 +298,12 @@ impl<'tcx> WfPredicates<'tcx> { self.recursion_depth, obligation.predicate, &mut obligations, - ); + self.fatal_overflow, + )?; obligation.predicate = normalized_predicate; obligations.push(obligation); } - obligations + Ok(obligations) } /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 493d5de0807a2..8c230dde52355 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -4,7 +4,7 @@ use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; use rustc_trait_selection::traits::{ - EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, + EvaluationResult, Obligation, ObligationCause, SelectionContext, }; pub(crate) fn provide(p: &mut Providers) { @@ -14,7 +14,7 @@ pub(crate) fn provide(p: &mut Providers) { fn evaluate_obligation<'tcx>( tcx: TyCtxt<'tcx>, canonical_goal: CanonicalPredicateGoal<'tcx>, -) -> Result { +) -> EvaluationResult { debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); // HACK This bubble is required for this tests to pass: // impl-trait/issue99642.rs @@ -25,7 +25,7 @@ fn evaluate_obligation<'tcx>( debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; - let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); + let mut selcx = SelectionContext::new(&infcx); let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); selcx.evaluate_root_obligation(&obligation) diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 82f6111f6f92e..48beeb9e71cd6 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -7,7 +7,7 @@ use rustc_infer::infer::canonical::{self, Canonical}; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::query::OutlivesBound; -use rustc_infer::traits::TraitEngineExt as _; +use rustc_infer::traits::{Overflow, TraitEngineExt as _}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use rustc_span::source_map::DUMMY_SP; @@ -70,8 +70,10 @@ fn compute_implied_outlives_bounds<'tcx>( // FIXME(@lcnr): It's not really "always fine", having fewer implied // bounds can be backward incompatible, e.g. #101951 was caused by // us not dealing with inference vars in `TypeOutlives` predicates. - let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) - .unwrap_or_default(); + let obligations = + wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP, true) + .unwrap_or_else(|Overflow| bug!("unexpected non-fatal overflow")) + .unwrap_or_default(); // While these predicates should all be implied by other parts of // the program, they are still relevant as they may constrain diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index e805eb4282119..d49aa28be5b6e 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -1,8 +1,10 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::{Obligation, Overflow}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_trait_selection::infer::InferCtxtBuilderExt; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::{ normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution, }; @@ -26,14 +28,20 @@ fn normalize_projection_ty<'tcx>( let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = vec![]; - let answer = traits::normalize_projection_type( + let answer = match traits::normalize_projection_type( selcx, param_env, goal, cause, 0, &mut obligations, - ); + ) { + Ok(value) => value, + Err(Overflow) => ocx.infcx.err_ctxt().report_overflow_error( + &Obligation::new(ObligationCause::dummy(), param_env, goal), + true, + ), + }; ocx.register_obligations(obligations); // FIXME(associated_const_equality): All users of normalize_projection_ty expected // a type, but there is the possibility it could've been a const now. Maybe change diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index d80637055829d..6bb6da63f9608 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -80,11 +80,9 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { param_env, predicate, ); - match infcx.evaluate_obligation(&obligation) { - Ok(eval_result) if eval_result.may_apply() => {} - Err(traits::OverflowError::Canonical) => {} - Err(traits::OverflowError::ErrorReporting) => {} - _ => continue 'blanket_impls, + + if !infcx.evaluate_obligation(&obligation).may_apply() { + continue 'blanket_impls; } } debug!( From b60376fbdf6d92531a4c22caf26f4da44472f48c Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 17 Nov 2022 17:48:49 +0100 Subject: [PATCH 2/5] cool beans --- .../src/traits/select/candidate_assembly.rs | 10 ++++++++-- .../rustc_trait_selection/src/traits/select/mod.rs | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 6521833bcaa47..a827358eb3f40 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -566,8 +566,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } self.infcx.probe(|_| { - if let Ok(_substs) = self.match_impl(impl_def_id, impl_trait_ref, obligation) { - candidates.vec.push(ImplCandidate(impl_def_id)); + match self.match_impl(impl_def_id, impl_trait_ref, obligation) { + Ok(Ok(_substs)) => candidates.vec.push(ImplCandidate(impl_def_id)), + Ok(Err(())) => {} + // Subtle: in case of overflow, we still add the candidate so + // that the overflow is correctly propagated. Otherwise caching + // would incorrectly consider this candidate to never apply, even + // if there's only overflow at a specific depth. + Err(Overflow) => candidates.vec.push(ImplCandidate(impl_def_id)), } }); }, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d3eff38ad9775..439b6c73a8c85 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2030,8 +2030,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx.sess.delay_span_bug( obligation.cause.span, &format!( - "Impl {:?} was matchable against {:?} but now is not", - impl_def_id, obligation + "Impl {:?} ({:?}) was matchable against {:?} but now is not", + impl_def_id, impl_trait_ref, obligation ), ); let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); From 674d3b446c2c6862550e71523543fe4a27c91c98 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 17 Nov 2022 17:53:17 +0100 Subject: [PATCH 3/5] overflow mention root obligation --- compiler/rustc_trait_selection/src/traits/codegen.rs | 2 +- .../rustc_trait_selection/src/traits/error_reporting/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index dc83d997790bc..6485afe52be5f 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -70,7 +70,7 @@ pub fn codegen_select_candidate<'tcx>( for err in errors { match err.code { FulfillmentErrorCode::CodeOverflow => { - infcx.err_ctxt().report_overflow_error(&err.obligation, true) + infcx.err_ctxt().report_overflow_error(&err.root_obligation, true) } FulfillmentErrorCode::CodeCycle(cycle) => { infcx.err_ctxt().report_overflow_error_cycle(&cycle) 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 eddbf72eebcc6..4e9acccdd9d09 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1536,7 +1536,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { FulfillmentErrorCode::CodeOverflow => { let predicate = self.resolve_vars_if_possible(error.obligation.predicate); if !predicate.references_error() { - self.report_overflow_error(&error.obligation, true); + self.report_overflow_error(&error.root_obligation, true); } } } From feae4870eb06a30e5e8ff1a266edb94feac532cc Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 17 Nov 2022 17:55:12 +0100 Subject: [PATCH 4/5] update evaluate tests --- src/test/ui/traits/cache-reached-depth-ice.rs | 2 +- src/test/ui/traits/cache-reached-depth-ice.stderr | 2 +- .../ui/traits/issue-83538-tainted-cache-after-cycle.rs | 8 ++++---- .../traits/issue-83538-tainted-cache-after-cycle.stderr | 8 ++++---- src/test/ui/traits/issue-85360-eval-obligation-ice.rs | 8 ++++---- src/test/ui/traits/issue-85360-eval-obligation-ice.stderr | 8 ++++---- src/test/ui/traits/project-modulo-regions.rs | 4 ++-- .../ui/traits/project-modulo-regions.with_clause.stderr | 2 +- .../traits/project-modulo-regions.without_clause.stderr | 2 +- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/test/ui/traits/cache-reached-depth-ice.rs b/src/test/ui/traits/cache-reached-depth-ice.rs index c36ac08579b77..f24d3e1b145bb 100644 --- a/src/test/ui/traits/cache-reached-depth-ice.rs +++ b/src/test/ui/traits/cache-reached-depth-ice.rs @@ -41,5 +41,5 @@ fn test() {} fn main() { test::(); - //~^ ERROR evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOk) + //~^ ERROR evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = EvaluatedToOk } diff --git a/src/test/ui/traits/cache-reached-depth-ice.stderr b/src/test/ui/traits/cache-reached-depth-ice.stderr index 082aa0f5cd93e..8444083d52b38 100644 --- a/src/test/ui/traits/cache-reached-depth-ice.stderr +++ b/src/test/ui/traits/cache-reached-depth-ice.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = EvaluatedToOk --> $DIR/cache-reached-depth-ice.rs:43:5 | LL | fn test() {} diff --git a/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs b/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs index 3cd68ff6f060e..8f77fcb3207b0 100644 --- a/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs +++ b/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs @@ -57,10 +57,10 @@ fn main() { // Key is that Vec is "ok" and Third<'_, Ty> is "ok modulo regions": forward(); - //~^ ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) + //~^ ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = EvaluatedToOk + //~| ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = EvaluatedToOkModuloRegions reverse(); - //~^ ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) + //~^ ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = EvaluatedToOk + //~| ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = EvaluatedToOkModuloRegions } diff --git a/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr b/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr index 7c4041144a4d2..f79e5186da98a 100644 --- a/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr +++ b/src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = EvaluatedToOk --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5 | LL | Vec: Unpin, @@ -7,7 +7,7 @@ LL | Vec: Unpin, LL | forward(); | ^^^^^^^ -error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = EvaluatedToOkModuloRegions --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5 | LL | Third<'a, Ty>: Unpin, @@ -16,7 +16,7 @@ LL | Third<'a, Ty>: Unpin, LL | forward(); | ^^^^^^^ -error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = EvaluatedToOkModuloRegions --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5 | LL | Third<'a, Ty>: Unpin, @@ -25,7 +25,7 @@ LL | Third<'a, Ty>: Unpin, LL | reverse(); | ^^^^^^^ -error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = EvaluatedToOk --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5 | LL | Vec: Unpin, diff --git a/src/test/ui/traits/issue-85360-eval-obligation-ice.rs b/src/test/ui/traits/issue-85360-eval-obligation-ice.rs index 19131684a481b..324d6d2894d64 100644 --- a/src/test/ui/traits/issue-85360-eval-obligation-ice.rs +++ b/src/test/ui/traits/issue-85360-eval-obligation-ice.rs @@ -7,12 +7,12 @@ use core::marker::PhantomData; fn main() { test::>>(make()); - //~^ ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) + //~^ ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = EvaluatedToOk + //~| ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = EvaluatedToOk test::>>(make()); - //~^ ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) - //~| ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) + //~^ ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = EvaluatedToOkModuloRegions + //~| ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = EvaluatedToOkModuloRegions } #[rustc_evaluate_where_clauses] diff --git a/src/test/ui/traits/issue-85360-eval-obligation-ice.stderr b/src/test/ui/traits/issue-85360-eval-obligation-ice.stderr index ebf977dd68051..cda01749f7dfe 100644 --- a/src/test/ui/traits/issue-85360-eval-obligation-ice.stderr +++ b/src/test/ui/traits/issue-85360-eval-obligation-ice.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = EvaluatedToOk --> $DIR/issue-85360-eval-obligation-ice.rs:9:5 | LL | test::>>(make()); @@ -7,7 +7,7 @@ LL | test::>>(make()); LL | fn test(_: T) {} | - predicate -error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = EvaluatedToOk --> $DIR/issue-85360-eval-obligation-ice.rs:9:5 | LL | test::>>(make()); @@ -16,7 +16,7 @@ LL | test::>>(make()); LL | fn test(_: T) {} | ----- predicate -error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = EvaluatedToOkModuloRegions --> $DIR/issue-85360-eval-obligation-ice.rs:13:5 | LL | test::>>(make()); @@ -25,7 +25,7 @@ LL | test::>>(make()); LL | fn test(_: T) {} | - predicate -error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = EvaluatedToOkModuloRegions --> $DIR/issue-85360-eval-obligation-ice.rs:13:5 | LL | test::>>(make()); diff --git a/src/test/ui/traits/project-modulo-regions.rs b/src/test/ui/traits/project-modulo-regions.rs index f0c0dd3ed9578..752c860ed5b22 100644 --- a/src/test/ui/traits/project-modulo-regions.rs +++ b/src/test/ui/traits/project-modulo-regions.rs @@ -48,8 +48,8 @@ fn test(val: MyStruct) where Helper: HelperTrait { fn foo(val: MyStruct) { test(val); - //[with_clause]~^ ERROR evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) - //[without_clause]~^^ ERROR evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOk) + //[with_clause]~^ ERROR evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = EvaluatedToOkModuloRegions + //[without_clause]~^^ ERROR evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = EvaluatedToOk } fn main() {} diff --git a/src/test/ui/traits/project-modulo-regions.with_clause.stderr b/src/test/ui/traits/project-modulo-regions.with_clause.stderr index 2434c32c81882..76b2d2b8f6256 100644 --- a/src/test/ui/traits/project-modulo-regions.with_clause.stderr +++ b/src/test/ui/traits/project-modulo-regions.with_clause.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = EvaluatedToOkModuloRegions --> $DIR/project-modulo-regions.rs:50:5 | LL | fn test(val: MyStruct) where Helper: HelperTrait { diff --git a/src/test/ui/traits/project-modulo-regions.without_clause.stderr b/src/test/ui/traits/project-modulo-regions.without_clause.stderr index 9d35690d5f0fe..389610e946703 100644 --- a/src/test/ui/traits/project-modulo-regions.without_clause.stderr +++ b/src/test/ui/traits/project-modulo-regions.without_clause.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = EvaluatedToOk --> $DIR/project-modulo-regions.rs:50:5 | LL | fn test(val: MyStruct) where Helper: HelperTrait { From e4a787b47f85b935685613585e97c8ebdc5676cd Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 18 Nov 2022 13:20:13 +0100 Subject: [PATCH 5/5] slow and steady? --- src/test/ui/recursion/issue-83150.rs | 2 +- src/test/ui/recursion/issue-83150.stderr | 17 +++++++++++------ .../ui/traits/issue-91949-hangs-on-recursion.rs | 5 ++--- .../issue-91949-hangs-on-recursion.stderr | 12 +++++++----- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/test/ui/recursion/issue-83150.rs b/src/test/ui/recursion/issue-83150.rs index e647f0ff4fb8b..487c9768f6f10 100644 --- a/src/test/ui/recursion/issue-83150.rs +++ b/src/test/ui/recursion/issue-83150.rs @@ -1,6 +1,5 @@ // build-fail // compile-flags: -Copt-level=0 -//~^^ ERROR overflow evaluating the requirement fn main() { let mut iter = 0u8..1; @@ -9,4 +8,5 @@ fn main() { fn func>(iter: &mut T) { //~ WARN function cannot return without recursing func(&mut iter.map(|x| x + 1)) + //~^ ERROR reached the recursion limit while instantiating `func::>` } diff --git a/src/test/ui/recursion/issue-83150.stderr b/src/test/ui/recursion/issue-83150.stderr index 59fba5af00e12..1b39f88aa5458 100644 --- a/src/test/ui/recursion/issue-83150.stderr +++ b/src/test/ui/recursion/issue-83150.stderr @@ -9,13 +9,18 @@ LL | func(&mut iter.map(|x| x + 1)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0275]: overflow evaluating the requirement ` as Iterator>::Item` +error: reached the recursion limit while instantiating `func::>` + --> $DIR/issue-83150.rs:11:5 | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) - = note: required for `Map<&mut std::ops::Range, [closure@$DIR/issue-83150.rs:11:24: 11:27]>` to implement `Iterator` - = note: 64 redundant requirements hidden - = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>` to implement `Iterator` +LL | func(&mut iter.map(|x| x + 1)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: `func` defined here + --> $DIR/issue-83150.rs:10:1 + | +LL | fn func>(iter: &mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type.txt' error: aborting due to previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/traits/issue-91949-hangs-on-recursion.rs b/src/test/ui/traits/issue-91949-hangs-on-recursion.rs index 499a64f281699..da09d6662e422 100644 --- a/src/test/ui/traits/issue-91949-hangs-on-recursion.rs +++ b/src/test/ui/traits/issue-91949-hangs-on-recursion.rs @@ -1,7 +1,6 @@ // build-fail // compile-flags: -Zinline-mir=no -// error-pattern: overflow evaluating the requirement `(): Sized` -// error-pattern: function cannot return without recursing +//~^^ ERROR overflow evaluating the requirement // Regression test for #91949. // This hanged *forever* on 1.56, fixed by #90423. @@ -19,7 +18,7 @@ impl> Iterator for IteratorOfWrapped { } } -fn recurse(elements: T) -> Vec +fn recurse(elements: T) -> Vec //~ WARN function cannot return without recursing where T: Iterator, { diff --git a/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr b/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr index 61b6d4b08bb6a..405afb336cf62 100644 --- a/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr +++ b/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/issue-91949-hangs-on-recursion.rs:22:1 + --> $DIR/issue-91949-hangs-on-recursion.rs:21:1 | LL | / fn recurse(elements: T) -> Vec LL | | where @@ -12,12 +12,14 @@ LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0275]: overflow evaluating the requirement `(): Sized` +error[E0275]: overflow evaluating the requirement `>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]> as Iterator>::Item == ()` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`) - = note: required for `std::iter::Empty<()>` to implement `Iterator` - = note: 171 redundant requirements hidden - = note: required for `IteratorOfWrapped<(), Map>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>` to implement `Iterator` +note: required for `IteratorOfWrapped<(), Map>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:48]>>` to implement `Iterator` + --> $DIR/issue-91949-hangs-on-recursion.rs:14:32 + | +LL | impl> Iterator for IteratorOfWrapped { + | ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted