From c0c373f3affa9ff3d8a6ab2e6124efd3c03d3516 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 15 Mar 2024 10:06:23 +0000 Subject: [PATCH 1/3] Prepare normalization to be fallible wrt overflow --- .../src/traits/normalize.rs | 71 +++++++++++++++---- .../src/traits/project.rs | 57 ++++++++++----- .../src/traits/select/candidate_assembly.rs | 1 + .../src/traits/select/mod.rs | 53 ++++++++------ .../src/normalize_projection_ty.rs | 3 +- .../hr-associated-type-bound-2.rs | 3 +- .../hr-associated-type-bound-2.stderr | 5 +- .../ui/methods/inherent-bound-in-probe.stderr | 4 +- 8 files changed, 141 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 15bfffef3cede..fa1d3c3badf3a 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -1,4 +1,6 @@ //! Deeply normalize types using the old trait solver. +use crate::traits::project::ProjectionNormalizationFailure; + use super::error_reporting::OverflowCause; use super::error_reporting::TypeErrCtxtExt; use super::SelectionContext; @@ -6,6 +8,7 @@ use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, Placeh use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::InferOk; +use rustc_infer::traits::OverflowError; use rustc_infer::traits::PredicateObligation; use rustc_infer::traits::{FulfillmentError, Normalized, Obligation, TraitEngine}; use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; @@ -97,6 +100,27 @@ where result } +#[instrument(level = "info", skip(selcx, param_env, cause, obligations))] +pub(crate) fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + value: T, + obligations: &mut Vec>, +) -> Result +where + T: TypeFoldable>, +{ + debug!(obligations.len = obligations.len()); + let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); + let result = ensure_sufficient_stack(|| normalizer.fold(value)); + debug!(?result, obligations.len = normalizer.obligations.len()); + debug!(?normalizer.obligations,); + normalizer.overflowed?; + Ok(result) +} + pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( value: &T, reveal: Reveal, @@ -121,6 +145,11 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> { obligations: &'a mut Vec>, depth: usize, universes: Vec>, + /// Signals that there was an overflow during normalization somewhere. + /// We use this side channel instead of a `FallibleTypeFolder`, because + /// most code expects to get their value back on error, and we'd have to + /// clone the original value before normalization to achieve this. + overflowed: Result<(), OverflowError>, } impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { @@ -132,7 +161,15 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { obligations: &'a mut Vec>, ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { debug_assert!(!selcx.infcx.next_trait_solver()); - AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] } + AssocTypeNormalizer { + selcx, + param_env, + cause, + obligations, + depth, + universes: vec![], + overflowed: Ok(()), + } } fn fold>>(&mut self, value: T) -> T { @@ -243,6 +280,13 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx self.depth, self.obligations, ); + let normalized_ty = match normalized_ty { + Ok(term) => term.ty().unwrap(), + Err(oflo) => { + self.overflowed = Err(oflo); + return ty; + } + }; debug!( ?self.depth, ?ty, @@ -250,7 +294,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx obligations.len = ?self.obligations.len(), "AssocTypeNormalizer: normalized type" ); - normalized_ty.ty().unwrap() + normalized_ty } ty::Projection => { @@ -277,21 +321,24 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx self.cause.clone(), self.depth, self.obligations, - ) - .ok() - .flatten() - .map(|term| term.ty().unwrap()) - .map(|normalized_ty| { - PlaceholderReplacer::replace_placeholders( + ); + let normalized_ty = match normalized_ty { + Ok(Some(term)) => PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, mapped_types, mapped_consts, &self.universes, - normalized_ty, - ) - }) - .unwrap_or_else(|| ty.super_fold_with(self)); + term.ty().unwrap(), + ), + Ok(None) | Err(ProjectionNormalizationFailure::InProgress) => { + ty.super_fold_with(self) + } + Err(ProjectionNormalizationFailure::Overflow(oflo)) => { + self.overflowed = Err(oflo); + return ty; + } + }; debug!( ?self.depth, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6756b5dec2318..30ba6cde267ee 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -46,7 +46,14 @@ pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<' pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>; -pub(super) struct InProgress; +/// Signals the various ways in which we can fail to normalize a projection +#[derive(Debug)] +pub enum ProjectionNormalizationFailure { + /// Blocked on inference variables resolving + InProgress, + /// Fatal failure, overflow occurred. + Overflow(OverflowError), +} /// When attempting to resolve `::Name` ... #[derive(Debug)] @@ -252,7 +259,10 @@ fn project_and_unify_type<'cx, 'tcx>( ) { Ok(Some(n)) => n, Ok(None) => return ProjectAndUnifyResult::FailedNormalization, - Err(InProgress) => return ProjectAndUnifyResult::Recursive, + Err( + ProjectionNormalizationFailure::InProgress + | ProjectionNormalizationFailure::Overflow(_), + ) => return ProjectAndUnifyResult::Recursive, }; debug!(?normalized, ?obligations, "project_and_unify_type result"); let actual = obligation.predicate.term; @@ -298,24 +308,29 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec>, -) -> Term<'tcx> { - opt_normalize_projection_type( +) -> Result, OverflowError> { + let normalized = 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.infcx.infer_projection(param_env, projection_ty, cause, depth + 1, obligations).into() - }) + ); + match normalized { + Ok(Some(term)) => Ok(term), + Ok(None) | Err(ProjectionNormalizationFailure::InProgress) => { + // if we bottom out in ambiguity, create a type variable + // and a deferred predicate to resolve this when more type + // information is available. + + Ok(selcx + .infcx + .infer_projection(param_env, projection_ty, cause, depth + 1, obligations) + .into()) + } + Err(ProjectionNormalizationFailure::Overflow(oflo)) => Err(oflo), + } } /// The guts of `normalize`: normalize a specific projection like `( /// often immediately appended to another obligations vector. So now this /// function takes an obligations vector and appends to it directly, which is /// slightly uglier but avoids the need for an extra short-lived allocation. -#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] +#[instrument(level = "debug", skip(selcx, param_env, cause, obligations), ret)] pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -336,7 +351,7 @@ pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>( cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec>, -) -> Result>, InProgress> { +) -> Result>, ProjectionNormalizationFailure> { let infcx = selcx.infcx; debug_assert!(!selcx.infcx.next_trait_solver()); // Don't use the projection cache in intercrate mode - @@ -387,11 +402,11 @@ pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>( if use_cache { infcx.inner.borrow_mut().projection_cache().recur(cache_key); } - return Err(InProgress); + return Err(ProjectionNormalizationFailure::InProgress); } Err(ProjectionCacheEntry::Recur) => { debug!("recur cache"); - return Err(InProgress); + return Err(ProjectionNormalizationFailure::InProgress); } Err(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => { // This is the hottest path in this function. @@ -471,6 +486,12 @@ pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>( } Ok(None) } + Err(ProjectionError::TraitSelectionError(SelectionError::Overflow(oflo))) => { + if use_cache { + infcx.inner.borrow_mut().projection_cache().error(cache_key); + } + Err(ProjectionNormalizationFailure::Overflow(oflo)) + } Err(ProjectionError::TraitSelectionError(_)) => { debug!("opt_normalize_projection_type: ERROR"); // if we got an error processing the `T as Trait` part, 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 49091e53be713..a94abd4f49cdd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -925,6 +925,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // since we don't actually use them. &mut vec![], ) + .ok()? .ty() .unwrap(); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d10fe6a949013..55048000f8291 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -23,6 +23,7 @@ use crate::solve::InferCtxtSelectExt; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::normalize_with_depth; use crate::traits::normalize::normalize_with_depth_to; +use crate::traits::normalize::try_normalize_with_depth_to; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; @@ -41,11 +42,13 @@ use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::_match::MatchAgainstFreshVars; use rustc_middle::ty::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, PolyProjectionPredicate, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::symbol::sym; +use rustc_span::ErrorGuaranteed; use rustc_span::Symbol; use std::cell::{Cell, RefCell}; @@ -2083,6 +2086,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } +#[derive(Debug)] +enum MatchImplFailure<'tcx> { + ReservationImpl, + #[allow(dead_code)] + TypeError(TypeError<'tcx>), + #[allow(dead_code)] + Overflow(OverflowError), + Error(ErrorGuaranteed), +} + impl<'tcx> SelectionContext<'_, 'tcx> { fn sized_conditions( &mut self, @@ -2435,9 +2448,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let impl_trait_header = self.tcx().impl_trait_header(impl_def_id).unwrap(); match self.match_impl(impl_def_id, impl_trait_header, obligation) { Ok(args) => args, - Err(()) => { + Err(err) => { let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); - bug!("impl {impl_def_id:?} was matchable against {predicate:?} but now is not") + bug!( + "impl {impl_def_id:?} was matchable against {predicate:?} but now is not: {err:?}" + ) } } } @@ -2448,7 +2463,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { impl_def_id: DefId, impl_trait_header: ty::ImplTraitHeader<'tcx>, obligation: &PolyTraitObligation<'tcx>, - ) -> Result>, ()> { + ) -> Result>, MatchImplFailure<'tcx>> { let placeholder_obligation = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; @@ -2456,22 +2471,22 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let impl_args = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id); let trait_ref = impl_trait_header.trait_ref.instantiate(self.tcx(), impl_args); - if trait_ref.references_error() { - return Err(()); - } + trait_ref.error_reported().map_err(MatchImplFailure::Error)?; debug!(?impl_trait_header); - let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = - ensure_sufficient_stack(|| { - normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - trait_ref, - ) - }); + let mut nested_obligations = vec![]; + let impl_trait_ref = ensure_sufficient_stack(|| { + try_normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_ref, + &mut nested_obligations, + ) + }) + .map_err(MatchImplFailure::Overflow)?; debug!(?impl_trait_ref, ?placeholder_obligation_trait_ref); @@ -2485,14 +2500,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> { .infcx .at(&cause, obligation.param_env) .eq(DefineOpaqueTypes::No, placeholder_obligation_trait_ref, impl_trait_ref) - .map_err(|e| { - debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx())) - })?; + .map_err(MatchImplFailure::TypeError)?; nested_obligations.extend(obligations); if !self.is_intercrate() && impl_trait_header.polarity == ty::ImplPolarity::Reservation { debug!("reservation impls only apply in intercrate mode"); - return Err(()); + return Err(MatchImplFailure::ReservationImpl); } Ok(Normalized { value: impl_args, obligations: nested_obligations }) diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 92a19fb91198c..0da330573dba0 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -40,7 +40,8 @@ fn normalize_canonicalized_projection_ty<'tcx>( cause, 0, &mut obligations, - ); + ) + .map_err(|_| NoSolution)?; ocx.register_obligations(obligations); // #112047: With projections and opaques, we are able to create opaques that // are recursive (given some generic parameters of the opaque's type variables). diff --git a/tests/ui/associated-types/hr-associated-type-bound-2.rs b/tests/ui/associated-types/hr-associated-type-bound-2.rs index a89f61a81a57c..c64733cdaeb4f 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-2.rs +++ b/tests/ui/associated-types/hr-associated-type-bound-2.rs @@ -8,7 +8,8 @@ where } } -impl X<'_> for u32 //~ overflow evaluating the requirement `for<'b> u32: X<'b>` +impl X<'_> for u32 +//~^ ERROR: overflow evaluating the requirement `for<'b> >::U: Clone` where for<'b> >::U: Clone, { diff --git a/tests/ui/associated-types/hr-associated-type-bound-2.stderr b/tests/ui/associated-types/hr-associated-type-bound-2.stderr index 2a7d75ef29bef..44ef7abbb6e71 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-2.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-2.stderr @@ -1,7 +1,8 @@ -error[E0275]: overflow evaluating the requirement `for<'b> u32: X<'b>` +error[E0275]: overflow evaluating the requirement `for<'b> >::U: Clone` --> $DIR/hr-associated-type-bound-2.rs:11:1 | LL | / impl X<'_> for u32 +LL | | LL | | where LL | | for<'b> >::U: Clone, | |______________________________________^ @@ -12,7 +13,7 @@ note: required for `u32` to implement `for<'b> X<'b>` | LL | impl X<'_> for u32 | ^^^^^ ^^^ -LL | where +... LL | for<'b> >::U: Clone, | ----- unsatisfied trait bound introduced here = note: 128 redundant requirements hidden diff --git a/tests/ui/methods/inherent-bound-in-probe.stderr b/tests/ui/methods/inherent-bound-in-probe.stderr index 8d7cc462280d6..1001f419c7628 100644 --- a/tests/ui/methods/inherent-bound-in-probe.stderr +++ b/tests/ui/methods/inherent-bound-in-probe.stderr @@ -26,10 +26,10 @@ LL | &'a T: IntoIterator, = note: 126 redundant requirements hidden = note: required for `&BitReaderWrapper>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` to implement `IntoIterator` note: required by a bound in `Helper<'a, T>` - --> $DIR/inherent-bound-in-probe.rs:25:25 + --> $DIR/inherent-bound-in-probe.rs:25:12 | LL | &'a T: IntoIterator, - | ^^^^^^^^^^^^^ required by this bound in `Helper<'a, T>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Helper<'a, T>` error: aborting due to 2 previous errors From aaeb05d864a780096ebca480084540fca3698c13 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 15 Mar 2024 11:20:59 +0000 Subject: [PATCH 2/3] Gracefully handle overflow errors in impl rematching --- .../src/traits/select/confirmation.rs | 13 ++++---- .../src/traits/select/mod.rs | 30 ++++++++++++++--- tests/ui/wf/impl-unconstrained-lifetime.rs | 15 +++++++++ .../ui/wf/impl-unconstrained-lifetime.stderr | 32 +++++++++++++++++++ 4 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 tests/ui/wf/impl-unconstrained-lifetime.rs create mode 100644 tests/ui/wf/impl-unconstrained-lifetime.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 51fc223a5d1b3..5eb7875f1e410 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_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::HigherRankedType; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; +use rustc_infer::traits::OverflowError; use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; use rustc_middle::ty::{ self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate, @@ -63,7 +64,7 @@ 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 => { @@ -441,14 +442,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, impl_def_id: DefId, - ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { + ) -> Result>, OverflowError> { debug!(?obligation, ?impl_def_id, "confirm_impl_candidate"); // First, create the generic parameters by matching the impl again, // this time not in a probe. - let args = self.rematch_impl(impl_def_id, obligation); + let args = self.rematch_impl(impl_def_id, obligation)?; debug!(?args, "impl args"); - ensure_sufficient_stack(|| { + Ok(ensure_sufficient_stack(|| { self.vtable_impl( impl_def_id, args, @@ -457,7 +458,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.predicate, ) - }) + })) } fn vtable_impl( @@ -1370,7 +1371,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_pred.trait_ref.def_id = drop_trait; trait_pred }); - let args = self.rematch_impl(impl_def_id, &new_obligation); + let args = self.rematch_impl(impl_def_id, &new_obligation)?; debug!(?args, "impl args"); let cause = obligation.derived_cause(|derived| { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 55048000f8291..6ae68ac25f7d1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -7,6 +7,7 @@ use self::SelectionCandidate::*; use super::coherence::{self, Conflict}; use super::const_evaluatable; +use super::error_reporting::OverflowCause; use super::project; use super::project::ProjectionTyObligation; use super::util; @@ -499,7 +500,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) } Ok(_) => Ok(None), - Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)), + Err(OverflowError::Canonical) => { + // In standard mode, overflow must have been caught and reported + // earlier. + assert!(self.query_mode == TraitQueryMode::Canonical); + Err(Overflow(OverflowError::Canonical)) + } Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))), }) .flat_map(Result::transpose) @@ -1235,7 +1241,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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(Overflow(OverflowError::Canonical)) => { + // In standard mode, overflow must have been caught and reported + // earlier. + assert!(self.query_mode == TraitQueryMode::Canonical); + Err(OverflowError::Canonical) + } Err(..) => Ok(EvaluatedToErr), } } @@ -2444,10 +2455,21 @@ impl<'tcx> SelectionContext<'_, 'tcx> { &mut self, impl_def_id: DefId, obligation: &PolyTraitObligation<'tcx>, - ) -> Normalized<'tcx, GenericArgsRef<'tcx>> { + ) -> Result>, OverflowError> { let impl_trait_header = self.tcx().impl_trait_header(impl_def_id).unwrap(); match self.match_impl(impl_def_id, impl_trait_header, obligation) { - Ok(args) => args, + Ok(args) => Ok(args), + Err(MatchImplFailure::Overflow(OverflowError::Canonical)) => Err(OverflowError::Error( + self.infcx + .err_ctxt() + .build_overflow_error( + OverflowCause::TraitSolver(obligation.predicate.to_predicate(self.tcx())), + obligation.cause.span, + true, + ) + .emit(), + )), + Err(MatchImplFailure::Overflow(oflo @ OverflowError::Error(_))) => Err(oflo), Err(err) => { let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); bug!( diff --git a/tests/ui/wf/impl-unconstrained-lifetime.rs b/tests/ui/wf/impl-unconstrained-lifetime.rs new file mode 100644 index 0000000000000..611a668b148b7 --- /dev/null +++ b/tests/ui/wf/impl-unconstrained-lifetime.rs @@ -0,0 +1,15 @@ +//@compile-flags: -Z deduplicate-diagnostics=yes +//~^ ERROR overflow + +pub trait Archive { + type Archived; +} + +impl<'a> Archive for <&'a [u8] as Archive>::Archived { + //~^ ERROR overflow + //~| ERROR `&'a [u8]: Archive` is not satisfied + //~| ERROR `&'a [u8]: Archive` is not satisfied + type Archived = (); +} + +fn main() {} diff --git a/tests/ui/wf/impl-unconstrained-lifetime.stderr b/tests/ui/wf/impl-unconstrained-lifetime.stderr new file mode 100644 index 0000000000000..a3f5ad7d32fa0 --- /dev/null +++ b/tests/ui/wf/impl-unconstrained-lifetime.stderr @@ -0,0 +1,32 @@ +error[E0275]: overflow evaluating the requirement `&[u8]: Archive` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`impl_unconstrained_lifetime`) + +error[E0275]: overflow evaluating the requirement `&[u8]: Archive` + --> $DIR/impl-unconstrained-lifetime.rs:8:10 + | +LL | impl<'a> Archive for <&'a [u8] as Archive>::Archived { + | ^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`impl_unconstrained_lifetime`) + +error[E0277]: the trait bound `&'a [u8]: Archive` is not satisfied + --> $DIR/impl-unconstrained-lifetime.rs:8:10 + | +LL | impl<'a> Archive for <&'a [u8] as Archive>::Archived { + | ^^^^^^^ the trait `Archive` is not implemented for `&'a [u8]` + | + = help: the trait `Archive` is implemented for `<&'a [u8] as Archive>::Archived` + +error[E0277]: the trait bound `&'a [u8]: Archive` is not satisfied + --> $DIR/impl-unconstrained-lifetime.rs:8:22 + | +LL | impl<'a> Archive for <&'a [u8] as Archive>::Archived { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Archive` is not implemented for `&'a [u8]` + | + = help: the trait `Archive` is implemented for `<&'a [u8] as Archive>::Archived` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0275, E0277. +For more information about an error, try `rustc --explain E0275`. From 980d0bea5cee58ede87063e6e10a3d41e698b1cc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 15 Mar 2024 15:01:30 +0000 Subject: [PATCH 3/3] Simplify `>::from` --- compiler/rustc_middle/src/traits/select.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 8e9751f45294c..a45a0f6a9de53 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -324,9 +324,6 @@ TrivialTypeTraversalImpls! { 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), - } + SelectionError::Overflow(overflow_error) } }