Suggest substituting `'static` lifetime in impl/dyn `Trait + 'static` return types

This commit is contained in:
Esteban Küber 2020-05-29 15:09:43 -07:00
parent ff4a2533a0
commit 81c909488e
6 changed files with 232 additions and 29 deletions

View File

@ -4,6 +4,7 @@ use crate::infer::error_reporting::msg_span_from_free_region;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use rustc_errors::{Applicability, ErrorReported};
use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
use rustc_middle::ty::RegionKind;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@ -20,8 +21,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
) = error.clone()
{
let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
let (fn_return_span, is_dyn) =
self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
let is_dyn = matches!(fn_return.kind, TyKind::TraitObject(..));
let fn_return_span = fn_return.span;
if sub_r == &RegionKind::ReStatic {
let sp = var_origin.span();
let return_sp = sub_origin.span();
@ -67,12 +69,58 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
lifetime,
);
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
err.span_suggestion_verbose(
fn_return_span.shrink_to_hi(),
&msg,
format!(" + {}", lifetime_name),
Applicability::MaybeIncorrect,
);
match fn_return.kind {
TyKind::Def(item_id, _) => {
let item = self.tcx().hir().item(item_id.id);
let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
opaque
} else {
err.emit();
return Some(ErrorReported);
};
let (span, sugg) = opaque
.bounds
.iter()
.filter_map(|arg| match arg {
GenericBound::Outlives(Lifetime {
name: LifetimeName::Static,
span,
..
}) => Some((*span, lifetime_name.clone())),
_ => None,
})
.next()
.unwrap_or_else(|| {
(
fn_return_span.shrink_to_hi(),
format!(" + {}", lifetime_name),
)
});
err.span_suggestion_verbose(
span,
&msg,
sugg,
Applicability::MaybeIncorrect,
);
}
TyKind::TraitObject(_, lt) => {
let (span, sugg) = match lt.name {
LifetimeName::ImplicitObjectLifetimeDefault => (
fn_return_span.shrink_to_hi(),
format!(" + {}", lifetime_name),
),
_ => (lt.span, lifetime_name),
};
err.span_suggestion_verbose(
span,
&msg,
sugg,
Applicability::MaybeIncorrect,
);
}
_ => {}
}
}
err.emit();
return Some(ErrorReported);

View File

@ -1383,7 +1383,10 @@ impl<'tcx> TyCtxt<'tcx> {
})
}
pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span, bool)> {
pub fn return_type_impl_or_dyn_trait(
&self,
scope_def_id: DefId,
) -> Option<&'tcx hir::Ty<'tcx>> {
let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
let hir_output = match self.hir().get(hir_id) {
Node::Item(hir::Item {
@ -1429,15 +1432,17 @@ impl<'tcx> TyCtxt<'tcx> {
let output = self.erase_late_bound_regions(&sig.output());
if output.is_impl_trait() {
let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
Some((fn_decl.output.span(), false))
if let hir::FnRetTy::Return(ty) = fn_decl.output {
return Some(ty);
}
} else {
let mut v = TraitObjectVisitor(vec![]);
rustc_hir::intravisit::walk_ty(&mut v, hir_output);
if v.0.len() == 1 {
return Some((v.0[0], true));
return Some(v.0[0]);
}
None
}
None
}
_ => None,
}

View File

@ -236,21 +236,21 @@ pub fn suggest_constraining_type_param(
}
}
pub struct TraitObjectVisitor(pub Vec<rustc_span::Span>);
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor {
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>);
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
type Map = rustc_hir::intravisit::ErasedMap<'v>;
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
hir::intravisit::NestedVisitorMap::None
}
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
if let hir::TyKind::TraitObject(
_,
hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. },
) = ty.kind
{
self.0.push(ty.span);
self.0.push(ty);
}
}
}

View File

@ -26,7 +26,34 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^^^^^^^^^^^
error: lifetime may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:12:69
--> $DIR/must_outlive_least_region_or_bound.rs:9:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| - ^ returning this value requires that `'1` must outlive `'static`
| |
| let's call the lifetime of this reference `'1`
|
= help: consider replacing `'1` with `'static`
error: lifetime may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:12:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
|
= help: consider replacing `'a` with `'static`
= help: consider replacing `'a` with `'static`
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/must_outlive_least_region_or_bound.rs:15:41
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
| ---- ^ lifetime `'a` required
| |
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
error: lifetime may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:33:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
@ -35,7 +62,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
= help: consider replacing `'a` with `'static`
error: lifetime may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:17:61
--> $DIR/must_outlive_least_region_or_bound.rs:38:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
@ -45,13 +72,14 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
= help: consider adding the following bound: `'b: 'a`
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:22:51
--> $DIR/must_outlive_least_region_or_bound.rs:43:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| ^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
error: aborting due to 5 previous errors
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0310`.
Some errors have detailed explanations: E0310, E0621.
For more information about an error, try `rustc --explain E0310`.

View File

@ -6,6 +6,27 @@ fn elided(x: &i32) -> impl Copy { x }
fn explicit<'a>(x: &'a i32) -> impl Copy { x }
//~^ ERROR cannot infer an appropriate lifetime
fn elided2(x: &i32) -> impl Copy + 'static { x }
//~^ ERROR cannot infer an appropriate lifetime
fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
//~^ ERROR cannot infer an appropriate lifetime
fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
//~^ ERROR explicit lifetime required in the type of `x`
fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
//~^ ERROR cannot infer an appropriate lifetime
fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
//~^ ERROR cannot infer an appropriate lifetime
fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
//~^ ERROR explicit lifetime required in the type of `x`
fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
//~^ ERROR cannot infer an appropriate lifetime
trait LifetimeTrait<'a> {}
impl<'a> LifetimeTrait<'a> for &'a i32 {}

View File

@ -27,7 +27,43 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^
error: cannot infer an appropriate lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:12:69
--> $DIR/must_outlive_least_region_or_bound.rs:9:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| ---- ------------------- ^ ...and is captured here
| | |
| | ...is required to be `'static` by this...
| data with this lifetime...
|
help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 9:1
|
LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
| ^^
error: cannot infer an appropriate lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:12:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| ------- ------------------- ^ ...and is captured here
| | |
| | ...is required to be `'static` by this...
| data with this lifetime...
|
help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:14
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/must_outlive_least_region_or_bound.rs:15:24
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
| ---- ^^^^^^^^^^^^^^ lifetime `'a` required
| |
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
error: cannot infer an appropriate lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:33:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ------- -------------------------------- ^ ...and is captured here
@ -35,13 +71,13 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| | ...is required to be `'static` by this...
| data with this lifetime...
|
help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:15
help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 33:15
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
| ^^^^
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
| ^^
error[E0623]: lifetime mismatch
--> $DIR/must_outlive_least_region_or_bound.rs:17:61
--> $DIR/must_outlive_least_region_or_bound.rs:38:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| ------- ^^^^^^^^^^^^^^^^
@ -50,14 +86,79 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
| this parameter and the return type are declared with different lifetimes...
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:22:51
--> $DIR/must_outlive_least_region_or_bound.rs:43:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
| |
| help: consider adding an explicit lifetime bound...: `T: 'static +`
error: aborting due to 5 previous errors
error: cannot infer an appropriate lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:18:50
|
LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
| ---- ---------^-
| | | |
| | | ...and is captured here
| | ...is required to be `'static` by this...
| data with this lifetime...
|
help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1
|
LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
| ^^^^
Some errors have detailed explanations: E0310, E0623.
error: cannot infer an appropriate lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:21:59
|
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
| ------- ---------^-
| | | |
| | | ...and is captured here
| | ...is required to be `'static` by this...
| data with this lifetime...
|
help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14
|
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
| ^^^^
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/must_outlive_least_region_or_bound.rs:24:51
|
LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ---- ^^^^^^^^^^^ lifetime `'static` required
| |
| help: add explicit lifetime `'static` to the type of `x`: `&'static i32`
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/must_outlive_least_region_or_bound.rs:27:69
|
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 27:14...
--> $DIR/must_outlive_least_region_or_bound.rs:27:14
|
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ^^
note: ...so that the expression is assignable
--> $DIR/must_outlive_least_region_or_bound.rs:27:69
|
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ^
= note: expected `&i32`
found `&'a i32`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
--> $DIR/must_outlive_least_region_or_bound.rs:27:60
|
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ^^^^^^^^^^^
= note: expected `std::boxed::Box<(dyn std::fmt::Debug + 'static)>`
found `std::boxed::Box<dyn std::fmt::Debug>`
error: aborting due to 12 previous errors
Some errors have detailed explanations: E0310, E0495, E0621, E0623.
For more information about an error, try `rustc --explain E0310`.