11//! Error Reporting for static impl Traits.
22
3- use crate :: infer:: error_reporting:: msg_span_from_free_region;
43use crate :: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
54use 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 } ;
77use rustc_middle:: ty:: RegionKind ;
88
99impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
1010 /// Print the error message for lifetime errors when the return type is a static impl Trait.
1111 pub ( super ) fn try_report_static_impl_trait ( & self ) -> Option < ErrorReported > {
12+ debug ! ( "try_report_static_impl_trait(error={:?})" , self . error) ;
1213 if let Some ( ref error) = self . error {
1314 if let RegionResolutionError :: SubSupConflict (
1415 _,
@@ -17,18 +18,36 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
1718 sub_r,
1819 sup_origin,
1920 sup_r,
20- ) = error. clone ( )
21+ ) = error
2122 {
23+ debug ! (
24+ "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})" ,
25+ var_origin, sub_origin, sub_r, sup_origin, sup_r
26+ ) ;
2227 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 {
2632 let sp = var_origin. span ( ) ;
2733 let return_sp = sub_origin. span ( ) ;
28- let mut err =
29- self . tcx ( ) . sess . struct_span_err ( sp, "cannot infer an appropriate lifetime" ) ;
3034 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) ;
3251
3352 // We try to make the output have fewer overlapping spans if possible.
3453 if ( sp == sup_origin. span ( ) || !return_sp. overlaps ( sup_origin. span ( ) ) )
@@ -38,41 +57,146 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
3857
3958 // Customize the spans and labels depending on their relative order so
4059 // 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+ ) ;
4480 } 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+ }
4793 }
4894 } else {
4995 err. span_label (
5096 return_sp,
51- "...is captured and required to be `'static` here" ,
97+ "...is captured and required to live as long as `'static` here" ,
5298 ) ;
5399 }
54100
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 ( ) } ;
59101 // only apply this suggestion onto functions with
60102 // 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 ( ) {
69104 // 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+ }
76200 }
77201 err. emit ( ) ;
78202 return Some ( ErrorReported ) ;
0 commit comments