Skip to content

Commit 92b2be2

Browse files
committed
rework so that we pick static as a last resort only
1 parent b893cff commit 92b2be2

File tree

4 files changed

+89
-55
lines changed

4 files changed

+89
-55
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

+47-33
Original file line numberDiff line numberDiff line change
@@ -733,44 +733,58 @@ impl<'tcx> RegionInferenceContext<'tcx> {
733733
return false;
734734
}
735735

736-
// If there WERE no upper bounds (apart from static), and static is one of the options,
737-
// then we can just pick that (c.f. #63033).
738-
let choice = if !any_upper_bounds && choice_regions.contains(&fr_static) {
739-
fr_static
740-
} else {
741-
// Otherwise, we need to find the minimum remaining choice, if
742-
// any, and take that.
743-
debug!("apply_member_constraint: choice_regions remaining are {:#?}", choice_regions);
744-
let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
745-
let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
746-
let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
747-
match (r1_outlives_r2, r2_outlives_r1) {
748-
(true, true) => Some(r1.min(r2)),
749-
(true, false) => Some(r2),
750-
(false, true) => Some(r1),
751-
(false, false) => None,
752-
}
753-
};
754-
let mut min_choice = choice_regions[0];
755-
for &other_option in &choice_regions[1..] {
756-
debug!(
757-
"apply_member_constraint: min_choice={:?} other_option={:?}",
758-
min_choice, other_option,
759-
);
760-
match min(min_choice, other_option) {
761-
Some(m) => min_choice = m,
762-
None => {
763-
debug!(
764-
"apply_member_constraint: {:?} and {:?} are incomparable; no min choice",
765-
min_choice, other_option,
736+
// Otherwise, we need to find the minimum remaining choice, if
737+
// any, and take that.
738+
debug!("apply_member_constraint: choice_regions remaining are {:#?}", choice_regions);
739+
let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
740+
let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
741+
let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
742+
match (r1_outlives_r2, r2_outlives_r1) {
743+
(true, true) => Some(r1.min(r2)),
744+
(true, false) => Some(r2),
745+
(false, true) => Some(r1),
746+
(false, false) => None,
747+
}
748+
};
749+
let mut min_choice = choice_regions[0];
750+
for &other_option in &choice_regions[1..] {
751+
debug!(
752+
"apply_member_constraint: min_choice={:?} other_option={:?}",
753+
min_choice, other_option,
754+
);
755+
match min(min_choice, other_option) {
756+
Some(m) => min_choice = m,
757+
None => {
758+
debug!(
759+
"apply_member_constraint: {:?} and {:?} are incomparable; no min choice",
760+
min_choice, other_option,
761+
);
762+
763+
// If there is no minimum choice, then we *may* wish to use `'static`
764+
// instead, but only if there are no upper bounds, and `'static` is a valid
765+
// choice.
766+
if !any_upper_bounds && choice_regions.contains(&fr_static) {
767+
return self.apply_member_constraint_choice(
768+
scc,
769+
member_constraint_index,
770+
fr_static,
766771
);
767-
return false;
768772
}
773+
774+
// Otherwise, we give up.
775+
return false;
769776
}
770777
}
771-
min_choice
772-
};
778+
}
779+
self.apply_member_constraint_choice(scc, member_constraint_index, min_choice)
780+
}
773781

782+
fn apply_member_constraint_choice(
783+
&mut self,
784+
scc: ConstraintSccIndex,
785+
member_constraint_index: NllMemberConstraintIndex,
786+
choice: ty::RegionVid,
787+
) -> bool {
774788
let choice_scc = self.constraint_sccs.scc(choice);
775789
debug!("apply_member_constraint: min_choice={:?} best_choice_scc={:?}", choice, choice_scc,);
776790
if self.scc_values.add_region(scc, choice_scc) {

compiler/rustc_borrowck/src/universal_regions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -473,8 +473,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
473473
}
474474

475475
let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid();
476-
let num_universals = self.infcx.num_region_vars();
476+
debug!("build: fr_fn_Body = {:?}", fr_fn_body);
477477

478+
let num_universals = self.infcx.num_region_vars();
478479
debug!("build: global regions = {}..{}", FIRST_GLOBAL_INDEX, first_extern_index);
479480
debug!("build: extern regions = {}..{}", first_extern_index, first_local_index);
480481
debug!("build: local regions = {}..{}", first_local_index, num_universals);

compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs

+21-21
Original file line numberDiff line numberDiff line change
@@ -303,16 +303,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
303303
self.collect_bounding_regions(graph, member_vid, OUTGOING, None);
304304
debug!("enforce_member_constraint: upper_bounds={:#?}", member_upper_bounds);
305305

306-
// If there are no upper bounds, and static is a choice (in practice, it always is),
307-
// then we should just pick static.
308-
if member_upper_bounds.is_empty()
309-
&& member_constraint.choice_regions.contains(&&ty::RegionKind::ReStatic)
310-
{
311-
debug!("enforce_member_constraint: selecting 'static since there are no upper bounds",);
312-
*var_values.value_mut(member_vid) = VarValue::Value(self.tcx().lifetimes.re_static);
313-
return true;
314-
}
315-
316306
// Get an iterator over the *available choice* -- that is,
317307
// each choice region `c` where `lb <= c` and `c <= ub` for all the
318308
// upper bounds `ub`.
@@ -326,19 +316,32 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
326316
// If there is more than one option, we only make a choice if
327317
// there is a single *least* choice -- i.e., some available
328318
// region that is `<=` all the others.
329-
let mut least_choice: ty::Region<'tcx> = match options.next() {
319+
let mut choice: ty::Region<'tcx> = match options.next() {
330320
Some(&r) => r,
331321
None => return false,
332322
};
333-
debug!("enforce_member_constraint: least_choice={:?}", least_choice);
323+
debug!("enforce_member_constraint: least_choice={:?}", choice);
334324
for &option in options {
335325
debug!("enforce_member_constraint: option={:?}", option);
336-
if !self.sub_concrete_regions(least_choice, option) {
337-
if self.sub_concrete_regions(option, least_choice) {
326+
if !self.sub_concrete_regions(choice, option) {
327+
if self.sub_concrete_regions(option, choice) {
338328
debug!("enforce_member_constraint: new least choice");
339-
least_choice = option;
329+
choice = option;
340330
} else {
341331
debug!("enforce_member_constraint: no least choice");
332+
333+
// Pick static if:
334+
// * There is no least choice (which we just found to be true)
335+
// * There are no upper bounds (so the region can grow to any size)
336+
// * Static is a choice (in practice, it always is)
337+
if member_upper_bounds.is_empty()
338+
&& member_constraint.choice_regions.contains(&&ty::RegionKind::ReStatic)
339+
{
340+
choice = self.tcx().lifetimes.re_static;
341+
break;
342+
}
343+
344+
// Otherwise give up
342345
return false;
343346
}
344347
}
@@ -353,13 +356,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
353356
// choice is needed here so that we don't end up in a cycle of
354357
// `expansion` changing the region one way and the code here changing
355358
// it back.
356-
let lub = self.lub_concrete_regions(least_choice, member_lower_bound);
357-
debug!(
358-
"enforce_member_constraint: final least choice = {:?}\nlub = {:?}",
359-
least_choice, lub
360-
);
359+
let lub = self.lub_concrete_regions(choice, member_lower_bound);
360+
debug!("enforce_member_constraint: final choice = {:?}\nlub = {:?}", choice, lub);
361361
if lub != member_lower_bound {
362-
*var_values.value_mut(member_vid) = VarValue::Value(least_choice);
362+
*var_values.value_mut(member_vid) = VarValue::Value(choice);
363363
true
364364
} else {
365365
false
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Regression test found by crater run. The scenario here is that we have
2+
// a region variable `?0` from the `impl Future` with no upper bounds
3+
// and a member constraint of `?0 in ['a, 'static]`. If we pick `'static`,
4+
// however, we then fail the check that `F: ?0` (since we only know that
5+
// F: ?a). The problem here is that our upper bound detection
6+
// doesn't consider "type tests" like `F: 'x`. This was fixed by
7+
// preferring to pick a least choice and only using static as a last resort.
8+
//
9+
// edition:2018
10+
// check-pass
11+
12+
trait Future {}
13+
impl Future for () {}
14+
15+
fn sink_error1<'a, F: 'a>(f: F) -> impl Future + 'a {
16+
sink_error2(f) // error: `F` may not live long enough
17+
}
18+
fn sink_error2<'a, F: 'a>(_: F) -> impl Future + 'a {}
19+
fn main() {}

0 commit comments

Comments
 (0)