1
Fork 0

Use a more accurate Span for 'static obligation from return type

This commit is contained in:
Esteban Kuber 2021-10-12 13:14:11 +00:00
parent ee0fd105d8
commit 10a74ac2e0
12 changed files with 85 additions and 79 deletions

View file

@ -10,7 +10,8 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor, self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable,
TypeVisitor,
}; };
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{MultiSpan, Span}; use rustc_span::{MultiSpan, Span};
@ -186,10 +187,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let parent_id = tcx.hir().get_parent_item(*hir_id); let parent_id = tcx.hir().get_parent_item(*hir_id);
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) { if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
let mut span: MultiSpan = fn_decl.output.span().into(); let mut span: MultiSpan = fn_decl.output.span().into();
span.push_span_label( let mut add_label = true;
fn_decl.output.span(), if let hir::FnRetTy::Return(ty) = fn_decl.output {
"requirement introduced by this return type".to_string(), let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
); v.visit_ty(ty);
if !v.0.is_empty() {
span = v.0.clone().into();
for sp in v.0 {
span.push_span_label(
sp,
"`'static` requirement introduced here".to_string(),
);
}
add_label = false;
}
}
if add_label {
span.push_span_label(
fn_decl.output.span(),
"requirement introduced by this return type".to_string(),
);
}
span.push_span_label( span.push_span_label(
cause.span, cause.span,
"because of this returned expression".to_string(), "because of this returned expression".to_string(),

View file

@ -1481,40 +1481,8 @@ impl<'tcx> TyCtxt<'tcx> {
scope_def_id: LocalDefId, scope_def_id: LocalDefId,
) -> Vec<&'tcx hir::Ty<'tcx>> { ) -> Vec<&'tcx hir::Ty<'tcx>> {
let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
let hir_output = match self.hir().get(hir_id) { let hir_output = match self.hir().fn_decl_by_hir_id(hir_id) {
Node::Item(hir::Item { Some(hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }) => ty,
kind:
ItemKind::Fn(
hir::FnSig {
decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. },
..
},
..,
),
..
})
| Node::ImplItem(hir::ImplItem {
kind:
hir::ImplItemKind::Fn(
hir::FnSig {
decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. },
..
},
_,
),
..
})
| Node::TraitItem(hir::TraitItem {
kind:
hir::TraitItemKind::Fn(
hir::FnSig {
decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. },
..
},
_,
),
..
}) => ty,
_ => return vec![], _ => return vec![],
}; };

View file

@ -6,6 +6,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
use rustc_span::Span;
impl<'tcx> TyS<'tcx> { impl<'tcx> TyS<'tcx> {
/// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive. /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
@ -432,3 +433,22 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
hir::intravisit::walk_ty(self, ty); hir::intravisit::walk_ty(self, ty);
} }
} }
/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'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_lifetime(&mut self, lt: &'v hir::Lifetime) {
if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static =
lt.name
{
self.0.push(lt.span);
}
}
}

View file

@ -8,10 +8,10 @@ LL | bar(foo, x)
| ^^^ - ...is captured and required to live as long as `'static` here | ^^^ - ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/project-fn-ret-invariant.rs:45:32 --> $DIR/project-fn-ret-invariant.rs:45:37
| |
LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
| ^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
... ...
LL | bar(foo, x) LL | bar(foo, x)
| ----------- because of this returned expression | ----------- because of this returned expression

View file

@ -141,12 +141,12 @@ LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
| this data with an anonymous lifetime `'_`... | this data with an anonymous lifetime `'_`...
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/must_outlive_least_region_or_bound.rs:14:24 --> $DIR/must_outlive_least_region_or_bound.rs:14:28
| |
LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
| ^^^^^^^^^^^^^^ ----------- because of this returned expression | ^^^^^^^^^ ----------- because of this returned expression
| | | |
| requirement introduced by this return type | `'static` requirement introduced here
help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
| |
LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) } LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
@ -161,12 +161,12 @@ LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
| this data with lifetime `'a`... | this data with lifetime `'a`...
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/must_outlive_least_region_or_bound.rs:16:33 --> $DIR/must_outlive_least_region_or_bound.rs:16:37
| |
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
| ^^^^^^^^^^^^^^ ----------- because of this returned expression | ^^^^^^^^^ ----------- because of this returned expression
| | | |
| requirement introduced by this return type | `'static` requirement introduced here
help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
| |
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) } LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
@ -181,12 +181,12 @@ LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| this data with an anonymous lifetime `'_`... | this data with an anonymous lifetime `'_`...
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/must_outlive_least_region_or_bound.rs:18:24 --> $DIR/must_outlive_least_region_or_bound.rs:18:40
| |
LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- because of this returned expression | ^^^^^^^ ----------- because of this returned expression
| | | |
| requirement introduced by this return type | `'static` requirement introduced here
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
| |
LL | fn elided4(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) } LL | fn elided4(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
@ -203,12 +203,12 @@ LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ------- this data with lifetime `'a`... ^ ...is captured and required to live as long as `'static` here | ------- this data with lifetime `'a`... ^ ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/must_outlive_least_region_or_bound.rs:20:33 --> $DIR/must_outlive_least_region_or_bound.rs:20:49
| |
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- because of this returned expression | ^^^^^^^ ----------- because of this returned expression
| | | |
| requirement introduced by this return type | `'static` requirement introduced here
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
| |
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) } LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }

View file

@ -8,10 +8,10 @@ LL | ss.r
| ^^^^ ...is captured and required to live as long as `'static` here | ^^^^ ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/object-lifetime-default-from-box-error.rs:14:33 --> $DIR/object-lifetime-default-from-box-error.rs:14:37
| |
LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> { LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
| ^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^^^^^^^ `'static` requirement introduced here
... ...
LL | ss.r LL | ss.r
| ---- because of this returned expression | ---- because of this returned expression

View file

@ -24,10 +24,10 @@ LL | Box::new(v)
| ^ ...is captured and required to live as long as `'static` here | ^ ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/region-object-lifetime-in-coercion.rs:12:19 --> $DIR/region-object-lifetime-in-coercion.rs:12:33
| |
LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> { LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
| ^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
LL | Box::new(v) LL | Box::new(v)
| ----------- because of this returned expression | ----------- because of this returned expression
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
@ -49,10 +49,10 @@ LL | Box::new(v)
| ^ ...is captured and required to live as long as `'static` here | ^ ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/region-object-lifetime-in-coercion.rs:16:19 --> $DIR/region-object-lifetime-in-coercion.rs:16:23
| |
LL | fn c(v: &[u8]) -> Box<dyn Foo> { LL | fn c(v: &[u8]) -> Box<dyn Foo> {
| ^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
... ...
LL | Box::new(v) LL | Box::new(v)
| ----------- because of this returned expression | ----------- because of this returned expression

View file

@ -7,10 +7,10 @@ LL | Box::new(B(&*v)) as Box<dyn X>
| ^^^ ...is captured and required to live as long as `'static` here | ^^^ ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/regions-close-object-into-object-2.rs:8:48 --> $DIR/regions-close-object-into-object-2.rs:8:60
| |
LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> { LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
| ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
LL | Box::new(B(&*v)) as Box<dyn X> LL | Box::new(B(&*v)) as Box<dyn X>
| ------------------------------ because of this returned expression | ------------------------------ because of this returned expression
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`

View file

@ -7,10 +7,10 @@ LL | Box::new(B(&*v)) as Box<dyn X>
| ^^^ ...is captured and required to live as long as `'static` here | ^^^ ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/regions-close-object-into-object-4.rs:8:40 --> $DIR/regions-close-object-into-object-4.rs:8:52
| |
LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
| ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
LL | Box::new(B(&*v)) as Box<dyn X> LL | Box::new(B(&*v)) as Box<dyn X>
| ------------------------------ because of this returned expression | ------------------------------ because of this returned expression
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`

View file

@ -8,10 +8,10 @@ LL | Box::new(move || { *x })
| ^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here | ^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/regions-proc-bound-capture.rs:7:30 --> $DIR/regions-proc-bound-capture.rs:7:59
| |
LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> { LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
LL | // This is illegal, because the region bound on `proc` is 'static. LL | // This is illegal, because the region bound on `proc` is 'static.
LL | Box::new(move || { *x }) LL | Box::new(move || { *x })
| ------------------------ because of this returned expression | ------------------------ because of this returned expression

View file

@ -47,10 +47,10 @@ note: ...and is required to live as long as `'static` here
LL | y.get_b() // ERROR LL | y.get_b() // ERROR
| ^^^^^^^^^ | ^^^^^^^^^
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/type-checking-test-4.rs:26:40 --> $DIR/type-checking-test-4.rs:26:48
| |
LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
| ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
... ...
LL | y.get_b() // ERROR LL | y.get_b() // ERROR
| --------- because of this returned expression | --------- because of this returned expression
@ -64,10 +64,10 @@ LL | <_ as Bar>::get_b(x) // ERROR
| ^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here | ^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/type-checking-test-4.rs:32:40 --> $DIR/type-checking-test-4.rs:32:48
| |
LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
| ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
LL | <_ as Bar>::get_b(x) // ERROR LL | <_ as Bar>::get_b(x) // ERROR
| -------------------- because of this returned expression | -------------------- because of this returned expression
@ -80,10 +80,10 @@ LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR
| ----------^^------------- ...is captured and required to live as long as `'static` here | ----------^^------------- ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/type-checking-test-4.rs:37:40 --> $DIR/type-checking-test-4.rs:37:48
| |
LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
| ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR
| ---------------------------- because of this returned expression | ---------------------------- because of this returned expression
@ -109,10 +109,10 @@ note: ...and is required to live as long as `'static` here
LL | z.get_b() // ERROR LL | z.get_b() // ERROR
| ^^^^^^^^^ | ^^^^^^^^^
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/type-checking-test-4.rs:42:40 --> $DIR/type-checking-test-4.rs:42:48
| |
LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
| ^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^ `'static` requirement introduced here
... ...
LL | z.get_b() // ERROR LL | z.get_b() // ERROR
| --------- because of this returned expression | --------- because of this returned expression

View file

@ -10,10 +10,10 @@ LL | Box::new(items.iter())
| ...is captured and required to live as long as `'static` here | ...is captured and required to live as long as `'static` here
| |
note: `'static` lifetime requirement introduced by the return type note: `'static` lifetime requirement introduced by the return type
--> $DIR/dyn-trait-underscore.rs:6:25 --> $DIR/dyn-trait-underscore.rs:6:29
| |
LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type | ^^^^^^^^^^^^^^^^^^^^^ `'static` requirement introduced here
LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
LL | Box::new(items.iter()) LL | Box::new(items.iter())
| ---------------------- because of this returned expression | ---------------------- because of this returned expression