mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-22 12:43:36 +00:00
Rollup merge of #133798 - lcnr:nested-bodies-opaques, r=compiler-errors
stop replacing bivariant args with `'static` when computing closure requirements It is unnecessary, these get constrained when checking that the opaque type is well-formed. It also results in the opaque type no longer being well formed. If you've got `fn foo<'a>() -> impl Sized + 'a` the opaque is `type Opaque<'a, 'aDummy> where 'a: 'aDummy, 'aDummy: 'a` where `'aDummy` is bivariant. If we call `foo::<'b>()` inside of a closure and its return type ends up in a type test, we start out with the WF `Opaque<'b, 'b>`, and then replace the bivariant `'b` with `'static`. `Opaque<'b, 'static>` is no longer well-formed. Given how these type tests are used, I don't think this caused any practical issues. r? types
This commit is contained in:
commit
9fd0972677
@ -973,25 +973,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
|
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
|
let TypeTest { generic_kind, lower_bound, span: blame_span, ref verify_bound } = *type_test;
|
||||||
let TypeTest { generic_kind, lower_bound, span: _, verify_bound: _ } = type_test;
|
|
||||||
|
|
||||||
let generic_ty = generic_kind.to_ty(tcx);
|
let generic_ty = generic_kind.to_ty(tcx);
|
||||||
let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else {
|
let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("subject = {:?}", subject);
|
let r_scc = self.constraint_sccs.scc(lower_bound);
|
||||||
|
|
||||||
let r_scc = self.constraint_sccs.scc(*lower_bound);
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"lower_bound = {:?} r_scc={:?} universe={:?}",
|
"lower_bound = {:?} r_scc={:?} universe={:?}",
|
||||||
lower_bound,
|
lower_bound,
|
||||||
r_scc,
|
r_scc,
|
||||||
self.constraint_sccs.annotation(r_scc).min_universe()
|
self.constraint_sccs.annotation(r_scc).min_universe()
|
||||||
);
|
);
|
||||||
|
|
||||||
// If the type test requires that `T: 'a` where `'a` is a
|
// If the type test requires that `T: 'a` where `'a` is a
|
||||||
// placeholder from another universe, that effectively requires
|
// placeholder from another universe, that effectively requires
|
||||||
// `T: 'static`, so we have to propagate that requirement.
|
// `T: 'static`, so we have to propagate that requirement.
|
||||||
@ -1004,7 +999,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||||
subject,
|
subject,
|
||||||
outlived_free_region: static_r,
|
outlived_free_region: static_r,
|
||||||
blame_span: type_test.span,
|
blame_span,
|
||||||
category: ConstraintCategory::Boring,
|
category: ConstraintCategory::Boring,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1031,12 +1026,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
// where `ur` is a local bound -- we are sometimes in a
|
// where `ur` is a local bound -- we are sometimes in a
|
||||||
// position to prove things that our caller cannot. See
|
// position to prove things that our caller cannot. See
|
||||||
// #53570 for an example.
|
// #53570 for an example.
|
||||||
if self.eval_verify_bound(infcx, generic_ty, ur, &type_test.verify_bound) {
|
if self.eval_verify_bound(infcx, generic_ty, ur, &verify_bound) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
|
let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
|
||||||
debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
|
debug!(?non_local_ub);
|
||||||
|
|
||||||
// This is slightly too conservative. To show T: '1, given `'2: '1`
|
// This is slightly too conservative. To show T: '1, given `'2: '1`
|
||||||
// and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to
|
// and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to
|
||||||
@ -1049,10 +1044,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
let requirement = ClosureOutlivesRequirement {
|
let requirement = ClosureOutlivesRequirement {
|
||||||
subject,
|
subject,
|
||||||
outlived_free_region: upper_bound,
|
outlived_free_region: upper_bound,
|
||||||
blame_span: type_test.span,
|
blame_span,
|
||||||
category: ConstraintCategory::Boring,
|
category: ConstraintCategory::Boring,
|
||||||
};
|
};
|
||||||
debug!("try_promote_type_test: pushing {:#?}", requirement);
|
debug!(?requirement, "adding closure requirement");
|
||||||
propagated_outlives_requirements.push(requirement);
|
propagated_outlives_requirements.push(requirement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1063,44 +1058,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
/// variables in the type `T` with an equal universal region from the
|
/// variables in the type `T` with an equal universal region from the
|
||||||
/// closure signature.
|
/// closure signature.
|
||||||
/// This is not always possible, so this is a fallible process.
|
/// This is not always possible, so this is a fallible process.
|
||||||
#[instrument(level = "debug", skip(self, infcx))]
|
#[instrument(level = "debug", skip(self, infcx), ret)]
|
||||||
fn try_promote_type_test_subject(
|
fn try_promote_type_test_subject(
|
||||||
&self,
|
&self,
|
||||||
infcx: &InferCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Option<ClosureOutlivesSubject<'tcx>> {
|
) -> Option<ClosureOutlivesSubject<'tcx>> {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
|
|
||||||
// Opaque types' args may include useless lifetimes.
|
|
||||||
// We will replace them with ReStatic.
|
|
||||||
struct OpaqueFolder<'tcx> {
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
}
|
|
||||||
impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for OpaqueFolder<'tcx> {
|
|
||||||
fn cx(&self) -> TyCtxt<'tcx> {
|
|
||||||
self.tcx
|
|
||||||
}
|
|
||||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
|
||||||
use ty::TypeSuperFoldable as _;
|
|
||||||
let tcx = self.tcx;
|
|
||||||
let &ty::Alias(ty::Opaque, ty::AliasTy { args, def_id, .. }) = t.kind() else {
|
|
||||||
return t.super_fold_with(self);
|
|
||||||
};
|
|
||||||
let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| {
|
|
||||||
match (arg.unpack(), v) {
|
|
||||||
(ty::GenericArgKind::Lifetime(_), ty::Bivariant) => {
|
|
||||||
tcx.lifetimes.re_static.into()
|
|
||||||
}
|
|
||||||
_ => arg.fold_with(self),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ty::new_opaque(tcx, def_id, tcx.mk_args_from_iter(args))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = ty.fold_with(&mut OpaqueFolder { tcx });
|
|
||||||
let mut failed = false;
|
let mut failed = false;
|
||||||
|
|
||||||
let ty = fold_regions(tcx, ty, |r, _depth| {
|
let ty = fold_regions(tcx, ty, |r, _depth| {
|
||||||
let r_vid = self.to_region_vid(r);
|
let r_vid = self.to_region_vid(r);
|
||||||
let r_scc = self.constraint_sccs.scc(r_vid);
|
let r_scc = self.constraint_sccs.scc(r_vid);
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
// This example broke while refactoring the way closure
|
||||||
|
// requirements are handled. The setup here matches
|
||||||
|
// `thread::scope`.
|
||||||
|
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
struct Outlives<'hr, 'scope: 'hr>(*mut (&'scope (), &'hr ()));
|
||||||
|
impl<'hr, 'scope> Outlives<'hr, 'scope> {
|
||||||
|
fn outlives_hr<T: 'hr>(self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn takes_closure_implied_bound<'scope>(f: impl for<'hr> FnOnce(Outlives<'hr, 'scope>)) {}
|
||||||
|
|
||||||
|
fn requires_external_outlives_hr<T>() {
|
||||||
|
// implied bounds:
|
||||||
|
// - `T: 'scope` as `'scope` is local to this function
|
||||||
|
// - `'scope: 'hr` as it's an implied bound of `Outlives`
|
||||||
|
//
|
||||||
|
// need to prove `T: 'hr` :>
|
||||||
|
takes_closure_implied_bound(|proof| proof.outlives_hr::<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,21 @@
|
|||||||
|
// This example incorrectly compiled while refactoring the way
|
||||||
|
// closure requirements are handled.
|
||||||
|
|
||||||
|
struct Outlives<'hr: 'scope, 'scope>(*mut (&'scope (), &'hr ()));
|
||||||
|
impl<'hr, 'scope> Outlives<'hr, 'scope> {
|
||||||
|
fn outlives_hr<T: 'hr>(self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn takes_closure_implied_bound<'scope>(f: impl for<'hr> FnOnce(Outlives<'hr, 'scope>)) {}
|
||||||
|
|
||||||
|
fn requires_external_outlives_hr<T>() {
|
||||||
|
// implied bounds:
|
||||||
|
// - `T: 'scope` as `'scope` is local to this function
|
||||||
|
// - `'hr: 'scope` as it's an implied bound of `Outlives`
|
||||||
|
//
|
||||||
|
// need to prove `T: 'hr` :<
|
||||||
|
takes_closure_implied_bound(|proof| proof.outlives_hr::<T>());
|
||||||
|
//~^ ERROR the parameter type `T` may not live long enough
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,17 @@
|
|||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/thread_scope_incorrect_implied_bound.rs:17:47
|
||||||
|
|
|
||||||
|
LL | takes_closure_implied_bound(|proof| proof.outlives_hr::<T>());
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| the parameter type `T` must be valid for the static lifetime...
|
||||||
|
| ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn requires_external_outlives_hr<T: 'static>() {
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0310`.
|
@ -1,8 +1,6 @@
|
|||||||
// Test that we can deduce when projections like `T::Item` outlive the
|
// Test that we can deduce when projections like `T::Item` outlive the
|
||||||
// function body. Test that this does not imply that `T: 'a` holds.
|
// function body. Test that this does not imply that `T: 'a` holds.
|
||||||
|
|
||||||
//@ compile-flags:-Zverbose-internals
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
fn twice<F, T>(mut value: T, mut f: F)
|
fn twice<F, T>(mut value: T, mut f: F)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error[E0310]: the parameter type `T` may not live long enough
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/projection-implied-bounds.rs:30:36
|
--> $DIR/projection-implied-bounds.rs:28:36
|
||||||
|
|
|
|
||||||
LL | twice(value, |value_ref, item| invoke2(value_ref, item));
|
LL | twice(value, |value_ref, item| invoke2(value_ref, item));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Loading…
Reference in New Issue
Block a user