@@ -59,18 +59,19 @@ use middle::subst::{VecPerParamSpace};
5959use middle:: ty;
6060use middle:: typeck:: lookup_def_tcx;
6161use middle:: typeck:: infer;
62- use middle:: typeck:: rscope:: { ExplicitRscope , RegionScope , SpecificRscope } ;
62+ use middle:: typeck:: rscope:: { UnelidableRscope , RegionScope , SpecificRscope } ;
6363use middle:: typeck:: rscope;
6464use middle:: typeck:: TypeAndSubsts ;
6565use middle:: typeck;
6666use util:: ppaux:: { Repr , UserString } ;
6767
6868use std:: collections:: HashMap ;
6969use std:: rc:: Rc ;
70- use syntax :: abi ;
71- use syntax:: { ast, ast_util} ;
70+ use std :: iter :: AdditiveIterator ;
71+ use syntax:: { abi , ast, ast_util} ;
7272use syntax:: codemap:: Span ;
7373use syntax:: parse:: token;
74+ use syntax:: print:: pprust;
7475
7576pub trait AstConv < ' tcx > {
7677 fn tcx < ' a > ( & ' a self ) -> & ' a ty:: ctxt < ' tcx > ;
@@ -147,10 +148,49 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
147148
148149 None => {
149150 match rscope. anon_regions ( default_span, 1 ) {
150- Err ( ( ) ) => {
151+ Err ( v ) => {
151152 debug ! ( "optional region in illegal location" ) ;
152153 span_err ! ( this. tcx( ) . sess, default_span, E0106 ,
153154 "missing lifetime specifier" ) ;
155+ match v {
156+ Some ( v) => {
157+ let mut m = String :: new ( ) ;
158+ let len = v. len ( ) ;
159+ for ( i, ( name, n) ) in v. move_iter ( ) . enumerate ( ) {
160+ m. push_str ( if n == 1 {
161+ format ! ( "`{}`" , name)
162+ } else {
163+ format ! ( "one of `{}`'s {} elided lifetimes" , name, n)
164+ } . as_slice ( ) ) ;
165+
166+ if len == 2 && i == 0 {
167+ m. push_str ( " or " ) ;
168+ } else if i == len - 2 {
169+ m. push_str ( ", or " ) ;
170+ } else if i != len - 1 {
171+ m. push_str ( ", " ) ;
172+ }
173+ }
174+ if len == 1 {
175+ span_note ! ( this. tcx( ) . sess, default_span,
176+ "this function's return type contains a borrowed value, but \
177+ the signature does not say which {} it is borrowed from",
178+ m) ;
179+ } else if len == 0 {
180+ span_note ! ( this. tcx( ) . sess, default_span,
181+ "this function's return type contains a borrowed value, but \
182+ there is no value for it to be borrowed from") ;
183+ span_note ! ( this. tcx( ) . sess, default_span,
184+ "consider giving it a 'static lifetime" ) ;
185+ } else {
186+ span_note ! ( this. tcx( ) . sess, default_span,
187+ "this function's return type contains a borrowed value, but \
188+ the signature does not say whether it is borrowed from {}",
189+ m) ;
190+ }
191+ }
192+ None => { } ,
193+ }
154194 ty:: ReStatic
155195 }
156196
@@ -217,7 +257,7 @@ fn ast_path_substs<'tcx,AC,RS>(
217257
218258 match anon_regions {
219259 Ok ( v) => v. into_iter ( ) . collect ( ) ,
220- Err ( ( ) ) => Vec :: from_fn ( expected_num_region_params,
260+ Err ( _ ) => Vec :: from_fn ( expected_num_region_params,
221261 |_| ty:: ReStatic ) // hokey
222262 }
223263 } ;
@@ -1153,15 +1193,20 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
11531193 } ;
11541194
11551195 // HACK(eddyb) replace the fake self type in the AST with the actual type.
1156- let input_tys = if self_ty. is_some ( ) {
1196+ let input_params = if self_ty. is_some ( ) {
11571197 decl. inputs . slice_from ( 1 )
11581198 } else {
11591199 decl. inputs . as_slice ( )
11601200 } ;
1161- let input_tys = input_tys. iter ( ) . map ( |a| ty_of_arg ( this, & rb, a, None ) ) ;
1162- let self_and_input_tys: Vec < _ > =
1201+ let input_tys = input_params. iter ( ) . map ( |a| ty_of_arg ( this, & rb, a, None ) ) ;
1202+ let input_pats: Vec < String > = input_params. iter ( )
1203+ . map ( |a| pprust:: pat_to_string ( & * a. pat ) )
1204+ . collect ( ) ;
1205+ let self_and_input_tys: Vec < ty:: t > =
11631206 self_ty. into_iter ( ) . chain ( input_tys) . collect ( ) ;
11641207
1208+ let mut lifetimes_for_params: Vec < ( String , Vec < ty:: Region > ) > = Vec :: new ( ) ;
1209+
11651210 // Second, if there was exactly one lifetime (either a substitution or a
11661211 // reference) in the arguments, then any anonymous regions in the output
11671212 // have that lifetime.
@@ -1172,15 +1217,25 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
11721217 drop ( self_and_input_tys_iter. next ( ) )
11731218 }
11741219
1175- let mut accumulator = Vec :: new ( ) ;
1176- for input_type in self_and_input_tys_iter {
1177- ty:: accumulate_lifetimes_in_type ( & mut accumulator, * input_type)
1220+ for ( input_type, input_pat) in self_and_input_tys_iter. zip ( input_pats. into_iter ( ) ) {
1221+ let mut accumulator = Vec :: new ( ) ;
1222+ ty:: accumulate_lifetimes_in_type ( & mut accumulator, * input_type) ;
1223+ lifetimes_for_params. push ( ( input_pat, accumulator) ) ;
11781224 }
1179- if accumulator. len ( ) == 1 {
1180- implied_output_region = Some ( * accumulator. get ( 0 ) ) ;
1225+
1226+ if lifetimes_for_params. iter ( ) . map ( |& ( _, ref x) | x. len ( ) ) . sum ( ) == 1 {
1227+ implied_output_region =
1228+ Some ( lifetimes_for_params. iter ( )
1229+ . filter_map ( |& ( _, ref x) |
1230+ if x. len ( ) == 1 { Some ( x[ 0 ] ) } else { None } )
1231+ . next ( ) . unwrap ( ) ) ;
11811232 }
11821233 }
11831234
1235+ let param_lifetimes: Vec < ( String , uint ) > = lifetimes_for_params. into_iter ( )
1236+ . map ( |( n, v) | ( n, v. len ( ) ) )
1237+ . collect ( ) ;
1238+
11841239 let output_ty = match decl. output . node {
11851240 ast:: TyInfer => this. ty_infer ( decl. output . span ) ,
11861241 _ => {
@@ -1193,7 +1248,7 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
11931248 // All regions must be explicitly specified in the output
11941249 // if the lifetime elision rules do not apply. This saves
11951250 // the user from potentially-confusing errors.
1196- let rb = ExplicitRscope ;
1251+ let rb = UnelidableRscope :: new ( param_lifetimes ) ;
11971252 ast_ty_to_ty ( this, & rb, & * decl. output )
11981253 }
11991254 }
0 commit comments