Skip to content

Commit ba196bd

Browse files
committed
Auto merge of #51444 - estebank:impl-static, r=nikomatsakis
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. Fix #43719, #51282. ``` error: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:17:16 | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { | ----------------------- this return type evaluates to the `'static` lifetime... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | | ...but this borrow... | note: ...can't outlive the anonymous lifetime #1 defined on the method body at 16:5 --> $DIR/static-return-lifetime-infered.rs:16:5 | LL | / fn iter_values_anon(&self) -> impl Iterator<Item=u32> { LL | | self.x.iter().map(|a| a.0) LL | | } | |_____^ 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 | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ```
2 parents 99a9d68 + 612657d commit ba196bd

File tree

8 files changed

+206
-1
lines changed

8 files changed

+206
-1
lines changed

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

+2
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>) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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::{BoundRegion, FreeRegion, 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+
"cannot infer an appropriate lifetime",
39+
);
40+
err.span_label(
41+
return_sp,
42+
"this return type evaluates to the `'static` lifetime...",
43+
);
44+
err.span_label(
45+
sup_origin.span(),
46+
"...but this borrow...",
47+
);
48+
49+
let (lifetime, lt_sp_opt) = self.tcx.msg_span_from_free_region(sup_r);
50+
if let Some(lifetime_sp) = lt_sp_opt {
51+
err.span_note(
52+
lifetime_sp,
53+
&format!("...can't outlive {}", lifetime),
54+
);
55+
}
56+
57+
let lifetime_name = match sup_r {
58+
RegionKind::ReFree(FreeRegion {
59+
bound_region: BoundRegion::BrNamed(_, ref name), ..
60+
}) => format!("{}", name),
61+
_ => "'_".to_owned(),
62+
};
63+
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(return_sp) {
64+
err.span_suggestion(
65+
return_sp,
66+
&format!(
67+
"you can add a constraint to the return type to make it last \
68+
less than `'static` and match {}",
69+
lifetime,
70+
),
71+
format!("{} + {}", snippet, lifetime_name),
72+
);
73+
}
74+
err.emit();
75+
return Some(ErrorReported);
76+
}
77+
}
78+
_ => {}
79+
}
80+
}
81+
None
82+
}
83+
}

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

+17
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

+1-1
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

+7
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
17511751
}
17521752
}
17531753

1754+
pub fn is_impl_trait(&self) -> bool {
1755+
match self.sty {
1756+
TyAnon(..) => true,
1757+
_ => false,
1758+
}
1759+
}
1760+
17541761
pub fn ty_to_def_id(&self) -> Option<DefId> {
17551762
match self.sty {
17561763
TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
warning: not reporting region error due to nll
2+
--> $DIR/static-return-lifetime-infered.rs:17:16
3+
|
4+
LL | self.x.iter().map(|a| a.0)
5+
| ^^^^
6+
7+
warning: not reporting region error due to nll
8+
--> $DIR/static-return-lifetime-infered.rs:21:16
9+
|
10+
LL | self.x.iter().map(|a| a.0)
11+
| ^^^^
12+
13+
error: free region `` does not outlive free region `'static`
14+
--> $DIR/static-return-lifetime-infered.rs:17:9
15+
|
16+
LL | self.x.iter().map(|a| a.0)
17+
| ^^^^^^^^^^^^^
18+
19+
error: free region `'a` does not outlive free region `'static`
20+
--> $DIR/static-return-lifetime-infered.rs:21:9
21+
|
22+
LL | self.x.iter().map(|a| a.0)
23+
| ^^^^^^^^^^^^^
24+
25+
error: aborting due to 2 previous errors
26+
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 cannot 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 cannot infer an appropriate lifetime
24+
}
25+
26+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error: cannot 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+
| ------ ^^^^
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: cannot 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+
| ------ ^^^^
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> + 'a {
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
43+
error: aborting due to 2 previous errors
44+

0 commit comments

Comments
 (0)