@@ -8,7 +8,7 @@ use crate::{PathResult, PathSource, Segment};
8
8
use rustc_hir:: def:: Namespace :: { self , * } ;
9
9
10
10
use rustc_ast:: ptr:: P ;
11
- use rustc_ast:: visit:: { FnCtxt , FnKind , LifetimeCtxt } ;
11
+ use rustc_ast:: visit:: { walk_ty , FnCtxt , FnKind , LifetimeCtxt , Visitor } ;
12
12
use rustc_ast:: {
13
13
self as ast, AssocItemKind , Expr , ExprKind , GenericParam , GenericParamKind , Item , ItemKind ,
14
14
MethodCall , NodeId , Path , Ty , TyKind , DUMMY_NODE_ID ,
@@ -2811,6 +2811,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2811
2811
. collect ( ) ;
2812
2812
debug ! ( ?in_scope_lifetimes) ;
2813
2813
2814
+ let mut maybe_static = false ;
2814
2815
debug ! ( ?function_param_lifetimes) ;
2815
2816
if let Some ( ( param_lifetimes, params) ) = & function_param_lifetimes {
2816
2817
let elided_len = param_lifetimes. len ( ) ;
@@ -2849,9 +2850,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2849
2850
2850
2851
if num_params == 0 {
2851
2852
err. help (
2852
- "this function's return type contains a borrowed value, \
2853
- but there is no value for it to be borrowed from",
2853
+ "this function's return type contains a borrowed value, but there is no value \
2854
+ for it to be borrowed from",
2854
2855
) ;
2856
+ maybe_static = true ;
2855
2857
if in_scope_lifetimes. is_empty ( ) {
2856
2858
in_scope_lifetimes = vec ! [ (
2857
2859
Ident :: with_dummy_span( kw:: StaticLifetime ) ,
@@ -2860,10 +2862,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2860
2862
}
2861
2863
} else if elided_len == 0 {
2862
2864
err. help (
2863
- "this function's return type contains a borrowed value with \
2864
- an elided lifetime, but the lifetime cannot be derived from \
2865
- the arguments",
2865
+ "this function's return type contains a borrowed value with an elided \
2866
+ lifetime, but the lifetime cannot be derived from the arguments",
2866
2867
) ;
2868
+ maybe_static = true ;
2867
2869
if in_scope_lifetimes. is_empty ( ) {
2868
2870
in_scope_lifetimes = vec ! [ (
2869
2871
Ident :: with_dummy_span( kw:: StaticLifetime ) ,
@@ -2872,13 +2874,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2872
2874
}
2873
2875
} else if num_params == 1 {
2874
2876
err. help ( format ! (
2875
- "this function's return type contains a borrowed value, \
2876
- but the signature does not say which {m} it is borrowed from"
2877
+ "this function's return type contains a borrowed value, but the signature does \
2878
+ not say which {m} it is borrowed from",
2877
2879
) ) ;
2878
2880
} else {
2879
2881
err. help ( format ! (
2880
- "this function's return type contains a borrowed value, \
2881
- but the signature does not say whether it is borrowed from {m}"
2882
+ "this function's return type contains a borrowed value, but the signature does \
2883
+ not say whether it is borrowed from {m}",
2882
2884
) ) ;
2883
2885
}
2884
2886
}
@@ -2943,11 +2945,107 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2943
2945
) ;
2944
2946
}
2945
2947
1 => {
2948
+ let post = if maybe_static {
2949
+ let owned = if let [ lt] = & lifetime_refs[ ..]
2950
+ && lt. kind != MissingLifetimeKind :: Ampersand
2951
+ {
2952
+ ", or if you will only have owned values"
2953
+ } else {
2954
+ ""
2955
+ } ;
2956
+ format ! (
2957
+ ", but this is uncommon unless you're returning a borrowed value from a \
2958
+ `const` or a `static`{owned}",
2959
+ )
2960
+ } else {
2961
+ String :: new ( )
2962
+ } ;
2946
2963
err. multipart_suggestion_verbose (
2947
- format ! ( "consider using the `{existing_name}` lifetime" ) ,
2964
+ format ! ( "consider using the `{existing_name}` lifetime{post} " ) ,
2948
2965
spans_suggs,
2949
2966
Applicability :: MaybeIncorrect ,
2950
2967
) ;
2968
+ if maybe_static {
2969
+ // FIXME: what follows are general suggestions, but we'd want to perform some
2970
+ // minimal flow analysis to provide more accurate suggestions. For example, if
2971
+ // we identified that the return expression references only one argument, we
2972
+ // would suggest borrowing only that argument, and we'd skip the prior
2973
+ // "use `'static`" suggestion entirely.
2974
+ if let [ lt] = & lifetime_refs[ ..] && lt. kind == MissingLifetimeKind :: Ampersand {
2975
+ let pre = if let Some ( ( kind, _span) ) =
2976
+ self . diagnostic_metadata . current_function
2977
+ && let FnKind :: Fn ( _, _, sig, _, _, _) = kind
2978
+ && !sig. decl . inputs . is_empty ( )
2979
+ && let sugg = sig
2980
+ . decl
2981
+ . inputs
2982
+ . iter ( )
2983
+ . filter_map ( |param| {
2984
+ if param. ty . span . contains ( lt. span ) {
2985
+ // We don't want to suggest `fn elision(_: &fn() -> &i32)`
2986
+ // when we have `fn elision(_: fn() -> &i32)`
2987
+ None
2988
+ } else if let TyKind :: CVarArgs = param. ty . kind {
2989
+ // Don't suggest `&...` for ffi fn with varargs
2990
+ None
2991
+ } else {
2992
+ Some ( ( param. ty . span . shrink_to_lo ( ) , "&" . to_string ( ) ) )
2993
+ }
2994
+ } )
2995
+ . collect :: < Vec < _ > > ( )
2996
+ && !sugg. is_empty ( )
2997
+ {
2998
+
2999
+ let ( the, s) = if sig. decl . inputs . len ( ) == 1 {
3000
+ ( "the" , "" )
3001
+ } else {
3002
+ ( "one of the" , "s" )
3003
+ } ;
3004
+ err. multipart_suggestion_verbose (
3005
+ format ! (
3006
+ "instead, you are more likely to want to change {the} \
3007
+ argument{s} to be borrowed...",
3008
+ ) ,
3009
+ sugg,
3010
+ Applicability :: MaybeIncorrect ,
3011
+ ) ;
3012
+ "...or alternatively,"
3013
+ } else {
3014
+ "instead, you are more likely"
3015
+ } ;
3016
+ let mut sugg = vec ! [ ( lt. span, String :: new( ) ) ] ;
3017
+ if let Some ( ( kind, _span) ) =
3018
+ self . diagnostic_metadata . current_function
3019
+ && let FnKind :: Fn ( _, _, sig, _, _, _) = kind
3020
+ && let ast:: FnRetTy :: Ty ( ty) = & sig. decl . output
3021
+ {
3022
+ let mut lt_finder = LifetimeFinder { lifetime : lt. span , found : None } ;
3023
+ lt_finder. visit_ty ( & ty) ;
3024
+
3025
+ if let Some ( ty) = lt_finder. found {
3026
+ if let TyKind :: Path ( None , Path { segments, .. } ) = & ty. kind
3027
+ && segments. len ( ) == 1
3028
+ && segments[ 0 ] . ident . name == sym:: str
3029
+ {
3030
+ // Don't suggest `-> str`, suggest `-> String`.
3031
+ sugg = vec ! [ ( lt. span. with_hi( ty. span. hi( ) ) , "String" . to_string( ) ) ] ;
3032
+ }
3033
+ if let TyKind :: Slice ( inner_ty) = & ty. kind {
3034
+ // Don't suggest `-> [T]`, suggest `-> Vec<T>`.
3035
+ sugg = vec ! [
3036
+ ( lt. span. with_hi( inner_ty. span. lo( ) ) , "Vec<" . to_string( ) ) ,
3037
+ ( ty. span. with_lo( inner_ty. span. hi( ) ) , ">" . to_string( ) ) ,
3038
+ ] ;
3039
+ }
3040
+ }
3041
+ } ;
3042
+ err. multipart_suggestion_verbose (
3043
+ format ! ( "{pre} to want to return an owned value" ) ,
3044
+ sugg,
3045
+ Applicability :: MaybeIncorrect ,
3046
+ ) ;
3047
+ }
3048
+ }
2951
3049
2952
3050
// Record as using the suggested resolution.
2953
3051
let ( _, ( _, res) ) = in_scope_lifetimes[ 0 ] ;
@@ -2977,7 +3075,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
2977
3075
fn mk_where_bound_predicate (
2978
3076
path : & Path ,
2979
3077
poly_trait_ref : & ast:: PolyTraitRef ,
2980
- ty : & ast :: Ty ,
3078
+ ty : & Ty ,
2981
3079
) -> Option < ast:: WhereBoundPredicate > {
2982
3080
use rustc_span:: DUMMY_SP ;
2983
3081
let modified_segments = {
@@ -3054,6 +3152,22 @@ pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: I
3054
3152
err. emit ( ) ;
3055
3153
}
3056
3154
3155
+ struct LifetimeFinder < ' ast > {
3156
+ lifetime : Span ,
3157
+ found : Option < & ' ast Ty > ,
3158
+ }
3159
+
3160
+ impl < ' ast > Visitor < ' ast > for LifetimeFinder < ' ast > {
3161
+ fn visit_ty ( & mut self , t : & ' ast Ty ) {
3162
+ if t. span . lo ( ) == self . lifetime . lo ( )
3163
+ && let TyKind :: Ref ( _, mut_ty) = & t. kind
3164
+ {
3165
+ self . found = Some ( & mut_ty. ty ) ;
3166
+ }
3167
+ walk_ty ( self , t)
3168
+ }
3169
+ }
3170
+
3057
3171
/// Shadowing involving a label is only a warning for historical reasons.
3058
3172
//FIXME: make this a proper lint.
3059
3173
pub ( super ) fn signal_label_shadowing ( sess : & Session , orig : Span , shadower : Ident ) {
0 commit comments