Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

promote placeholder bounds to 'static obligations #98713

Merged
merged 1 commit into from
Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 33 additions & 5 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// The idea then is to lower the `T: 'X` constraint into multiple
/// bounds -- e.g., if `'X` is the union of two free lifetimes,
/// `'1` and `'2`, then we would create `T: '1` and `T: '2`.
#[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))]
fn try_promote_type_test(
&self,
infcx: &InferCtxt<'_, 'tcx>,
Expand All @@ -933,11 +934,41 @@ impl<'tcx> RegionInferenceContext<'tcx> {
return false;
};

debug!("subject = {:?}", subject);

let r_scc = self.constraint_sccs.scc(*lower_bound);

debug!(
"lower_bound = {:?} r_scc={:?} universe={:?}",
lower_bound, r_scc, self.scc_universes[r_scc]
);

// If the type test requires that `T: 'a` where `'a` is a
// placeholder from another universe, that effectively requires
// `T: 'static`, so we have to propagate that requirement.
//
// It doesn't matter *what* universe because the promoted `T` will
// always be in the root universe.
if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() {
debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
let static_r = self.universal_regions.fr_static;
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject,
outlived_free_region: static_r,
blame_span: locations.span(body),
category: ConstraintCategory::Boring,
});

// we can return here -- the code below might push add'l constraints
// but they would all be weaker than this one.
return true;
}

// For each region outlived by lower_bound find a non-local,
// universal region (it may be the same region) and add it to
// `ClosureOutlivesRequirement`.
let r_scc = self.constraint_sccs.scc(*lower_bound);
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
debug!("universal_region_outlived_by ur={:?}", ur);
// Check whether we can already prove that the "subject" outlives `ur`.
// If so, we don't have to propagate this requirement to our caller.
//
Expand All @@ -962,8 +993,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
continue;
}

debug!("try_promote_type_test: ur={:?}", 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);

Expand Down Expand Up @@ -1000,15 +1029,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// will use it's *external name*, which will be a `RegionKind`
/// variant that can be used in query responses such as
/// `ReEarlyBound`.
#[instrument(level = "debug", skip(self, infcx))]
fn try_promote_type_test_subject(
&self,
infcx: &InferCtxt<'_, 'tcx>,
ty: Ty<'tcx>,
) -> Option<ClosureOutlivesSubject<'tcx>> {
let tcx = infcx.tcx;

debug!("try_promote_type_test_subject(ty = {:?})", ty);

let ty = tcx.fold_regions(ty, |r, _depth| {
let region_vid = self.to_region_vid(r);

Expand Down
1 change: 1 addition & 0 deletions src/test/ui/generic-associated-types/issue-91139.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fn foo<T>() {
//~| ERROR `T` does not live long enough
//~| ERROR `T` does not live long enough
//~| ERROR `T` does not live long enough
//~| ERROR `T` may not live long enough
//
// FIXME: This error is bogus, but it arises because we try to validate
// that `<() as Foo<T>>::Type<'a>` is valid, which requires proving
Expand Down
14 changes: 13 additions & 1 deletion src/test/ui/generic-associated-types/issue-91139.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ error: `T` does not live long enough
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
| ^^^^^^^^^

error[E0310]: the parameter type `T` may not live long enough
--> $DIR/issue-91139.rs:16:58
|
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
| ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
LL | fn foo<T: 'static>() {
| +++++++++

error: `T` does not live long enough
--> $DIR/issue-91139.rs:16:58
|
Expand All @@ -46,5 +57,6 @@ error: `T` does not live long enough
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
| ^^^^^^^^^

error: aborting due to 8 previous errors
error: aborting due to 9 previous errors

For more information about this error, try `rustc --explain E0310`.
21 changes: 21 additions & 0 deletions src/test/ui/nll/issue-98693.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Regression test for #98693.
//
// The closure encounters an obligation that `T` must outlive `!U1`,
// a placeholder from universe U1. We were ignoring this placeholder
// when promoting the constraint to the enclosing function, and
// thus incorrectly judging the closure to be safe.

fn assert_static<T>()
where
for<'a> T: 'a,
{
}

fn test<T>() {
|| {
//~^ ERROR the parameter type `T` may not live long enough
assert_static::<T>();
};
}

fn main() {}
17 changes: 17 additions & 0 deletions src/test/ui/nll/issue-98693.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/issue-98693.rs:15:5
|
LL | / || {
LL | |
LL | | assert_static::<T>();
LL | | };
| |_____^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
LL | fn test<T: 'static>() {
| +++++++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0310`.