10
10
11
11
use middle:: infer;
12
12
use middle:: traits;
13
- use middle:: ty:: { mod } ;
14
- use middle:: subst:: { mod , Subst , VecPerParamSpace } ;
15
- use util:: ppaux:: { mod , Repr } ;
13
+ use middle:: ty:: { self } ;
14
+ use middle:: subst:: { self , Subst , Substs , VecPerParamSpace } ;
15
+ use util:: ppaux:: { self , Repr , UserString } ;
16
16
17
17
use syntax:: ast;
18
18
use syntax:: codemap:: { Span } ;
@@ -171,9 +171,6 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
171
171
//
172
172
// Finally we register each of these predicates as an obligation in
173
173
// a fresh FulfillmentCtxt, and invoke select_all_or_error.
174
- //
175
- // FIXME(jroesch): Currently the error reporting is not correctly attached
176
- // to a span and results in terrible error reporting.
177
174
178
175
// Create a parameter environment that represents the implementation's
179
176
// method.
@@ -192,6 +189,18 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
192
189
debug ! ( "compare_impl_method: trait_to_skol_substs={}" ,
193
190
trait_to_skol_substs. repr( tcx) ) ;
194
191
192
+ // Check region bounds. FIXME(@jroesch) refactor this away when removing
193
+ // ParamBounds.
194
+ if !check_region_bounds_on_impl_method ( tcx,
195
+ impl_m_span,
196
+ impl_m,
197
+ & trait_m. generics ,
198
+ & impl_m. generics ,
199
+ & trait_to_skol_substs,
200
+ impl_to_skol_substs) {
201
+ return ;
202
+ }
203
+
195
204
// Create obligations for each predicate declared by the impl
196
205
// definition in the context of the trait's parameter
197
206
// environment. We can't just use `impl_env.caller_bounds`,
@@ -208,7 +217,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
208
217
debug ! ( "compare_impl_method: impl_bounds={}" ,
209
218
impl_bounds. repr( tcx) ) ;
210
219
211
- let mut selcx = traits:: SelectionContext :: new ( & infcx, & impl_param_env, tcx ) ;
220
+ let mut selcx = traits:: SelectionContext :: new ( & infcx, & impl_param_env) ;
212
221
213
222
let normalize_cause =
214
223
traits:: ObligationCause :: misc ( impl_m_span, impl_m_body_id) ;
@@ -260,6 +269,19 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
260
269
traits:: Obligation :: new ( cause, predicate) ) ;
261
270
}
262
271
272
+ // We now need to check that the signature of the impl method is
273
+ // compatible with that of the trait method. We do this by
274
+ // checking that `impl_fty <: trait_fty`.
275
+ //
276
+ // FIXME. Unfortunately, this doesn't quite work right now because
277
+ // associated type normalization is not integrated into subtype
278
+ // checks. For the comparison to be valid, we need to
279
+ // normalize the associated types in the impl/trait methods
280
+ // first. However, because function types bind regions, just
281
+ // calling `normalize_associated_types_in` would have no effect on
282
+ // any associated types appearing in the fn arguments or return
283
+ // type.
284
+
263
285
// Compute skolemized form of impl and trait method tys.
264
286
let impl_fty = ty:: mk_bare_fn ( tcx, None , tcx. mk_bare_fn ( impl_m. fty . clone ( ) ) ) ;
265
287
let impl_fty = impl_fty. subst ( tcx, impl_to_skol_substs) ;
@@ -271,28 +293,25 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
271
293
272
294
let ( impl_sig, _) =
273
295
infcx. replace_late_bound_regions_with_fresh_var ( impl_m_span,
274
- infer:: HigherRankedType ,
275
- & impl_m. fty . sig ) ;
276
-
296
+ infer:: HigherRankedType ,
297
+ & impl_m. fty . sig ) ;
277
298
let impl_sig =
278
299
impl_sig. subst ( tcx, impl_to_skol_substs) ;
279
300
let impl_sig =
280
301
assoc:: normalize_associated_types_in ( & infcx,
281
302
& impl_param_env,
282
- infcx. tcx ,
283
303
& mut fulfillment_cx,
284
304
impl_m_span,
285
305
impl_m_body_id,
286
306
& impl_sig) ;
287
307
let impl_fty =
288
308
ty:: mk_bare_fn ( tcx,
289
309
None ,
290
- tcx. mk_bare_fn ( ty:: BareFnTy {
291
- unsafety : impl_m. fty . unsafety ,
292
- abi : impl_m. fty . abi ,
293
- sig : ty:: Binder ( impl_sig) } ) ) ;
294
- debug ! ( "compare_impl_method: impl_fty={}" ,
295
- impl_fty. repr( tcx) ) ;
310
+ tcx. mk_bare_fn ( ty:: BareFnTy { unsafety : impl_m. fty . unsafety ,
311
+ abi : impl_m. fty . abi ,
312
+ sig : ty:: Binder ( impl_sig) } ) ) ;
313
+ debug ! ( "compare_impl_method: impl_fty={}" ,
314
+ impl_fty. repr( tcx) ) ;
296
315
297
316
let ( trait_sig, skol_map) =
298
317
infcx. skolemize_late_bound_regions ( & trait_m. fty . sig , snapshot) ;
@@ -301,46 +320,164 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
301
320
let trait_sig =
302
321
assoc:: normalize_associated_types_in ( & infcx,
303
322
& impl_param_env,
304
- infcx. tcx ,
305
323
& mut fulfillment_cx,
306
324
impl_m_span,
307
325
impl_m_body_id,
308
326
& trait_sig) ;
309
327
let trait_fty =
310
328
ty:: mk_bare_fn ( tcx,
311
329
None ,
312
- tcx. mk_bare_fn ( ty:: BareFnTy {
313
- unsafety : trait_m. fty . unsafety ,
314
- abi : trait_m. fty . abi ,
315
- sig : ty:: Binder ( trait_sig) } ) ) ;
330
+ tcx. mk_bare_fn ( ty:: BareFnTy { unsafety : trait_m. fty . unsafety ,
331
+ abi : trait_m. fty . abi ,
332
+ sig : ty:: Binder ( trait_sig) } ) ) ;
333
+
334
+ debug ! ( "compare_impl_method: trait_fty={}" ,
335
+ trait_fty. repr( tcx) ) ;
316
336
317
- debug ! ( "compare_impl_method: trait_fty={}" , trait_fty. repr( tcx) ) ;
318
337
try!( infer:: mk_subty ( & infcx, false , origin, impl_fty, trait_fty) ) ;
338
+
319
339
infcx. leak_check ( & skol_map, snapshot)
320
340
} ) ;
321
341
322
342
match err {
323
343
Ok ( ( ) ) => { }
324
344
Err ( terr) => {
325
345
debug ! ( "checking trait method for compatibility: impl ty {}, trait ty {}" ,
326
- impl_fty. repr( tcx) ,
327
- trait_fty. repr( tcx) ) ;
328
- span_err ! ( tcx. sess, impl_m_span, E0053 ,
329
- "method `{}` has an incompatible type for trait: {}" ,
330
- token:: get_name( trait_m. name) ,
331
- ty:: type_err_to_str( tcx, & terr) ) ;
332
- return ;
346
+ impl_fty. repr( tcx) ,
347
+ trait_fty. repr( tcx) ) ;
348
+ span_err ! ( tcx. sess, impl_m_span, E0053 ,
349
+ "method `{}` has an incompatible type for trait: {}" ,
350
+ token:: get_name( trait_m. name) ,
351
+ ty:: type_err_to_str( tcx, & terr) ) ;
352
+ return ;
333
353
}
334
354
}
335
355
336
356
// Check that all obligations are satisfied by the implementation's
337
357
// version.
338
- match fulfillment_cx. select_all_or_error ( & infcx, & trait_param_env, tcx ) {
358
+ match fulfillment_cx. select_all_or_error ( & infcx, & trait_param_env) {
339
359
Err ( ref errors) => { traits:: report_fulfillment_errors ( & infcx, errors) }
340
360
Ok ( _) => { }
341
361
}
342
362
343
363
// Finally, resolve all regions. This catches wily misuses of lifetime
344
364
// parameters.
345
365
infcx. resolve_regions_and_report_errors ( impl_m_body_id) ;
366
+
367
+ fn check_region_bounds_on_impl_method < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
368
+ span : Span ,
369
+ impl_m : & ty:: Method < ' tcx > ,
370
+ trait_generics : & ty:: Generics < ' tcx > ,
371
+ impl_generics : & ty:: Generics < ' tcx > ,
372
+ trait_to_skol_substs : & Substs < ' tcx > ,
373
+ impl_to_skol_substs : & Substs < ' tcx > )
374
+ -> bool
375
+ {
376
+
377
+ let trait_params = trait_generics. regions . get_slice ( subst:: FnSpace ) ;
378
+ let impl_params = impl_generics. regions . get_slice ( subst:: FnSpace ) ;
379
+
380
+ debug ! ( "check_region_bounds_on_impl_method: \
381
+ trait_generics={} \
382
+ impl_generics={} \
383
+ trait_to_skol_substs={} \
384
+ impl_to_skol_substs={}",
385
+ trait_generics. repr( tcx) ,
386
+ impl_generics. repr( tcx) ,
387
+ trait_to_skol_substs. repr( tcx) ,
388
+ impl_to_skol_substs. repr( tcx) ) ;
389
+
390
+ // Must have same number of early-bound lifetime parameters.
391
+ // Unfortunately, if the user screws up the bounds, then this
392
+ // will change classification between early and late. E.g.,
393
+ // if in trait we have `<'a,'b:'a>`, and in impl we just have
394
+ // `<'a,'b>`, then we have 2 early-bound lifetime parameters
395
+ // in trait but 0 in the impl. But if we report "expected 2
396
+ // but found 0" it's confusing, because it looks like there
397
+ // are zero. Since I don't quite know how to phrase things at
398
+ // the moment, give a kind of vague error message.
399
+ if trait_params. len ( ) != impl_params. len ( ) {
400
+ tcx. sess . span_err (
401
+ span,
402
+ format ! ( "lifetime parameters or bounds on method `{}` do \
403
+ not match the trait declaration",
404
+ token:: get_name( impl_m. name) ) [ ] ) ;
405
+ return false ;
406
+ }
407
+
408
+ // Each parameter `'a:'b+'c+'d` in trait should have the same
409
+ // set of bounds in the impl, after subst.
410
+ for ( trait_param, impl_param) in
411
+ trait_params. iter ( ) . zip (
412
+ impl_params. iter ( ) )
413
+ {
414
+ let trait_bounds =
415
+ trait_param. bounds . subst ( tcx, trait_to_skol_substs) ;
416
+ let impl_bounds =
417
+ impl_param. bounds . subst ( tcx, impl_to_skol_substs) ;
418
+
419
+ debug ! ( "check_region_bounds_on_impl_method: \
420
+ trait_param={} \
421
+ impl_param={} \
422
+ trait_bounds={} \
423
+ impl_bounds={}",
424
+ trait_param. repr( tcx) ,
425
+ impl_param. repr( tcx) ,
426
+ trait_bounds. repr( tcx) ,
427
+ impl_bounds. repr( tcx) ) ;
428
+
429
+ // Collect the set of bounds present in trait but not in
430
+ // impl.
431
+ let missing: Vec < ty:: Region > =
432
+ trait_bounds. iter ( )
433
+ . filter ( |& b| !impl_bounds. contains ( b) )
434
+ . map ( |& b| b)
435
+ . collect ( ) ;
436
+
437
+ // Collect set present in impl but not in trait.
438
+ let extra: Vec < ty:: Region > =
439
+ impl_bounds. iter ( )
440
+ . filter ( |& b| !trait_bounds. contains ( b) )
441
+ . map ( |& b| b)
442
+ . collect ( ) ;
443
+
444
+ debug ! ( "missing={} extra={}" ,
445
+ missing. repr( tcx) , extra. repr( tcx) ) ;
446
+
447
+ let err = if missing. len ( ) != 0 || extra. len ( ) != 0 {
448
+ tcx. sess . span_err (
449
+ span,
450
+ format ! (
451
+ "the lifetime parameter `{}` declared in the impl \
452
+ has a distinct set of bounds \
453
+ from its counterpart `{}` \
454
+ declared in the trait",
455
+ impl_param. name. user_string( tcx) ,
456
+ trait_param. name. user_string( tcx) ) [ ] ) ;
457
+ true
458
+ } else {
459
+ false
460
+ } ;
461
+
462
+ if missing. len ( ) != 0 {
463
+ tcx. sess . span_note (
464
+ span,
465
+ format ! ( "the impl is missing the following bounds: `{}`" ,
466
+ missing. user_string( tcx) ) [ ] ) ;
467
+ }
468
+
469
+ if extra. len ( ) != 0 {
470
+ tcx. sess . span_note (
471
+ span,
472
+ format ! ( "the impl has the following extra bounds: `{}`" ,
473
+ extra. user_string( tcx) ) [ ] ) ;
474
+ }
475
+
476
+ if err {
477
+ return false ;
478
+ }
479
+ }
480
+
481
+ return true ;
482
+ }
346
483
}
0 commit comments