1
1
//! Error Reporting for static impl Traits.
2
2
3
- use crate :: infer:: error_reporting:: msg_span_from_free_region;
4
3
use crate :: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
5
4
use crate :: infer:: lexical_region_resolve:: RegionResolutionError ;
6
- use rustc_errors:: { Applicability , ErrorReported } ;
5
+ use rustc_errors:: { struct_span_err, Applicability , ErrorReported } ;
6
+ use rustc_hir:: { GenericBound , ItemKind , Lifetime , LifetimeName , TyKind } ;
7
7
use rustc_middle:: ty:: RegionKind ;
8
8
9
9
impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
10
10
/// Print the error message for lifetime errors when the return type is a static impl Trait.
11
11
pub ( super ) fn try_report_static_impl_trait ( & self ) -> Option < ErrorReported > {
12
+ debug ! ( "try_report_static_impl_trait(error={:?})" , self . error) ;
12
13
if let Some ( ref error) = self . error {
13
14
if let RegionResolutionError :: SubSupConflict (
14
15
_,
@@ -17,18 +18,36 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
17
18
sub_r,
18
19
sup_origin,
19
20
sup_r,
20
- ) = error. clone ( )
21
+ ) = error
21
22
{
23
+ debug ! (
24
+ "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})" ,
25
+ var_origin, sub_origin, sub_r, sup_origin, sup_r
26
+ ) ;
22
27
let anon_reg_sup = self . tcx ( ) . is_suitable_region ( sup_r) ?;
23
- let ( fn_return_span, is_dyn) =
24
- self . tcx ( ) . return_type_impl_or_dyn_trait ( anon_reg_sup. def_id ) ?;
25
- if sub_r == & RegionKind :: ReStatic {
28
+ debug ! ( "try_report_static_impl_trait: anon_reg_sup={:?}" , anon_reg_sup) ;
29
+ let fn_return = self . tcx ( ) . return_type_impl_or_dyn_trait ( anon_reg_sup. def_id ) ?;
30
+ debug ! ( "try_report_static_impl_trait: fn_return={:?}" , fn_return) ;
31
+ if * * sub_r == RegionKind :: ReStatic {
26
32
let sp = var_origin. span ( ) ;
27
33
let return_sp = sub_origin. span ( ) ;
28
- let mut err =
29
- self . tcx ( ) . sess . struct_span_err ( sp, "cannot infer an appropriate lifetime" ) ;
30
34
let param_info = self . find_param_with_region ( sup_r, sub_r) ?;
31
- err. span_label ( param_info. param_ty_span , "data with this lifetime..." ) ;
35
+ let ( lifetime_name, lifetime) = if sup_r. has_name ( ) {
36
+ ( sup_r. to_string ( ) , format ! ( "lifetime `{}`" , sup_r) )
37
+ } else {
38
+ ( "'_" . to_owned ( ) , "an anonymous lifetime `'_`" . to_string ( ) )
39
+ } ;
40
+ let mut err = struct_span_err ! (
41
+ self . tcx( ) . sess,
42
+ sp,
43
+ E0759 ,
44
+ "cannot infer an appropriate lifetime"
45
+ ) ;
46
+ err. span_label (
47
+ param_info. param_ty_span ,
48
+ & format ! ( "this data with {}..." , lifetime) ,
49
+ ) ;
50
+ debug ! ( "try_report_static_impl_trait: param_info={:?}" , param_info) ;
32
51
33
52
// We try to make the output have fewer overlapping spans if possible.
34
53
if ( sp == sup_origin. span ( ) || !return_sp. overlaps ( sup_origin. span ( ) ) )
@@ -38,41 +57,146 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
38
57
39
58
// Customize the spans and labels depending on their relative order so
40
59
// that split sentences flow correctly.
41
- if sup_origin. span ( ) . shrink_to_hi ( ) <= return_sp. shrink_to_lo ( ) {
42
- err. span_label ( sup_origin. span ( ) , "...is captured here..." ) ;
43
- err. span_label ( return_sp, "...and required to be `'static` by this" ) ;
60
+ if sup_origin. span ( ) . overlaps ( return_sp) && sp == sup_origin. span ( ) {
61
+ // Avoid the following:
62
+ //
63
+ // error: cannot infer an appropriate lifetime
64
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
65
+ // |
66
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
67
+ // | ---- ---------^-
68
+ //
69
+ // and instead show:
70
+ //
71
+ // error: cannot infer an appropriate lifetime
72
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
73
+ // |
74
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
75
+ // | ---- ^
76
+ err. span_label (
77
+ sup_origin. span ( ) ,
78
+ "...is captured here, requiring it to live as long as `'static`" ,
79
+ ) ;
44
80
} else {
45
- err. span_label ( return_sp, "...is required to be `'static` by this..." ) ;
46
- err. span_label ( sup_origin. span ( ) , "...and is captured here" ) ;
81
+ err. span_label ( sup_origin. span ( ) , "...is captured here..." ) ;
82
+ if return_sp < sup_origin. span ( ) {
83
+ err. span_note (
84
+ return_sp,
85
+ "...and is required to live as long as `'static` here" ,
86
+ ) ;
87
+ } else {
88
+ err. span_label (
89
+ return_sp,
90
+ "...and is required to live as long as `'static` here" ,
91
+ ) ;
92
+ }
47
93
}
48
94
} else {
49
95
err. span_label (
50
96
return_sp,
51
- "...is captured and required to be `'static` here" ,
97
+ "...is captured and required to live as long as `'static` here" ,
52
98
) ;
53
99
}
54
100
55
- let ( lifetime, _) = msg_span_from_free_region ( self . tcx ( ) , sup_r) ;
56
-
57
- let lifetime_name =
58
- if sup_r. has_name ( ) { sup_r. to_string ( ) } else { "'_" . to_owned ( ) } ;
59
101
// only apply this suggestion onto functions with
60
102
// explicit non-desugar'able return.
61
- if fn_return_span. desugaring_kind ( ) . is_none ( ) {
62
- let msg = format ! (
63
- "to permit non-static references in {} `{} Trait` value, you can add \
64
- an explicit bound for {}",
65
- if is_dyn { "a" } else { "an" } ,
66
- if is_dyn { "dyn" } else { "impl" } ,
67
- lifetime,
68
- ) ;
103
+ if fn_return. span . desugaring_kind ( ) . is_none ( ) {
69
104
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
70
- err. span_suggestion_verbose (
71
- fn_return_span. shrink_to_hi ( ) ,
72
- & msg,
73
- format ! ( " + {}" , lifetime_name) ,
74
- Applicability :: MaybeIncorrect ,
75
- ) ;
105
+
106
+ let consider = "consider changing the" ;
107
+ let declare = "to declare that the" ;
108
+ let arg = match param_info. param . pat . simple_ident ( ) {
109
+ Some ( simple_ident) => format ! ( "argument `{}`" , simple_ident) ,
110
+ None => "the argument" . to_string ( ) ,
111
+ } ;
112
+ let explicit =
113
+ format ! ( "you can add an explicit `{}` lifetime bound" , lifetime_name) ;
114
+ let explicit_static =
115
+ format ! ( "explicit `'static` bound to the lifetime of {}" , arg) ;
116
+ let captures = format ! ( "captures data from {}" , arg) ;
117
+ let add_static_bound =
118
+ "alternatively, add an explicit `'static` bound to this reference" ;
119
+ let plus_lt = format ! ( " + {}" , lifetime_name) ;
120
+ match fn_return. kind {
121
+ TyKind :: OpaqueDef ( item_id, _) => {
122
+ let item = self . tcx ( ) . hir ( ) . item ( item_id. id ) ;
123
+ let opaque = if let ItemKind :: OpaqueTy ( opaque) = & item. kind {
124
+ opaque
125
+ } else {
126
+ err. emit ( ) ;
127
+ return Some ( ErrorReported ) ;
128
+ } ;
129
+
130
+ if let Some ( span) = opaque
131
+ . bounds
132
+ . iter ( )
133
+ . filter_map ( |arg| match arg {
134
+ GenericBound :: Outlives ( Lifetime {
135
+ name : LifetimeName :: Static ,
136
+ span,
137
+ ..
138
+ } ) => Some ( * span) ,
139
+ _ => None ,
140
+ } )
141
+ . next ( )
142
+ {
143
+ err. span_suggestion_verbose (
144
+ span,
145
+ & format ! ( "{} `impl Trait`'s {}" , consider, explicit_static) ,
146
+ lifetime_name,
147
+ Applicability :: MaybeIncorrect ,
148
+ ) ;
149
+ err. span_suggestion_verbose (
150
+ param_info. param_ty_span ,
151
+ add_static_bound,
152
+ param_info. param_ty . to_string ( ) ,
153
+ Applicability :: MaybeIncorrect ,
154
+ ) ;
155
+ } else {
156
+ err. span_suggestion_verbose (
157
+ fn_return. span . shrink_to_hi ( ) ,
158
+ & format ! (
159
+ "{declare} `impl Trait` {captures}, {explicit}" ,
160
+ declare = declare,
161
+ captures = captures,
162
+ explicit = explicit,
163
+ ) ,
164
+ plus_lt,
165
+ Applicability :: MaybeIncorrect ,
166
+ ) ;
167
+ } ;
168
+ }
169
+ TyKind :: TraitObject ( _, lt) => match lt. name {
170
+ LifetimeName :: ImplicitObjectLifetimeDefault => {
171
+ err. span_suggestion_verbose (
172
+ fn_return. span . shrink_to_hi ( ) ,
173
+ & format ! (
174
+ "{declare} trait object {captures}, {explicit}" ,
175
+ declare = declare,
176
+ captures = captures,
177
+ explicit = explicit,
178
+ ) ,
179
+ plus_lt,
180
+ Applicability :: MaybeIncorrect ,
181
+ ) ;
182
+ }
183
+ _ => {
184
+ err. span_suggestion_verbose (
185
+ lt. span ,
186
+ & format ! ( "{} trait object's {}" , consider, explicit_static) ,
187
+ lifetime_name,
188
+ Applicability :: MaybeIncorrect ,
189
+ ) ;
190
+ err. span_suggestion_verbose (
191
+ param_info. param_ty_span ,
192
+ add_static_bound,
193
+ param_info. param_ty . to_string ( ) ,
194
+ Applicability :: MaybeIncorrect ,
195
+ ) ;
196
+ }
197
+ } ,
198
+ _ => { }
199
+ }
76
200
}
77
201
err. emit ( ) ;
78
202
return Some ( ErrorReported ) ;
0 commit comments