Skip to content

Commit 82d3a49

Browse files
committed
Suggestion for 'static impl Trait return
When encountering a named or anonymous sup requirement (for example, `&'a self`) and a `'static` impl Trait return type, suggest adding the `'_` lifetime constraing to the return type.
1 parent 41affd0 commit 82d3a49

File tree

7 files changed

+175
-1
lines changed

7 files changed

+175
-1
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ mod different_lifetimes;
1919
mod find_anon_type;
2020
mod named_anon_conflict;
2121
mod outlives_closure;
22+
mod static_impl_trait;
2223
mod util;
2324

2425
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
@@ -67,6 +68,7 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
6768
self.try_report_named_anon_conflict()
6869
.or_else(|| self.try_report_anon_anon_conflict())
6970
.or_else(|| self.try_report_outlives_closure())
71+
.or_else(|| self.try_report_static_impl_trait())
7072
}
7173

7274
pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Error Reporting for static impl Traits.
12+
13+
use infer::error_reporting::nice_region_error::NiceRegionError;
14+
use infer::lexical_region_resolve::RegionResolutionError;
15+
use ty::RegionKind;
16+
use util::common::ErrorReported;
17+
18+
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
19+
/// Print the error message for lifetime errors when the return type is a static impl Trait.
20+
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
21+
if let Some(ref error) = self.error {
22+
match error.clone() {
23+
RegionResolutionError::SubSupConflict(
24+
var_origin,
25+
sub_origin,
26+
sub_r,
27+
sup_origin,
28+
sup_r,
29+
) => {
30+
let anon_reg_sup = self.is_suitable_region(sup_r)?;
31+
if sub_r == &RegionKind::ReStatic &&
32+
self._is_return_type_impl_trait(anon_reg_sup.def_id)
33+
{
34+
let sp = var_origin.span();
35+
let return_sp = sub_origin.span();
36+
let mut err = self.tcx.sess.struct_span_err(
37+
sp,
38+
"can't infer an appropriate lifetime",
39+
);
40+
err.span_label(sp, "can't infer an appropriate lifetime");
41+
err.span_label(
42+
return_sp,
43+
"this return type evaluates to the `'static` lifetime...",
44+
);
45+
err.span_label(
46+
sup_origin.span(),
47+
"...but this borrow...",
48+
);
49+
50+
let (lifetime, lt_sp_opt) = self.tcx.msg_span_from_free_region(sup_r);
51+
if let Some(lifetime_sp) = lt_sp_opt {
52+
err.span_note(
53+
lifetime_sp,
54+
&format!("...can't outlive {}", lifetime),
55+
);
56+
}
57+
58+
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(return_sp) {
59+
err.span_suggestion(
60+
return_sp,
61+
&format!(
62+
"you can add a constraint to the return type to make it last \
63+
less than `'static` and match {}",
64+
lifetime,
65+
),
66+
format!("{} + '_", snippet),
67+
);
68+
}
69+
err.emit();
70+
return Some(ErrorReported);
71+
}
72+
}
73+
_ => {}
74+
}
75+
}
76+
None
77+
}
78+
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,23 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
167167
}
168168
None
169169
}
170+
171+
pub(super) fn _is_return_type_impl_trait(
172+
&self,
173+
scope_def_id: DefId,
174+
) -> bool {
175+
let ret_ty = self.tcx.type_of(scope_def_id);
176+
match ret_ty.sty {
177+
ty::TyFnDef(_, _) => {
178+
let sig = ret_ty.fn_sig(self.tcx);
179+
let output = self.tcx.erase_late_bound_regions(&sig.output());
180+
return output.is_impl_trait();
181+
}
182+
_ => {}
183+
}
184+
false
185+
}
186+
170187
// Here we check for the case where anonymous region
171188
// corresponds to self and if yes, we display E0312.
172189
// FIXME(#42700) - Need to format self properly to

src/librustc/middle/mem_categorization.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ pub enum Note {
179179
// and how it is located, as well as the mutability of the memory in
180180
// which the value is stored.
181181
//
182-
// *WARNING* The field `cmt.type` is NOT necessarily the same as the
182+
// *WARNING* The field `cmt.ty` is NOT necessarily the same as the
183183
// result of `node_id_to_type(cmt.id)`. This is because the `id` is
184184
// always the `id` of the node producing the type; in an expression
185185
// like `*x`, the type of this deref node is the deref'd type (`T`),

src/librustc/ty/sty.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,6 +1754,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
17541754
}
17551755
}
17561756

1757+
pub fn is_impl_trait(&self) -> bool {
1758+
match self.sty {
1759+
TyAnon(..) => true,
1760+
_ => false,
1761+
}
1762+
}
1763+
17571764
pub fn ty_to_def_id(&self) -> Option<DefId> {
17581765
match self.sty {
17591766
TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct A {
12+
x: [(u32, u32); 10]
13+
}
14+
15+
impl A {
16+
fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
17+
self.x.iter().map(|a| a.0)
18+
}
19+
//~^^^ ERROR can't infer an appropriate lifetime
20+
fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
21+
self.x.iter().map(|a| a.0)
22+
}
23+
//~^^^ ERROR can't infer an appropriate lifetime
24+
}
25+
26+
fn main() {}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error: can't infer an appropriate lifetime
2+
--> $DIR/static-return-lifetime-infered.rs:17:16
3+
|
4+
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
5+
| ----------------------- this return type evaluates to the `'static` lifetime...
6+
LL | self.x.iter().map(|a| a.0)
7+
| ------ ^^^^ can't infer an appropriate lifetime
8+
| |
9+
| ...but this borrow...
10+
|
11+
note: ...can't outlive the anonymous lifetime #1 defined on the method body at 16:5
12+
--> $DIR/static-return-lifetime-infered.rs:16:5
13+
|
14+
LL | / fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
15+
LL | | self.x.iter().map(|a| a.0)
16+
LL | | }
17+
| |_____^
18+
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 method body at 16:5
19+
|
20+
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
23+
error: can't infer an appropriate lifetime
24+
--> $DIR/static-return-lifetime-infered.rs:21:16
25+
|
26+
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
27+
| ----------------------- this return type evaluates to the `'static` lifetime...
28+
LL | self.x.iter().map(|a| a.0)
29+
| ------ ^^^^ can't infer an appropriate lifetime
30+
| |
31+
| ...but this borrow...
32+
|
33+
note: ...can't outlive the lifetime 'a as defined on the method body at 20:5
34+
--> $DIR/static-return-lifetime-infered.rs:20:5
35+
|
36+
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime 'a as defined on the method body at 20:5
39+
|
40+
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + '_ {
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
43+
error: aborting due to 2 previous errors
44+

0 commit comments

Comments
 (0)