From 596d6c4b3b5e86e024cd02f7221749ee6958bec6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Jul 2020 21:59:43 +0100 Subject: [PATCH] Avoid cycle with projections from object types Normalizing ` as Iterator>::Item` no longer requires selecting `dyn Iterator: Iterator`. This was previously worked around by using a special type-folder to normalize things. --- .../src/traits/project.rs | 207 +++++++----------- .../src/traits/select/confirmation.rs | 176 ++++----------- .../src/traits/select/mod.rs | 4 +- src/test/ui/regions/regions-enum-not-wf.rs | 23 +- .../ui/regions/regions-enum-not-wf.stderr | 24 +- .../regions-normalize-in-where-clause-list.rs | 17 +- ...ions-normalize-in-where-clause-list.stderr | 24 +- .../regions-enum-not-wf.rs | 23 +- .../regions-enum-not-wf.stderr | 24 +- src/test/ui/traits/cycle-cache-err-60010.rs | 3 +- .../ui/traits/cycle-cache-err-60010.stderr | 18 +- 11 files changed, 193 insertions(+), 350 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index d52e54191006..71a4623cd629 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1,6 +1,5 @@ //! Code for projecting associated types out of trait references. -use super::elaborate_predicates; use super::specialization_graph; use super::translate_substs; use super::util; @@ -53,13 +52,16 @@ pub enum ProjectionTyError<'tcx> { #[derive(PartialEq, Eq, Debug)] enum ProjectionTyCandidate<'tcx> { - // from a where-clause in the env or object type + /// From a where-clause in the env or object type ParamEnv(ty::PolyProjectionPredicate<'tcx>), - // from the definition of `Trait` when you have something like <::B as Trait2>::C + /// From the definition of `Trait` when you have something like <::B as Trait2>::C TraitDef(ty::PolyProjectionPredicate<'tcx>), - // from a "impl" (or a "pseudo-impl" returned by select) + /// Bounds specified on an object type + Object(ty::PolyProjectionPredicate<'tcx>), + + /// From a "impl" (or a "pseudo-impl" returned by select) Select(Selection<'tcx>), } @@ -561,14 +563,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( } else { obligations.extend(ty.obligations); } - - obligations.push(get_paranoid_cache_value_obligation( - infcx, - param_env, - projection_ty, - cause, - depth, - )); return Ok(Some(ty.value)); } Err(ProjectionCacheEntry::Error) => { @@ -703,45 +697,6 @@ fn prune_cache_value_obligations<'a, 'tcx>( NormalizedTy { value: result.value, obligations } } -/// Whenever we give back a cache result for a projection like `::Item ==> X`, we *always* include the obligation to prove -/// that `T: Trait` (we may also include some other obligations). This -/// may or may not be necessary -- in principle, all the obligations -/// that must be proven to show that `T: Trait` were also returned -/// when the cache was first populated. But there are some vague concerns, -/// and so we take the precautionary measure of including `T: Trait` in -/// the result: -/// -/// Concern #1. The current setup is fragile. Perhaps someone could -/// have failed to prove the concerns from when the cache was -/// populated, but also not have used a snapshot, in which case the -/// cache could remain populated even though `T: Trait` has not been -/// shown. In this case, the "other code" is at fault -- when you -/// project something, you are supposed to either have a snapshot or -/// else prove all the resulting obligations -- but it's still easy to -/// get wrong. -/// -/// Concern #2. Even within the snapshot, if those original -/// obligations are not yet proven, then we are able to do projections -/// that may yet turn out to be wrong. This *may* lead to some sort -/// of trouble, though we don't have a concrete example of how that -/// can occur yet. But it seems risky at best. -fn get_paranoid_cache_value_obligation<'a, 'tcx>( - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, -) -> PredicateObligation<'tcx> { - let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); - Obligation { - cause, - recursion_depth: depth, - param_env, - predicate: trait_ref.without_const().to_predicate(infcx.tcx), - } -} - /// If we are projecting `::Item`, but `T: Trait` does not /// hold. In various error cases, we cannot generate a valid /// normalized projection. Therefore, we create an inference variable @@ -848,12 +803,21 @@ fn project_type<'cx, 'tcx>( assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates); - assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates); + assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates); + + if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates { + // Avoid normalization cycle from selection (see + // `assemble_candidates_from_object_ty`). + // FIXME(lazy_normalization): Lazy normalization should save us from + // having to do special case this. + } else { + assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates); + }; match candidates { - ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress( - confirm_candidate(selcx, obligation, &obligation_trait_ref, candidate), - )), + ProjectionTyCandidateSet::Single(candidate) => { + Ok(ProjectedTy::Progress(confirm_candidate(selcx, obligation, candidate))) + } ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress( selcx .tcx() @@ -932,6 +896,53 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( ) } +/// In the case of a trait object like +/// ` as Iterator>::Item` we can use the existential +/// predicate in the trait object. +/// +/// We don't go through the select candidate for these bounds to avoid cycles: +/// In the above case, `dyn Iterator: Iterator` would create a +/// nested obligation of ` as Iterator>::Item: Sized`, +/// this then has to be normalized without having to prove +/// `dyn Iterator: Iterator` again. +fn assemble_candidates_from_object_ty<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>, +) { + debug!("assemble_candidates_from_object_ty(..)"); + + let tcx = selcx.tcx(); + + let self_ty = obligation_trait_ref.self_ty(); + let object_ty = selcx.infcx().shallow_resolve(self_ty); + let data = match object_ty.kind { + ty::Dynamic(ref data, ..) => data, + ty::Infer(ty::TyVar(_)) => { + // 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, + }; + let env_predicates = data + .projection_bounds() + .filter(|bound| bound.item_def_id() == obligation.predicate.item_def_id) + .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx)); + + assemble_candidates_from_predicates( + selcx, + obligation, + obligation_trait_ref, + candidate_set, + ProjectionTyCandidate::Object, + env_predicates, + false, + ); +} + fn assemble_candidates_from_predicates<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, @@ -1000,7 +1011,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( super::ImplSource::Closure(_) | super::ImplSource::Generator(_) | super::ImplSource::FnPointer(_) - | super::ImplSource::Object(_) | super::ImplSource::TraitAlias(_) => { debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source); true @@ -1125,6 +1135,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // in `assemble_candidates_from_param_env`. false } + super::ImplSource::Object(_) => { + // Handled by the `Object` projection candidate. See + // `assemble_candidates_from_object_ty` for an explanation of + // why we special case object types. + false + } super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => { // These traits have no associated types. selcx.tcx().sess.delay_span_bug( @@ -1150,13 +1166,13 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( fn confirm_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate: ProjectionTyCandidate<'tcx>, ) -> Progress<'tcx> { debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation); let mut progress = match candidate { - ProjectionTyCandidate::ParamEnv(poly_projection) => { + ProjectionTyCandidate::ParamEnv(poly_projection) + | ProjectionTyCandidate::Object(poly_projection) => { confirm_param_env_candidate(selcx, obligation, poly_projection, false) } @@ -1165,7 +1181,7 @@ fn confirm_candidate<'cx, 'tcx>( } ProjectionTyCandidate::Select(impl_source) => { - confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source) + confirm_select_candidate(selcx, obligation, impl_source) } }; // When checking for cycle during evaluation, we compare predicates with @@ -1182,7 +1198,6 @@ fn confirm_candidate<'cx, 'tcx>( fn confirm_select_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, impl_source: Selection<'tcx>, ) -> Progress<'tcx> { match impl_source { @@ -1193,10 +1208,8 @@ fn confirm_select_candidate<'cx, 'tcx>( super::ImplSource::DiscriminantKind(data) => { confirm_discriminant_kind_candidate(selcx, obligation, data) } - super::ImplSource::Object(_) => { - confirm_object_candidate(selcx, obligation, obligation_trait_ref) - } - super::ImplSource::AutoImpl(..) + super::ImplSource::Object(_) + | super::ImplSource::AutoImpl(..) | super::ImplSource::Param(..) | super::ImplSource::Builtin(..) | super::ImplSource::TraitAlias(..) => @@ -1211,72 +1224,6 @@ fn confirm_select_candidate<'cx, 'tcx>( } } -fn confirm_object_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, -) -> Progress<'tcx> { - let self_ty = obligation_trait_ref.self_ty(); - let object_ty = selcx.infcx().shallow_resolve(self_ty); - debug!("confirm_object_candidate(object_ty={:?})", object_ty); - let data = match object_ty.kind() { - ty::Dynamic(data, ..) => data, - _ => span_bug!( - obligation.cause.span, - "confirm_object_candidate called with non-object: {:?}", - object_ty - ), - }; - let env_predicates = data - .projection_bounds() - .map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate(selcx.tcx())); - let env_predicate = { - let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); - - // select only those projections that are actually projecting an - // item with the correct name - - let env_predicates = env_predicates.filter_map(|o| match o.predicate.skip_binders() { - ty::PredicateAtom::Projection(data) - if data.projection_ty.item_def_id == obligation.predicate.item_def_id => - { - Some(ty::Binder::bind(data)) - } - _ => None, - }); - - // select those with a relevant trait-ref - let mut env_predicates = env_predicates.filter(|data| { - let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx()); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - selcx.infcx().probe(|_| { - selcx - .infcx() - .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .is_ok() - }) - }); - - // select the first matching one; there really ought to be one or - // else the object type is not WF, since an object type should - // include all of its projections explicitly - match env_predicates.next() { - Some(env_predicate) => env_predicate, - None => { - debug!( - "confirm_object_candidate: no env-predicate \ - found in object type `{:?}`; ill-formed", - object_ty - ); - return Progress::error(selcx.tcx()); - } - } - }; - - confirm_param_env_candidate(selcx, obligation, env_predicate, false) -} - fn confirm_generator_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index e6fce78f269c..1e68554fecf5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -9,11 +9,10 @@ use rustc_data_structures::stack::ensure_sufficient_stack; 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::infer::{self, InferOk}; -use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness}; use rustc_span::def_id::DefId; @@ -434,100 +433,54 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum(); } - // Check supertraits hold - nested.extend(util::supertraits(tcx, obligation_trait_ref).skip(1).map(|super_trait| { - Obligation::new( - obligation.cause.clone(), - obligation.param_env, - super_trait.without_const().to_predicate(tcx), - ) - })); - let upcast_trait_ref = upcast_trait_ref.unwrap(); + // Check supertraits hold + nested.extend( + tcx.super_predicates_of(trait_predicate.def_id()) + .instantiate(tcx, trait_predicate.trait_ref.substs) + .predicates + .into_iter() + .map(|super_trait| { + Obligation::new(obligation.cause.clone(), obligation.param_env, super_trait) + }), + ); + let assoc_types: Vec<_> = tcx - .associated_items(upcast_trait_ref.def_id()) + .associated_items(trait_predicate.def_id()) .in_definition_order() .filter_map( |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None }, ) .collect(); - if !assoc_types.is_empty() { - let predicates: Vec<_> = - data.iter() - .filter_map(|pred| match pred { - ty::ExistentialPredicate::Projection(proj) => { - if assoc_types.contains(&proj.item_def_id) { - match self.infcx.commit_if_ok(|_| { - self.infcx - .at(&obligation.cause, obligation.param_env) - .sup( - ty::Binder::dummy( - proj.trait_ref(tcx).with_self_ty(tcx, self_ty), - ), - upcast_trait_ref, - ) - .map(|InferOk { obligations, .. }| obligations) - .map_err(|_| ()) - }) { - Ok(obligations) => { - nested.extend(obligations); - Some(proj) - } - Err(_) => None, - } - } else { - None - } - } - ty::ExistentialPredicate::AutoTrait(_) - | ty::ExistentialPredicate::Trait(_) => None, - }) - .collect(); - - let upcast_trait_ref = upcast_trait_ref - .no_bound_vars() - .expect("sup shouldn't return binder with bound vars"); - let mut normalizer = ObjectAssociatedTypeNormalizer { - infcx: self.infcx, - object_ty: self_ty, - object_bounds: &predicates, - param_env: obligation.param_env, - cause: &obligation.cause, - nested: &mut nested, - }; - for assoc_type in assoc_types { - if !tcx.generics_of(assoc_type).params.is_empty() { - // FIXME(generic_associated_types) generate placeholders to - // extend the trait substs. - tcx.sess.span_fatal( - obligation.cause.span, - "generic associated types in trait objects are not supported yet", - ); - } - // This maybe belongs in wf, but that can't (doesn't) handle - // higher-ranked things. - // Prevent, e.g., `dyn Iterator`. - for bound in self.tcx().item_bounds(assoc_type) { - let subst_bound = bound.subst(tcx, upcast_trait_ref.substs); - // Normalize projections the trait object manually to - // avoid evaluation overflow. - let object_normalized = subst_bound.fold_with(&mut normalizer); - let normalized_bound = normalize_with_depth_to( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &object_normalized, - normalizer.nested, - ); - normalizer.nested.push(Obligation::new( - obligation.cause.clone(), - obligation.param_env.clone(), - normalized_bound, - )); - } + for assoc_type in assoc_types { + if !tcx.generics_of(assoc_type).params.is_empty() { + // FIXME(generic_associated_types) generate placeholders to + // extend the trait substs. + tcx.sess.span_fatal( + obligation.cause.span, + "generic associated types in trait objects are not supported yet", + ); + } + // This maybe belongs in wf, but that can't (doesn't) handle + // higher-ranked things. + // Prevent, e.g., `dyn Iterator`. + for bound in self.tcx().item_bounds(assoc_type) { + let subst_bound = bound.subst(tcx, trait_predicate.trait_ref.substs); + let normalized_bound = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &subst_bound, + &mut nested, + ); + nested.push(Obligation::new( + obligation.cause.clone(), + obligation.param_env.clone(), + normalized_bound, + )); } } @@ -972,50 +925,3 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(ImplSourceBuiltinData { nested }) } } - -struct ObjectAssociatedTypeNormalizer<'a, 'tcx> { - infcx: &'a infer::InferCtxt<'a, 'tcx>, - object_ty: Ty<'tcx>, - object_bounds: &'a [ty::ExistentialProjection<'tcx>], - param_env: ty::ParamEnv<'tcx>, - cause: &'a ObligationCause<'tcx>, - nested: &'a mut Vec>, -} - -impl<'tcx> TypeFolder<'tcx> for ObjectAssociatedTypeNormalizer<'_, 'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_projections() { - return t; - } - if let ty::Projection(proj) = t.kind { - if let ty::Dynamic(..) = proj.self_ty().kind { - for bound in self.object_bounds { - if proj.item_def_id == bound.item_def_id { - // FIXME(generic_associated_types): This isn't relating - // the substs for the associated type. - match self.infcx.commit_if_ok(|_| { - self.infcx.at(self.cause, self.param_env).sub( - bound - .with_self_ty(self.infcx.tcx, self.object_ty) - .projection_ty - .trait_ref(self.infcx.tcx), - proj.trait_ref(self.infcx.tcx), - ) - }) { - Ok(InferOk { value: (), obligations }) => { - self.nested.extend(obligations); - return bound.ty; - } - Err(_) => {} - } - } - } - } - } - t.super_fold_with(self) - } -} diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 147b0c74d16e..d0c0e658c921 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -441,8 +441,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result { debug!( "evaluate_predicate_recursively(obligation={:?}, previous_stack={:?})", - previous_stack.head(), - obligation + obligation, + previous_stack.head() ); // `previous_stack` stores a `TraitObligation`, while `obligation` is diff --git a/src/test/ui/regions/regions-enum-not-wf.rs b/src/test/ui/regions/regions-enum-not-wf.rs index 781cdb7286a0..6de08f66d753 100644 --- a/src/test/ui/regions/regions-enum-not-wf.rs +++ b/src/test/ui/regions/regions-enum-not-wf.rs @@ -5,17 +5,18 @@ #![allow(dead_code)] trait Dummy<'a> { - type Out; + type Out; } impl<'a, T> Dummy<'a> for T -where T: 'a +where + T: 'a, { - type Out = (); + type Out = (); } type RequireOutlives<'a, T> = >::Out; enum Ref1<'a, T> { - Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough + Ref1Variant1(RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough } enum Ref2<'a, T> { @@ -23,18 +24,18 @@ enum Ref2<'a, T> { Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough } -enum RefOk<'a, T:'a> { - RefOkVariant1(&'a T) +enum RefOk<'a, T: 'a> { + RefOkVariant1(&'a T), } // This is now well formed. RFC 2093 enum RefIndirect<'a, T> { - RefIndirectVariant1(isize, RefOk<'a,T>) + RefIndirectVariant1(isize, RefOk<'a, T>), } -enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309] - RefDoubleVariant1(&'a RequireOutlives<'b, T>) - //~^ the parameter type `T` may not live long enough [E0309] +enum RefDouble<'a, 'b, T> { + RefDoubleVariant1(&'a RequireOutlives<'b, T>), + //~^ the parameter type `T` may not live long enough [E0309] } -fn main() { } +fn main() {} diff --git a/src/test/ui/regions/regions-enum-not-wf.stderr b/src/test/ui/regions/regions-enum-not-wf.stderr index e32a36f72cd1..36686eaf92f3 100644 --- a/src/test/ui/regions/regions-enum-not-wf.stderr +++ b/src/test/ui/regions/regions-enum-not-wf.stderr @@ -1,13 +1,13 @@ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/regions-enum-not-wf.rs:18:18 + --> $DIR/regions-enum-not-wf.rs:19:18 | LL | enum Ref1<'a, T> { | - help: consider adding an explicit lifetime bound...: `T: 'a` -LL | Ref1Variant1(RequireOutlives<'a, T>) +LL | Ref1Variant1(RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough - --> $DIR/regions-enum-not-wf.rs:23:25 + --> $DIR/regions-enum-not-wf.rs:24:25 | LL | enum Ref2<'a, T> { | - help: consider adding an explicit lifetime bound...: `T: 'a` @@ -16,25 +16,13 @@ LL | Ref2Variant2(isize, RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough - --> $DIR/regions-enum-not-wf.rs:35:1 - | -LL | enum RefDouble<'a, 'b, T> { - | ^ - help: consider adding an explicit lifetime bound...: `T: 'b` - | _| - | | -LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) -LL | | -LL | | } - | |_^ ...so that the type `T` will meet its required lifetime bounds - -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/regions-enum-not-wf.rs:36:23 + --> $DIR/regions-enum-not-wf.rs:37:23 | LL | enum RefDouble<'a, 'b, T> { | - help: consider adding an explicit lifetime bound...: `T: 'b` -LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) +LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>), | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.rs b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs index e912805d855d..9912e88c2ec5 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.rs +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs @@ -6,7 +6,8 @@ trait Project<'a, 'b> { } impl<'a, 'b> Project<'a, 'b> for () - where 'a: 'b +where + 'a: 'b, { type Item = (); } @@ -14,16 +15,18 @@ impl<'a, 'b> Project<'a, 'b> for () // No error here, we have 'a: 'b. We used to report an error here // though, see https://github.com/rust-lang/rust/issues/45937. fn foo<'a: 'b, 'b>() - where <() as Project<'a, 'b>>::Item : Eq +where + <() as Project<'a, 'b>>::Item: Eq, { } // Here we get an error: we need `'a: 'b`. -fn bar<'a, 'b>() //~ ERROR cannot infer - //~| ERROR cannot infer - //~| ERROR cannot infer - where <() as Project<'a, 'b>>::Item : Eq +fn bar<'a, 'b>() +//~^ ERROR cannot infer +//~| ERROR cannot infer +where + <() as Project<'a, 'b>>::Item: Eq, { } -fn main() { } +fn main() {} diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index 10ecb8d52629..24bf64261e9d 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -1,5 +1,5 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements - --> $DIR/regions-normalize-in-where-clause-list.rs:22:1 + --> $DIR/regions-normalize-in-where-clause-list.rs:24:1 | LL | / fn bar<'a, 'b>() LL | | @@ -7,18 +7,18 @@ LL | | LL | | where <() as Project<'a, 'b>>::Item : Eq | |____________________________________________^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8... - --> $DIR/regions-normalize-in-where-clause-list.rs:22:8 +note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 24:8... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:8 | LL | fn bar<'a, 'b>() | ^^ -note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12... - --> $DIR/regions-normalize-in-where-clause-list.rs:22:12 +note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 24:12... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:12 | LL | fn bar<'a, 'b>() | ^^ note: ...so that the types are compatible - --> $DIR/regions-normalize-in-where-clause-list.rs:22:1 + --> $DIR/regions-normalize-in-where-clause-list.rs:24:1 | LL | / fn bar<'a, 'b>() LL | | @@ -64,24 +64,24 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d LL | fn bar<'a, 'b>() | ^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8... - --> $DIR/regions-normalize-in-where-clause-list.rs:22:8 +note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 24:8... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:8 | LL | fn bar<'a, 'b>() | ^^ -note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12... - --> $DIR/regions-normalize-in-where-clause-list.rs:22:12 +note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 24:12... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:12 | LL | fn bar<'a, 'b>() | ^^ note: ...so that the types are compatible - --> $DIR/regions-normalize-in-where-clause-list.rs:22:4 + --> $DIR/regions-normalize-in-where-clause-list.rs:24:4 | LL | fn bar<'a, 'b>() | ^^^ = note: expected `Project<'a, 'b>` found `Project<'_, '_>` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs index 781cdb7286a0..6de08f66d753 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs +++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs @@ -5,17 +5,18 @@ #![allow(dead_code)] trait Dummy<'a> { - type Out; + type Out; } impl<'a, T> Dummy<'a> for T -where T: 'a +where + T: 'a, { - type Out = (); + type Out = (); } type RequireOutlives<'a, T> = >::Out; enum Ref1<'a, T> { - Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough + Ref1Variant1(RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough } enum Ref2<'a, T> { @@ -23,18 +24,18 @@ enum Ref2<'a, T> { Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough } -enum RefOk<'a, T:'a> { - RefOkVariant1(&'a T) +enum RefOk<'a, T: 'a> { + RefOkVariant1(&'a T), } // This is now well formed. RFC 2093 enum RefIndirect<'a, T> { - RefIndirectVariant1(isize, RefOk<'a,T>) + RefIndirectVariant1(isize, RefOk<'a, T>), } -enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309] - RefDoubleVariant1(&'a RequireOutlives<'b, T>) - //~^ the parameter type `T` may not live long enough [E0309] +enum RefDouble<'a, 'b, T> { + RefDoubleVariant1(&'a RequireOutlives<'b, T>), + //~^ the parameter type `T` may not live long enough [E0309] } -fn main() { } +fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr index e32a36f72cd1..36686eaf92f3 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr @@ -1,13 +1,13 @@ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/regions-enum-not-wf.rs:18:18 + --> $DIR/regions-enum-not-wf.rs:19:18 | LL | enum Ref1<'a, T> { | - help: consider adding an explicit lifetime bound...: `T: 'a` -LL | Ref1Variant1(RequireOutlives<'a, T>) +LL | Ref1Variant1(RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough - --> $DIR/regions-enum-not-wf.rs:23:25 + --> $DIR/regions-enum-not-wf.rs:24:25 | LL | enum Ref2<'a, T> { | - help: consider adding an explicit lifetime bound...: `T: 'a` @@ -16,25 +16,13 @@ LL | Ref2Variant2(isize, RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough - --> $DIR/regions-enum-not-wf.rs:35:1 - | -LL | enum RefDouble<'a, 'b, T> { - | ^ - help: consider adding an explicit lifetime bound...: `T: 'b` - | _| - | | -LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) -LL | | -LL | | } - | |_^ ...so that the type `T` will meet its required lifetime bounds - -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/regions-enum-not-wf.rs:36:23 + --> $DIR/regions-enum-not-wf.rs:37:23 | LL | enum RefDouble<'a, 'b, T> { | - help: consider adding an explicit lifetime bound...: `T: 'b` -LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) +LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>), | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/traits/cycle-cache-err-60010.rs b/src/test/ui/traits/cycle-cache-err-60010.rs index 62d558fde888..98bfcb8d67b5 100644 --- a/src/test/ui/traits/cycle-cache-err-60010.rs +++ b/src/test/ui/traits/cycle-cache-err-60010.rs @@ -24,7 +24,7 @@ struct Runtime { _storage: Box, } struct SalsaStorage { - _parse: >::Data, //~ ERROR overflow + _parse: >::Data, } impl Database for RootDatabase { @@ -67,6 +67,7 @@ pub(crate) fn goto_implementation(db: &RootDatabase) -> u32 { // we used to fail to report an error here because we got the // caching wrong. SourceDatabase::parse(db); + //~^ ERROR overflow 22 } diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr index 25b1f427f3a1..738b052a11eb 100644 --- a/src/test/ui/traits/cycle-cache-err-60010.stderr +++ b/src/test/ui/traits/cycle-cache-err-60010.stderr @@ -1,10 +1,18 @@ -error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase` - --> $DIR/cycle-cache-err-60010.rs:27:13 +error[E0275]: overflow evaluating the requirement `SalsaStorage: std::panic::RefUnwindSafe` + --> $DIR/cycle-cache-err-60010.rs:69:5 | -LL | _parse: >::Data, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn parse(&self) { + | --------------- required by `SourceDatabase::parse` +... +LL | SourceDatabase::parse(db); + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: required because of the requirements on the impl of `Query` for `ParseQuery` + = note: required because it appears within the type `*const SalsaStorage` + = note: required because it appears within the type `std::ptr::Unique` + = note: required because it appears within the type `std::boxed::Box` + = note: required because it appears within the type `Runtime` + = note: required because it appears within the type `RootDatabase` + = note: required because of the requirements on the impl of `SourceDatabase` for `RootDatabase` error[E0275]: overflow evaluating the requirement `Runtime: RefUnwindSafe` --> $DIR/cycle-cache-err-60010.rs:31:20