diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index ec26a10c536..55bb75c8b6d 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -68,6 +68,7 @@ }; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; +use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; @@ -324,6 +325,29 @@ fn projection_must_outlive( origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, + ) { + self.generic_must_outlive( + origin, + region, + GenericKind::Projection(projection_ty), + projection_ty.item_def_id, + projection_ty.substs, + |ty| match ty.kind() { + ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs), + _ => bug!("expected only projection types from env, not {:?}", ty), + }, + ); + } + + #[instrument(level = "debug", skip(self, filter))] + fn generic_must_outlive( + &mut self, + origin: infer::SubregionOrigin<'tcx>, + region: ty::Region<'tcx>, + generic: GenericKind<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>), ) { // This case is thorny for inference. The fundamental problem is // that there are many cases where we have choice, and inference @@ -342,13 +366,10 @@ fn projection_must_outlive( // Compute the bounds we can derive from the trait definition. // These are guaranteed to apply, no matter the inference // results. - let trait_bounds: Vec<_> = - self.verify_bound.bounds(projection_ty.item_def_id, projection_ty.substs).collect(); + let trait_bounds: Vec<_> = self.verify_bound.bounds(def_id, substs).collect(); debug!(?trait_bounds); - let generic = GenericKind::Projection(projection_ty); - // Compute the bounds we can derive from the environment. This // is an "approximate" match -- in some cases, these bounds // may not apply. @@ -367,14 +388,8 @@ fn projection_must_outlive( // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait` // will be invoked with `['b => ^1]` and so we will get `^1` returned. let bound = bound_outlives.skip_binder(); - match *bound.0.kind() { - ty::Projection(projection_ty) => self - .verify_bound - .bounds(projection_ty.item_def_id, projection_ty.substs) - .all(|r| r != bound.1), - - _ => panic!("expected only projection types from env, not {:?}", bound.0), - } + let (def_id, substs) = filter(bound.0); + self.verify_bound.bounds(def_id, substs).all(|r| r != bound.1) }); // If declared bounds list is empty, the only applicable rule is @@ -391,11 +406,11 @@ fn projection_must_outlive( // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. - let needs_infer = projection_ty.needs_infer(); + let needs_infer = substs.needs_infer(); if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer { debug!("no declared bounds"); - self.substs_must_outlive(projection_ty.substs, origin, region); + self.substs_must_outlive(substs, origin, region); return; }