Skip to content

Commit

Permalink
use report_generic_bound_failure when we can in the compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis committed Dec 20, 2017
1 parent 5274e29 commit dbb21b3
Show file tree
Hide file tree
Showing 25 changed files with 189 additions and 85 deletions.
114 changes: 87 additions & 27 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
None
};

self.check_type_tests(infcx, mir, outlives_requirements.as_mut());
self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut());

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

Expand Down Expand Up @@ -504,6 +504,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
mir_def_id: DefId,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
) {
let tcx = infcx.tcx;
Expand All @@ -522,14 +523,56 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}

// Oh the humanity. Obviously we will do better than this error eventually.
tcx.sess.span_err(
type_test.span,
&format!(
"`{}` does not outlive `{:?}`",
let lower_bound_region = self.to_error_region(type_test.lower_bound);
if let Some(lower_bound_region) = lower_bound_region {
let region_scope_tree = &tcx.region_scope_tree(mir_def_id);
infcx.report_generic_bound_failure(
region_scope_tree,
type_test.span,
None,
type_test.generic_kind,
type_test.lower_bound,
),
);
lower_bound_region,
);
} else {
// FIXME. We should handle this case better. It
// indicates that we have e.g. some region variable
// whose value is like `'a+'b` where `'a` and `'b` are
// distinct unrelated univesal regions that are not
// known to outlive one another. It'd be nice to have
// some examples where this arises to decide how best
// to report it; we could probably handle it by
// iterating over the universal regions and reporting
// an error that multiple bounds are required.
tcx.sess.span_err(
type_test.span,
&format!(
"`{}` does not live long enough",
type_test.generic_kind,
),
);
}
}
}

/// Converts a region inference variable into a `ty::Region` that
/// we can use for error reporting. If `r` is universally bound,
/// then we use the name that we have on record for it. If `r` is
/// existentially bound, then we check its inferred value and try
/// to find a good name from that. Returns `None` if we can't find
/// one (e.g., this is just some random part of the CFG).
fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
if self.universal_regions.is_universal_region(r) {
return self.definitions[r].external_name;
} else {
let inferred_values = self.inferred_values
.as_ref()
.expect("region values not yet inferred");
let upper_bound = self.universal_upper_bound(r);
if inferred_values.contains(r, upper_bound) {
self.to_error_region(upper_bound)
} else {
None
}
}
}

Expand Down Expand Up @@ -663,6 +706,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// encoding `T` as part of `try_promote_type_test_subject` (see
/// that fn for details).
///
/// This is based on the result `'y` of `universal_upper_bound`,
/// except that it converts further takes the non-local upper
/// bound of `'y`, so that the final result is non-local.
fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
let inferred_values = self.inferred_values.as_ref().unwrap();

debug!(
"non_local_universal_upper_bound(r={:?}={})",
r,
inferred_values.region_value_str(r)
);

let lub = self.universal_upper_bound(r);

// Grow further to get smallest universal region known to
// creator.
let non_local_lub = self.universal_regions.non_local_upper_bound(lub);

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

non_local_lub
}

/// Returns a universally quantified region that outlives the
/// value of `r` (`r` may be existentially or universally
/// quantified).
///
/// Since `r` is (potentially) an existential region, it has some
/// value which may include (a) any number of points in the CFG
/// and (b) any number of `end('x)` elements of universally
Expand All @@ -673,15 +746,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// include the CFG anyhow.
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
/// a result `'y`.
/// - Finally, we take the non-local upper bound of `'y`.
/// - This uses `UniversalRegions::non_local_upper_bound`, which
/// is similar to this method but only works on universal
/// regions).
fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
let inferred_values = self.inferred_values.as_ref().unwrap();

debug!(
"non_local_universal_upper_bound(r={:?}={})",
"universal_upper_bound(r={:?}={})",
r,
inferred_values.region_value_str(r)
);
Expand All @@ -693,18 +762,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
lub = self.universal_regions.postdom_upper_bound(lub, ur);
}

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

// Grow further to get smallest universal region known to
// creator.
let non_local_lub = self.universal_regions.non_local_upper_bound(lub);
debug!("universal_upper_bound: r={:?} lub={:?}", r, lub);

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

non_local_lub
lub
}

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

let fr_name = self.definitions[fr].external_name;
let outlived_fr_name = self.definitions[outlived_fr].external_name;
let fr_name = self.to_error_region(fr);
let outlived_fr_name = self.to_error_region(outlived_fr);

if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ where
T: Trait<'a>,
{
establish_relationships(value, |value| {
//~^ ERROR `T` does not outlive
//~^ ERROR the parameter type `T` may not live long enough

// This function call requires that
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ note: External requirements
|
42 | establish_relationships(value, |value| {
| ____________________________________^
43 | | //~^ ERROR `T` does not outlive
43 | | //~^ ERROR the parameter type `T` may not live long enough
44 | |
45 | | // This function call requires that
... |
Expand All @@ -26,18 +26,20 @@ note: External requirements
= note: number of external vids: 2
= note: where T: '_#1r

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

note: No external requirements
--> $DIR/propagate-from-trait-match.rs:38:1
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/nll/ty-outlives/impl-trait-outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ where
T: Debug,
{
x
//~^ ERROR `T` does not outlive
//~^ ERROR the parameter type `T` may not live long enough [E0309]
}

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

fn outlives_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
Expand Down
8 changes: 6 additions & 2 deletions src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ warning: not reporting region error due to -Znll
34 | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
| ^^^^^^^^^^^^^^^

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

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

error: aborting due to 2 previous errors

2 changes: 1 addition & 1 deletion src/test/ui/nll/ty-outlives/projection-implied-bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ where
fn generic2<T: Iterator>(value: T) {
twice(value, |value_ref, item| invoke2(value_ref, item));
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `T` does not outlive
//~| ERROR the parameter type `T` may not live long enough
}

fn invoke2<'a, T, U>(a: &T, b: Cell<&'a Option<U>>)
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ warning: not reporting region error due to -Znll
45 | twice(value, |value_ref, item| invoke2(value_ref, item));
| ^^^^^^^

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

error: aborting due to previous error

4 changes: 2 additions & 2 deletions src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ where
{
with_signature(x, |mut y| Box::new(y.next()))
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
//~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}

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

#[rustc_regions]
Expand Down
12 changes: 8 additions & 4 deletions src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ note: External requirements
= note: number of external vids: 4
= note: where <T as std::iter::Iterator>::Item: '_#3r

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

note: No external requirements
--> $DIR/projection-no-regions-closure.rs:32:1
Expand All @@ -86,7 +88,7 @@ note: No external requirements
34 | | T: Iterator,
35 | | {
... |
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
39 | | }
| |_^
|
Expand All @@ -111,11 +113,13 @@ note: No external requirements
T
]

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

note: No external requirements
--> $DIR/projection-no-regions-closure.rs:50:1
Expand All @@ -125,7 +129,7 @@ note: No external requirements
52 | | T: 'b + Iterator,
53 | | {
... |
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
57 | | }
| |_^
|
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ where
{
Box::new(x.next())
//~^ WARNING not reporting region error due to -Znll
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
//~| the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}

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

fn outlives_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
Expand Down
8 changes: 6 additions & 2 deletions src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ warning: not reporting region error due to -Znll
40 | Box::new(x.next())
| ^^^^^^^^^^^^^^^^^^

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

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

error: aborting due to 2 previous errors

Loading

0 comments on commit dbb21b3

Please sign in to comment.