@@ -59,18 +59,19 @@ use middle::subst::{VecPerParamSpace};
59
59
use middle:: ty;
60
60
use middle:: typeck:: lookup_def_tcx;
61
61
use middle:: typeck:: infer;
62
- use middle:: typeck:: rscope:: { ExplicitRscope , RegionScope , SpecificRscope } ;
62
+ use middle:: typeck:: rscope:: { UnelidableRscope , RegionScope , SpecificRscope } ;
63
63
use middle:: typeck:: rscope;
64
64
use middle:: typeck:: TypeAndSubsts ;
65
65
use middle:: typeck;
66
66
use util:: ppaux:: { Repr , UserString } ;
67
67
68
68
use std:: collections:: HashMap ;
69
69
use 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} ;
72
72
use syntax:: codemap:: Span ;
73
73
use syntax:: parse:: token;
74
+ use syntax:: print:: pprust;
74
75
75
76
pub trait AstConv < ' tcx > {
76
77
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>(
147
148
148
149
None => {
149
150
match rscope. anon_regions ( default_span, 1 ) {
150
- Err ( ( ) ) => {
151
+ Err ( v ) => {
151
152
debug ! ( "optional region in illegal location" ) ;
152
153
span_err ! ( this. tcx( ) . sess, default_span, E0106 ,
153
154
"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
+ }
154
194
ty:: ReStatic
155
195
}
156
196
@@ -217,7 +257,7 @@ fn ast_path_substs<'tcx,AC,RS>(
217
257
218
258
match anon_regions {
219
259
Ok ( v) => v. into_iter ( ) . collect ( ) ,
220
- Err ( ( ) ) => Vec :: from_fn ( expected_num_region_params,
260
+ Err ( _ ) => Vec :: from_fn ( expected_num_region_params,
221
261
|_| ty:: ReStatic ) // hokey
222
262
}
223
263
} ;
@@ -1153,15 +1193,20 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
1153
1193
} ;
1154
1194
1155
1195
// 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 ( ) {
1157
1197
decl. inputs . slice_from ( 1 )
1158
1198
} else {
1159
1199
decl. inputs . as_slice ( )
1160
1200
} ;
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 > =
1163
1206
self_ty. into_iter ( ) . chain ( input_tys) . collect ( ) ;
1164
1207
1208
+ let mut lifetimes_for_params: Vec < ( String , Vec < ty:: Region > ) > = Vec :: new ( ) ;
1209
+
1165
1210
// Second, if there was exactly one lifetime (either a substitution or a
1166
1211
// reference) in the arguments, then any anonymous regions in the output
1167
1212
// have that lifetime.
@@ -1172,15 +1217,25 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
1172
1217
drop ( self_and_input_tys_iter. next ( ) )
1173
1218
}
1174
1219
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) ) ;
1178
1224
}
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 ( ) ) ;
1181
1232
}
1182
1233
}
1183
1234
1235
+ let param_lifetimes: Vec < ( String , uint ) > = lifetimes_for_params. into_iter ( )
1236
+ . map ( |( n, v) | ( n, v. len ( ) ) )
1237
+ . collect ( ) ;
1238
+
1184
1239
let output_ty = match decl. output . node {
1185
1240
ast:: TyInfer => this. ty_infer ( decl. output . span ) ,
1186
1241
_ => {
@@ -1193,7 +1248,7 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
1193
1248
// All regions must be explicitly specified in the output
1194
1249
// if the lifetime elision rules do not apply. This saves
1195
1250
// the user from potentially-confusing errors.
1196
- let rb = ExplicitRscope ;
1251
+ let rb = UnelidableRscope :: new ( param_lifetimes ) ;
1197
1252
ast_ty_to_ty ( this, & rb, & * decl. output )
1198
1253
}
1199
1254
}
0 commit comments