Skip to content

Commit dbb21b3

Browse files
committed
use report_generic_bound_failure when we can in the compiler
1 parent 5274e29 commit dbb21b3

25 files changed

+189
-85
lines changed

Diff for: src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+87-27
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
430430
None
431431
};
432432

433-
self.check_type_tests(infcx, mir, outlives_requirements.as_mut());
433+
self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut());
434434

435435
self.check_universal_regions(infcx, mir, mir_def_id, outlives_requirements.as_mut());
436436

@@ -504,6 +504,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
504504
&self,
505505
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
506506
mir: &Mir<'tcx>,
507+
mir_def_id: DefId,
507508
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
508509
) {
509510
let tcx = infcx.tcx;
@@ -522,14 +523,56 @@ impl<'tcx> RegionInferenceContext<'tcx> {
522523
}
523524

524525
// Oh the humanity. Obviously we will do better than this error eventually.
525-
tcx.sess.span_err(
526-
type_test.span,
527-
&format!(
528-
"`{}` does not outlive `{:?}`",
526+
let lower_bound_region = self.to_error_region(type_test.lower_bound);
527+
if let Some(lower_bound_region) = lower_bound_region {
528+
let region_scope_tree = &tcx.region_scope_tree(mir_def_id);
529+
infcx.report_generic_bound_failure(
530+
region_scope_tree,
531+
type_test.span,
532+
None,
529533
type_test.generic_kind,
530-
type_test.lower_bound,
531-
),
532-
);
534+
lower_bound_region,
535+
);
536+
} else {
537+
// FIXME. We should handle this case better. It
538+
// indicates that we have e.g. some region variable
539+
// whose value is like `'a+'b` where `'a` and `'b` are
540+
// distinct unrelated univesal regions that are not
541+
// known to outlive one another. It'd be nice to have
542+
// some examples where this arises to decide how best
543+
// to report it; we could probably handle it by
544+
// iterating over the universal regions and reporting
545+
// an error that multiple bounds are required.
546+
tcx.sess.span_err(
547+
type_test.span,
548+
&format!(
549+
"`{}` does not live long enough",
550+
type_test.generic_kind,
551+
),
552+
);
553+
}
554+
}
555+
}
556+
557+
/// Converts a region inference variable into a `ty::Region` that
558+
/// we can use for error reporting. If `r` is universally bound,
559+
/// then we use the name that we have on record for it. If `r` is
560+
/// existentially bound, then we check its inferred value and try
561+
/// to find a good name from that. Returns `None` if we can't find
562+
/// one (e.g., this is just some random part of the CFG).
563+
fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
564+
if self.universal_regions.is_universal_region(r) {
565+
return self.definitions[r].external_name;
566+
} else {
567+
let inferred_values = self.inferred_values
568+
.as_ref()
569+
.expect("region values not yet inferred");
570+
let upper_bound = self.universal_upper_bound(r);
571+
if inferred_values.contains(r, upper_bound) {
572+
self.to_error_region(upper_bound)
573+
} else {
574+
None
575+
}
533576
}
534577
}
535578

@@ -663,6 +706,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
663706
/// encoding `T` as part of `try_promote_type_test_subject` (see
664707
/// that fn for details).
665708
///
709+
/// This is based on the result `'y` of `universal_upper_bound`,
710+
/// except that it converts further takes the non-local upper
711+
/// bound of `'y`, so that the final result is non-local.
712+
fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
713+
let inferred_values = self.inferred_values.as_ref().unwrap();
714+
715+
debug!(
716+
"non_local_universal_upper_bound(r={:?}={})",
717+
r,
718+
inferred_values.region_value_str(r)
719+
);
720+
721+
let lub = self.universal_upper_bound(r);
722+
723+
// Grow further to get smallest universal region known to
724+
// creator.
725+
let non_local_lub = self.universal_regions.non_local_upper_bound(lub);
726+
727+
debug!(
728+
"non_local_universal_upper_bound: non_local_lub={:?}",
729+
non_local_lub
730+
);
731+
732+
non_local_lub
733+
}
734+
735+
/// Returns a universally quantified region that outlives the
736+
/// value of `r` (`r` may be existentially or universally
737+
/// quantified).
738+
///
666739
/// Since `r` is (potentially) an existential region, it has some
667740
/// value which may include (a) any number of points in the CFG
668741
/// and (b) any number of `end('x)` elements of universally
@@ -673,15 +746,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
673746
/// include the CFG anyhow.
674747
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
675748
/// a result `'y`.
676-
/// - Finally, we take the non-local upper bound of `'y`.
677-
/// - This uses `UniversalRegions::non_local_upper_bound`, which
678-
/// is similar to this method but only works on universal
679-
/// regions).
680-
fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
749+
fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
681750
let inferred_values = self.inferred_values.as_ref().unwrap();
682751

683752
debug!(
684-
"non_local_universal_upper_bound(r={:?}={})",
753+
"universal_upper_bound(r={:?}={})",
685754
r,
686755
inferred_values.region_value_str(r)
687756
);
@@ -693,18 +762,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
693762
lub = self.universal_regions.postdom_upper_bound(lub, ur);
694763
}
695764

696-
debug!("non_local_universal_upper_bound: lub={:?}", lub);
697-
698-
// Grow further to get smallest universal region known to
699-
// creator.
700-
let non_local_lub = self.universal_regions.non_local_upper_bound(lub);
765+
debug!("universal_upper_bound: r={:?} lub={:?}", r, lub);
701766

702-
debug!(
703-
"non_local_universal_upper_bound: non_local_lub={:?}",
704-
non_local_lub
705-
);
706-
707-
non_local_lub
767+
lub
708768
}
709769

710770
/// Test if `test` is true when applied to `lower_bound` at
@@ -924,8 +984,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
924984
) {
925985
// Obviously uncool error reporting.
926986

927-
let fr_name = self.definitions[fr].external_name;
928-
let outlived_fr_name = self.definitions[outlived_fr].external_name;
987+
let fr_name = self.to_error_region(fr);
988+
let outlived_fr_name = self.to_error_region(outlived_fr);
929989

930990
if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
931991
let tables = infcx.tcx.typeck_tables_of(mir_def_id);

Diff for: src/test/ui/nll/closure-requirements/propagate-from-trait-match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ where
4040
T: Trait<'a>,
4141
{
4242
establish_relationships(value, |value| {
43-
//~^ ERROR `T` does not outlive
43+
//~^ ERROR the parameter type `T` may not live long enough
4444

4545
// This function call requires that
4646
//

Diff for: src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ note: External requirements
99
|
1010
42 | establish_relationships(value, |value| {
1111
| ____________________________________^
12-
43 | | //~^ ERROR `T` does not outlive
12+
43 | | //~^ ERROR the parameter type `T` may not live long enough
1313
44 | |
1414
45 | | // This function call requires that
1515
... |
@@ -26,18 +26,20 @@ note: External requirements
2626
= note: number of external vids: 2
2727
= note: where T: '_#1r
2828

29-
error: `T` does not outlive `'_#3r`
29+
error[E0309]: the parameter type `T` may not live long enough
3030
--> $DIR/propagate-from-trait-match.rs:42:36
3131
|
3232
42 | establish_relationships(value, |value| {
3333
| ____________________________________^
34-
43 | | //~^ ERROR `T` does not outlive
34+
43 | | //~^ ERROR the parameter type `T` may not live long enough
3535
44 | |
3636
45 | | // This function call requires that
3737
... |
3838
56 | | //~^ WARNING not reporting region error due to -Znll
3939
57 | | });
4040
| |_____^
41+
|
42+
= help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
4143

4244
note: No external requirements
4345
--> $DIR/propagate-from-trait-match.rs:38:1

Diff for: src/test/ui/nll/ty-outlives/impl-trait-outlives.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ where
2121
T: Debug,
2222
{
2323
x
24-
//~^ ERROR `T` does not outlive
24+
//~^ ERROR the parameter type `T` may not live long enough [E0309]
2525
}
2626

2727
fn correct_region<'a, T>(x: Box<T>) -> impl Debug + 'a
@@ -37,7 +37,7 @@ where
3737
T: 'b + Debug,
3838
{
3939
x
40-
//~^ ERROR `T` does not outlive
40+
//~^ ERROR the parameter type `T` may not live long enough [E0309]
4141
}
4242

4343
fn outlives_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a

Diff for: src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,21 @@ warning: not reporting region error due to -Znll
1010
34 | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
1111
| ^^^^^^^^^^^^^^^
1212

13-
error: `T` does not outlive `'_#1r`
13+
error[E0309]: the parameter type `T` may not live long enough
1414
--> $DIR/impl-trait-outlives.rs:23:5
1515
|
1616
23 | x
1717
| ^
18+
|
19+
= help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
1820

19-
error: `T` does not outlive `'_#1r`
21+
error[E0309]: the parameter type `T` may not live long enough
2022
--> $DIR/impl-trait-outlives.rs:39:5
2123
|
2224
39 | x
2325
| ^
26+
|
27+
= help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
2428

2529
error: aborting due to 2 previous errors
2630

Diff for: src/test/ui/nll/ty-outlives/projection-implied-bounds.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ where
4444
fn generic2<T: Iterator>(value: T) {
4545
twice(value, |value_ref, item| invoke2(value_ref, item));
4646
//~^ WARNING not reporting region error due to -Znll
47-
//~| ERROR `T` does not outlive
47+
//~| ERROR the parameter type `T` may not live long enough
4848
}
4949

5050
fn invoke2<'a, T, U>(a: &T, b: Cell<&'a Option<U>>)

Diff for: src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ warning: not reporting region error due to -Znll
44
45 | twice(value, |value_ref, item| invoke2(value_ref, item));
55
| ^^^^^^^
66

7-
error: `T` does not outlive `'_#0r`
7+
error[E0310]: the parameter type `T` may not live long enough
88
--> $DIR/projection-implied-bounds.rs:45:18
99
|
1010
45 | twice(value, |value_ref, item| invoke2(value_ref, item));
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
|
13+
= help: consider adding an explicit lifetime bound `T: 'static`...
1214

1315
error: aborting due to previous error
1416

Diff for: src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ where
3535
{
3636
with_signature(x, |mut y| Box::new(y.next()))
3737
//~^ WARNING not reporting region error due to -Znll
38-
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
38+
//~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
3939
}
4040

4141
#[rustc_regions]
@@ -53,7 +53,7 @@ where
5353
{
5454
with_signature(x, |mut y| Box::new(y.next()))
5555
//~^ WARNING not reporting region error due to -Znll
56-
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
56+
//~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
5757
}
5858

5959
#[rustc_regions]

Diff for: src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr

+8-4
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,13 @@ note: External requirements
7272
= note: number of external vids: 4
7373
= note: where <T as std::iter::Iterator>::Item: '_#3r
7474

75-
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#4r`
75+
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
7676
--> $DIR/projection-no-regions-closure.rs:36:23
7777
|
7878
36 | with_signature(x, |mut y| Box::new(y.next()))
7979
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
80+
|
81+
= help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
8082

8183
note: No external requirements
8284
--> $DIR/projection-no-regions-closure.rs:32:1
@@ -86,7 +88,7 @@ note: No external requirements
8688
34 | | T: Iterator,
8789
35 | | {
8890
... |
89-
38 | | //~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
91+
38 | | //~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
9092
39 | | }
9193
| |_^
9294
|
@@ -111,11 +113,13 @@ note: No external requirements
111113
T
112114
]
113115

114-
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#6r`
116+
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
115117
--> $DIR/projection-no-regions-closure.rs:54:23
116118
|
117119
54 | with_signature(x, |mut y| Box::new(y.next()))
118120
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
121+
|
122+
= help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
119123

120124
note: No external requirements
121125
--> $DIR/projection-no-regions-closure.rs:50:1
@@ -125,7 +129,7 @@ note: No external requirements
125129
52 | | T: 'b + Iterator,
126130
53 | | {
127131
... |
128-
56 | | //~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
132+
56 | | //~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
129133
57 | | }
130134
| |_^
131135
|

Diff for: src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ where
2323
{
2424
Box::new(x.next())
2525
//~^ WARNING not reporting region error due to -Znll
26-
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
26+
//~| the associated type `<T as std::iter::Iterator>::Item` may not live long enough
2727
}
2828

2929
fn correct_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
@@ -39,7 +39,7 @@ where
3939
{
4040
Box::new(x.next())
4141
//~^ WARNING not reporting region error due to -Znll
42-
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
42+
//~| the associated type `<T as std::iter::Iterator>::Item` may not live long enough
4343
}
4444

4545
fn outlives_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>

Diff for: src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,21 @@ warning: not reporting region error due to -Znll
1010
40 | Box::new(x.next())
1111
| ^^^^^^^^^^^^^^^^^^
1212

13-
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#4r`
13+
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
1414
--> $DIR/projection-no-regions-fn.rs:24:5
1515
|
1616
24 | Box::new(x.next())
1717
| ^^^^^^^^^^^^^^^^^^
18+
|
19+
= help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
1820

19-
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#5r`
21+
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
2022
--> $DIR/projection-no-regions-fn.rs:40:5
2123
|
2224
40 | Box::new(x.next())
2325
| ^^^^^^^^^^^^^^^^^^
26+
|
27+
= help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
2428

2529
error: aborting due to 2 previous errors
2630

0 commit comments

Comments
 (0)