Skip to content

Commit 30c247f

Browse files
committed
Suggest using anonymous lifetime in impl Trait return without hacks
Fallback to `static_impl_trait` for nice error message by peeking at the return type and the lifetime type. Point at the return type instead of the return expr/stmt in NLL mode.
1 parent ee2a9d9 commit 30c247f

File tree

6 files changed

+41
-48
lines changed

6 files changed

+41
-48
lines changed

src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs

+13-34
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Error Reporting for Anonymous Region Lifetime Errors
22
//! where one region is named and the other is anonymous.
33
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
4+
use crate::hir::{FunctionRetTy, TyKind};
45
use crate::ty;
56
use errors::{Applicability, DiagnosticBuilder};
67

@@ -11,9 +12,10 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
1112
let (span, sub, sup) = self.get_regions();
1213

1314
debug!(
14-
"try_report_named_anon_conflict(sub={:?}, sup={:?})",
15+
"try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",
1516
sub,
16-
sup
17+
sup,
18+
self.error,
1719
);
1820

1921
// Determine whether the sub and sup consist of one named region ('a)
@@ -84,6 +86,13 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
8486
{
8587
return None;
8688
}
89+
if let FunctionRetTy::Return(ty) = &fndecl.output {
90+
if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.node, sub) {
91+
// This is an impl Trait return that evaluates de need of 'static.
92+
// We handle this case better in `static_impl_trait`.
93+
return None;
94+
}
95+
}
8796
}
8897

8998
let (error_var, span_label_var) = if let Some(simple_ident) = arg.pat.simple_ident() {
@@ -103,40 +112,10 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
103112
error_var
104113
);
105114

106-
let many = if let Ok(snippet) = self.tcx().sess.source_map().span_to_snippet(span) {
107-
if "'static" == &named.to_string() && snippet.starts_with("impl ") {
108-
diag.span_suggestion(
109-
span,
110-
"add explicit unnamed lifetime `'_` to the return type to constrain it",
111-
format!("{} + '_", snippet),
112-
Applicability::Unspecified,
113-
);
114-
true
115-
} else {
116-
false
117-
}
118-
} else {
119-
false
120-
};
121-
if many {
122-
diag.span_label(
123-
span,
124-
"`impl Trait` types can only capture lifetimes that they reference"
125-
);
126-
} else {
127-
diag.span_label(span, format!("lifetime `{}` required", named));
128-
}
115+
diag.span_label(span, format!("lifetime `{}` required", named));
129116
diag.span_suggestion(
130117
new_ty_span,
131-
&format!("{}add explicit lifetime `{}` to {}",
132-
if many {
133-
"otherwise, "
134-
} else {
135-
""
136-
},
137-
named,
138-
span_label_var,
139-
),
118+
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
140119
new_ty.to_string(),
141120
Applicability::Unspecified,
142121
);

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
132132
}
133133
});
134134
if let Some(i) = best_choice {
135+
if let Some(next) = categorized_path.get(i + 1) {
136+
if categorized_path[i].0 == ConstraintCategory::Return
137+
&& next.0 == ConstraintCategory::OpaqueType
138+
{
139+
// The return expression is being influenced by the return type being
140+
// impl Trait, point at the return type and not the return expr.
141+
return *next;
142+
}
143+
}
135144
return categorized_path[i];
136145
}
137146

@@ -240,6 +249,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
240249
self.provides_universal_region(r, fr, outlived_fr)
241250
});
242251

252+
debug!("report_error: category={:?} {:?}", category, span);
243253
// Check if we can use one of the "nice region errors".
244254
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
245255
let tables = infcx.tcx.typeck_tables_of(mir_def_id);

src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::fmt::Debug;
22

33
fn elided(x: &i32) -> impl Copy { x }
4-
//~^ ERROR explicit lifetime required in the type of `x` [E0621]
4+
//~^ ERROR cannot infer an appropriate lifetime
55

66
fn explicit<'a>(x: &'a i32) -> impl Copy { x }
77
//~^ ERROR cannot infer an appropriate lifetime

src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr

+13-9
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
error[E0621]: explicit lifetime required in the type of `x`
2-
--> $DIR/must_outlive_least_region_or_bound.rs:3:23
1+
error: cannot infer an appropriate lifetime
2+
--> $DIR/must_outlive_least_region_or_bound.rs:3:35
33
|
44
LL | fn elided(x: &i32) -> impl Copy { x }
5-
| ^^^^^^^^^ `impl Trait` types can only capture lifetimes that they reference
6-
help: add explicit unnamed lifetime `'_` to the return type to constrain it
5+
| --------- ^ ...but this borrow...
6+
| |
7+
| this return type evaluates to the `'static` lifetime...
8+
|
9+
note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1
10+
--> $DIR/must_outlive_least_region_or_bound.rs:3:1
11+
|
12+
LL | fn elided(x: &i32) -> impl Copy { x }
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1
715
|
816
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
917
| ^^^^^^^^^^^^^^
10-
help: otherwise, add explicit lifetime `'static` to the type of `x`
11-
|
12-
LL | fn elided(x: &'static i32) -> impl Copy { x }
13-
| ^^^^^^^^^^^^
1418

1519
error: cannot infer an appropriate lifetime
1620
--> $DIR/must_outlive_least_region_or_bound.rs:6:44
@@ -73,5 +77,5 @@ LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
7377

7478
error: aborting due to 5 previous errors
7579

76-
Some errors occurred: E0310, E0621, E0623.
80+
Some errors occurred: E0310, E0623.
7781
For more information about an error, try `rustc --explain E0310`.

src/test/ui/nll/ty-outlives/impl-trait-captures.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ trait Foo<'a> {
88
impl<'a, T> Foo<'a> for T { }
99

1010
fn foo<'a, T>(x: &T) -> impl Foo<'a> {
11+
//~^ ERROR explicit lifetime required in the type of `x` [E0621]
1112
x
12-
//~^ ERROR explicit lifetime required in the type of `x` [E0621]
1313
}
1414

1515
fn main() {}

src/test/ui/nll/ty-outlives/impl-trait-captures.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0621]: explicit lifetime required in the type of `x`
2-
--> $DIR/impl-trait-captures.rs:11:5
2+
--> $DIR/impl-trait-captures.rs:10:25
33
|
4-
LL | x
5-
| ^ lifetime `ReEarlyBound(0, 'a)` required
4+
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
5+
| ^^^^^^^^^^^^ lifetime `ReEarlyBound(0, 'a)` required
66
help: add explicit lifetime `ReEarlyBound(0, 'a)` to the type of `x`
77
|
88
LL | fn foo<'a, T>(x: &ReEarlyBound(0, 'a) T) -> impl Foo<'a> {

0 commit comments

Comments
 (0)