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> + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ```
This commit is contained in:
commit
ba196bdcb1
@ -19,6 +19,7 @@ mod different_lifetimes;
|
||||
mod find_anon_type;
|
||||
mod named_anon_conflict;
|
||||
mod outlives_closure;
|
||||
mod static_impl_trait;
|
||||
mod util;
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
@ -67,6 +68,7 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
|
||||
self.try_report_named_anon_conflict()
|
||||
.or_else(|| self.try_report_anon_anon_conflict())
|
||||
.or_else(|| self.try_report_outlives_closure())
|
||||
.or_else(|| self.try_report_static_impl_trait())
|
||||
}
|
||||
|
||||
pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
|
||||
|
@ -0,0 +1,83 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Error Reporting for static impl Traits.
|
||||
|
||||
use infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use infer::lexical_region_resolve::RegionResolutionError;
|
||||
use ty::{BoundRegion, FreeRegion, RegionKind};
|
||||
use util::common::ErrorReported;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
|
||||
/// Print the error message for lifetime errors when the return type is a static impl Trait.
|
||||
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
|
||||
if let Some(ref error) = self.error {
|
||||
match error.clone() {
|
||||
RegionResolutionError::SubSupConflict(
|
||||
var_origin,
|
||||
sub_origin,
|
||||
sub_r,
|
||||
sup_origin,
|
||||
sup_r,
|
||||
) => {
|
||||
let anon_reg_sup = self.is_suitable_region(sup_r)?;
|
||||
if sub_r == &RegionKind::ReStatic &&
|
||||
self.is_return_type_impl_trait(anon_reg_sup.def_id)
|
||||
{
|
||||
let sp = var_origin.span();
|
||||
let return_sp = sub_origin.span();
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
sp,
|
||||
"cannot infer an appropriate lifetime",
|
||||
);
|
||||
err.span_label(
|
||||
return_sp,
|
||||
"this return type evaluates to the `'static` lifetime...",
|
||||
);
|
||||
err.span_label(
|
||||
sup_origin.span(),
|
||||
"...but this borrow...",
|
||||
);
|
||||
|
||||
let (lifetime, lt_sp_opt) = self.tcx.msg_span_from_free_region(sup_r);
|
||||
if let Some(lifetime_sp) = lt_sp_opt {
|
||||
err.span_note(
|
||||
lifetime_sp,
|
||||
&format!("...can't outlive {}", lifetime),
|
||||
);
|
||||
}
|
||||
|
||||
let lifetime_name = match sup_r {
|
||||
RegionKind::ReFree(FreeRegion {
|
||||
bound_region: BoundRegion::BrNamed(_, ref name), ..
|
||||
}) => format!("{}", name),
|
||||
_ => "'_".to_owned(),
|
||||
};
|
||||
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(return_sp) {
|
||||
err.span_suggestion(
|
||||
return_sp,
|
||||
&format!(
|
||||
"you can add a constraint to the return type to make it last \
|
||||
less than `'static` and match {}",
|
||||
lifetime,
|
||||
),
|
||||
format!("{} + {}", snippet, lifetime_name),
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
return Some(ErrorReported);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
@ -167,6 +167,23 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(super) fn is_return_type_impl_trait(
|
||||
&self,
|
||||
scope_def_id: DefId,
|
||||
) -> bool {
|
||||
let ret_ty = self.tcx.type_of(scope_def_id);
|
||||
match ret_ty.sty {
|
||||
ty::TyFnDef(_, _) => {
|
||||
let sig = ret_ty.fn_sig(self.tcx);
|
||||
let output = self.tcx.erase_late_bound_regions(&sig.output());
|
||||
return output.is_impl_trait();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// Here we check for the case where anonymous region
|
||||
// corresponds to self and if yes, we display E0312.
|
||||
// FIXME(#42700) - Need to format self properly to
|
||||
|
@ -179,7 +179,7 @@ pub enum Note {
|
||||
// and how it is located, as well as the mutability of the memory in
|
||||
// which the value is stored.
|
||||
//
|
||||
// *WARNING* The field `cmt.type` is NOT necessarily the same as the
|
||||
// *WARNING* The field `cmt.ty` is NOT necessarily the same as the
|
||||
// result of `node_id_to_type(cmt.id)`. This is because the `id` is
|
||||
// always the `id` of the node producing the type; in an expression
|
||||
// like `*x`, the type of this deref node is the deref'd type (`T`),
|
||||
|
@ -1751,6 +1751,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_impl_trait(&self) -> bool {
|
||||
match self.sty {
|
||||
TyAnon(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty_to_def_id(&self) -> Option<DefId> {
|
||||
match self.sty {
|
||||
TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
|
||||
|
@ -0,0 +1,26 @@
|
||||
warning: not reporting region error due to nll
|
||||
--> $DIR/static-return-lifetime-infered.rs:17:16
|
||||
|
|
||||
LL | self.x.iter().map(|a| a.0)
|
||||
| ^^^^
|
||||
|
||||
warning: not reporting region error due to nll
|
||||
--> $DIR/static-return-lifetime-infered.rs:21:16
|
||||
|
|
||||
LL | self.x.iter().map(|a| a.0)
|
||||
| ^^^^
|
||||
|
||||
error: free region `` does not outlive free region `'static`
|
||||
--> $DIR/static-return-lifetime-infered.rs:17:9
|
||||
|
|
||||
LL | self.x.iter().map(|a| a.0)
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: free region `'a` does not outlive free region `'static`
|
||||
--> $DIR/static-return-lifetime-infered.rs:21:9
|
||||
|
|
||||
LL | self.x.iter().map(|a| a.0)
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
26
src/test/ui/impl-trait/static-return-lifetime-infered.rs
Normal file
26
src/test/ui/impl-trait/static-return-lifetime-infered.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct A {
|
||||
x: [(u32, u32); 10]
|
||||
}
|
||||
|
||||
impl A {
|
||||
fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
|
||||
self.x.iter().map(|a| a.0)
|
||||
}
|
||||
//~^^ ERROR cannot infer an appropriate lifetime
|
||||
fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
|
||||
self.x.iter().map(|a| a.0)
|
||||
}
|
||||
//~^^ ERROR cannot infer an appropriate lifetime
|
||||
}
|
||||
|
||||
fn main() {}
|
44
src/test/ui/impl-trait/static-return-lifetime-infered.stderr
Normal file
44
src/test/ui/impl-trait/static-return-lifetime-infered.stderr
Normal file
@ -0,0 +1,44 @@
|
||||
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> + '_ {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: cannot infer an appropriate lifetime
|
||||
--> $DIR/static-return-lifetime-infered.rs:21:16
|
||||
|
|
||||
LL | fn iter_values<'a>(&'a 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 lifetime 'a as defined on the method body at 20:5
|
||||
--> $DIR/static-return-lifetime-infered.rs:20:5
|
||||
|
|
||||
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
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
|
||||
|
|
||||
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
x
Reference in New Issue
Block a user