diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 0e30b136622a0..e660a7477c981 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1049,6 +1049,62 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } + // Attempts to satisfy a type outlives predicate that is instantiated with + // a placeholder by using a higher-ranked type outlives caller bound. + pub fn type_outlives_predicate_from_param_env( + &self, + cause: &traits::ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + region: ty::Region<'tcx>, + ) -> Option>> { + if ty.is_ty_infer() { + return None; + } + + for caller_bound in param_env.caller_bounds() { + let ty::PredicateKind::TypeOutlives(bound_outlives) = + caller_bound.kind().skip_binder() else { continue }; + + // Only use WC bounds that are themselves of the form `for<'a> TY: 'a` + if !bound_outlives.1.is_late_bound() { + continue; + } + + let satisfies = self.commit_if_ok::<_, (), _>(|_| { + let ty::OutlivesPredicate(wc_ty, wc_region) = self + .replace_bound_vars_with_fresh_vars( + cause.span, + LateBoundRegionConversionTime::HigherRankedType, + caller_bound.kind().rebind(bound_outlives), + ); + + let mut r = self.at(cause, param_env).eq(wc_region, region).map_err(|_| ())?; + + // Specifically use two snapshots here, so we can make sure _not_ + // to constrain the regions of `Ty` here. We probably should just + // use some custom `replace_bound_vars_with_fresh_vars` that doesn't + // replace `wc_region` with an infer variable, but eagerly replaces + // it with `region` instead. + self.commit_if_ok::<_, (), _>(|snapshot| { + let t = self.at(cause, param_env).eq(wc_ty, ty).map_err(|_| ())?; + r.obligations.extend(t.into_obligations()); + if self.region_constraints_added_in_snapshot(snapshot).is_none() { + Ok(r.obligations) + } else { + Err(()) + } + }) + }); + + if let Ok(obligations) = satisfies { + return Some(obligations); + } + } + + None + } + /// Number of type variables created so far. pub fn num_ty_vars(&self) -> usize { self.inner.borrow_mut().type_variables().num_vars() diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 053e871c14f6e..a548a702eaca3 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -432,13 +432,17 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => { + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_a)) => { if self.register_region_obligations { - self.selcx.infcx().register_region_obligation_with_cause( - t_a, - r_b, + if let Some(obligations) = infcx.type_outlives_predicate_from_param_env( &obligation.cause, - ); + obligation.param_env, + t_a, + r_a, + ) { + return ProcessResult::Changed(mk_pending(obligations)); + } + infcx.register_region_obligation_with_cause(t_a, r_a, &obligation.cause); } ProcessResult::Changed(vec![]) } diff --git a/src/test/ui/generic-associated-types/issue-86483.rs b/src/test/ui/generic-associated-types/issue-86483.rs index a8b54c354e3f3..eb6acb19f3b8a 100644 --- a/src/test/ui/generic-associated-types/issue-86483.rs +++ b/src/test/ui/generic-associated-types/issue-86483.rs @@ -1,14 +1,13 @@ // Regression test of #86483. +// check-pass #![feature(generic_associated_types)] -pub trait IceIce //~ ERROR: the parameter type `T` may not live long enough +pub trait IceIce where for<'a> T: 'a, { type Ice<'v>: IntoIterator; - //~^ ERROR: the parameter type `T` may not live long enough - //~| ERROR: the parameter type `T` may not live long enough } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-86483.stderr b/src/test/ui/generic-associated-types/issue-86483.stderr deleted file mode 100644 index a13dc043dc52b..0000000000000 --- a/src/test/ui/generic-associated-types/issue-86483.stderr +++ /dev/null @@ -1,50 +0,0 @@ -error[E0311]: the parameter type `T` may not live long enough - --> $DIR/issue-86483.rs:5:1 - | -LL | / pub trait IceIce -LL | | where -LL | | for<'a> T: 'a, -LL | | { -... | -LL | | -LL | | } - | |_^ - | - = note: ...so that the type `T` will meet its required lifetime bounds... -note: ...that is required by this bound - --> $DIR/issue-86483.rs:7:16 - | -LL | for<'a> T: 'a, - | ^^ -help: consider adding an explicit lifetime bound... - | -LL | for<'a> T: 'a + 'a, - | ++++ - -error[E0311]: the parameter type `T` may not live long enough - --> $DIR/issue-86483.rs:9:5 - | -LL | type Ice<'v>: IntoIterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... - | -note: ...that is required by this bound - --> $DIR/issue-86483.rs:7:16 - | -LL | for<'a> T: 'a, - | ^^ -help: consider adding an explicit lifetime bound... - | -LL | for<'a> T: 'a + 'a, - | ++++ - -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/issue-86483.rs:9:32 - | -LL | type Ice<'v>: IntoIterator; - | ^^^^^^^^^^^^ - help: consider adding a where clause: `where T: 'v` - | | - | ...so that the reference type `&'v T` does not outlive the data it points at - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/generic-associated-types/issue-88360.rs b/src/test/ui/generic-associated-types/issue-88360.rs index 8ee98201aba7a..84203c17da6a6 100644 --- a/src/test/ui/generic-associated-types/issue-88360.rs +++ b/src/test/ui/generic-associated-types/issue-88360.rs @@ -13,7 +13,7 @@ where { fn copy(&self) -> Self::Gat<'_> where T: Copy { *self.test() - //~^ mismatched types + //~^ ERROR mismatched types } } diff --git a/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs b/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs index b50f56b03d9cd..c047d6d9bc6c5 100644 --- a/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs +++ b/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs @@ -1,10 +1,9 @@ +// check-pass + // Regression test for #88586: a higher-ranked outlives bound on Self in a trait // definition caused an ICE when debug_assertions were enabled. -// -// FIXME: The error output in the absence of the ICE is unhelpful; this should be improved. trait A where for<'a> Self: 'a -//~^ ERROR the parameter type `Self` may not live long enough { } diff --git a/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr b/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr deleted file mode 100644 index 18618ffcc86dc..0000000000000 --- a/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0311]: the parameter type `Self` may not live long enough - --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:1 - | -LL | / trait A where for<'a> Self: 'a -LL | | -LL | | { -LL | | } - | |_^ - | - = help: consider adding an explicit lifetime bound `Self: 'a`... - = note: ...so that the type `Self` will meet its required lifetime bounds... -note: ...that is required by this bound - --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:29 - | -LL | trait A where for<'a> Self: 'a - | ^^ - -error: aborting due to previous error - diff --git a/src/test/ui/hrtb/issue-97607.rs b/src/test/ui/hrtb/issue-97607.rs new file mode 100644 index 0000000000000..a1d7c741436ff --- /dev/null +++ b/src/test/ui/hrtb/issue-97607.rs @@ -0,0 +1,11 @@ +// check-pass + +fn test(f: F) -> Box U + 'static> +where + F: 'static + Fn(T) -> U, + for<'a> U: 'a, // < This is the problematic line -- remove it, and it passes. +{ + Box::new(move |t| f(t)) +} + +fn main() {}