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.
This commit is contained in:
parent
41affd03eb
commit
82d3a49564
7 changed files with 175 additions and 1 deletions
|
@ -19,6 +19,7 @@ mod different_lifetimes;
|
||||||
mod find_anon_type;
|
mod find_anon_type;
|
||||||
mod named_anon_conflict;
|
mod named_anon_conflict;
|
||||||
mod outlives_closure;
|
mod outlives_closure;
|
||||||
|
mod static_impl_trait;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
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()
|
self.try_report_named_anon_conflict()
|
||||||
.or_else(|| self.try_report_anon_anon_conflict())
|
.or_else(|| self.try_report_anon_anon_conflict())
|
||||||
.or_else(|| self.try_report_outlives_closure())
|
.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>) {
|
pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
// 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::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,
|
||||||
|
"can't infer an appropriate lifetime",
|
||||||
|
);
|
||||||
|
err.span_label(sp, "can't 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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
return Some(ErrorReported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
|
@ -167,6 +167,23 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
None
|
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
|
// Here we check for the case where anonymous region
|
||||||
// corresponds to self and if yes, we display E0312.
|
// corresponds to self and if yes, we display E0312.
|
||||||
// FIXME(#42700) - Need to format self properly to
|
// 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
|
// and how it is located, as well as the mutability of the memory in
|
||||||
// which the value is stored.
|
// 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
|
// 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
|
// 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`),
|
// like `*x`, the type of this deref node is the deref'd type (`T`),
|
||||||
|
|
|
@ -1754,6 +1754,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> {
|
pub fn ty_to_def_id(&self) -> Option<DefId> {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
|
TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
|
||||||
|
|
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 can't infer an appropriate lifetime
|
||||||
|
fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
|
||||||
|
self.x.iter().map(|a| a.0)
|
||||||
|
}
|
||||||
|
//~^^^ ERROR can't 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: can't 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)
|
||||||
|
| ------ ^^^^ can't infer an appropriate lifetime
|
||||||
|
| |
|
||||||
|
| ...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: can't 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)
|
||||||
|
| ------ ^^^^ can't infer an appropriate lifetime
|
||||||
|
| |
|
||||||
|
| ...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> + '_ {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue