@@ -12,10 +12,9 @@ use middle::free_region::FreeRegionMap;
12
12
use rustc:: infer:: { self , InferOk , TypeOrigin } ;
13
13
use rustc:: ty;
14
14
use rustc:: traits:: { self , Reveal } ;
15
- use rustc:: ty:: error:: ExpectedFound ;
15
+ use rustc:: ty:: error:: { ExpectedFound , TypeError } ;
16
16
use rustc:: ty:: subst:: { Subst , Substs } ;
17
- use rustc:: hir:: map:: Node ;
18
- use rustc:: hir:: { ImplItemKind , TraitItem_ } ;
17
+ use rustc:: hir:: { ImplItemKind , TraitItem_ , Ty_ } ;
19
18
20
19
use syntax:: ast;
21
20
use syntax_pos:: Span ;
@@ -300,6 +299,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
300
299
impl_m_span,
301
300
impl_m_body_id,
302
301
& impl_sig) ;
302
+ let impl_args = impl_sig. inputs . clone ( ) ;
303
303
let impl_fty = tcx. mk_fn_ptr ( tcx. mk_bare_fn ( ty:: BareFnTy {
304
304
unsafety : impl_m. fty . unsafety ,
305
305
abi : impl_m. fty . abi ,
@@ -318,6 +318,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
318
318
impl_m_span,
319
319
impl_m_body_id,
320
320
& trait_sig) ;
321
+ let trait_args = trait_sig. inputs . clone ( ) ;
321
322
let trait_fty = tcx. mk_fn_ptr ( tcx. mk_bare_fn ( ty:: BareFnTy {
322
323
unsafety : trait_m. fty . unsafety ,
323
324
abi : trait_m. fty . abi ,
@@ -331,16 +332,82 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
331
332
impl_fty,
332
333
trait_fty) ;
333
334
335
+ let impl_m_iter = match tcx. map . expect_impl_item ( impl_m_node_id) . node {
336
+ ImplItemKind :: Method ( ref impl_m_sig, _) => impl_m_sig. decl . inputs . iter ( ) ,
337
+ _ => bug ! ( "{:?} is not a method" , impl_m)
338
+ } ;
339
+
340
+ let ( impl_err_span, trait_err_span) = match terr {
341
+ TypeError :: Mutability => {
342
+ if let Some ( trait_m_node_id) = tcx. map . as_local_node_id ( trait_m. def_id ) {
343
+ let trait_m_iter = match tcx. map . expect_trait_item ( trait_m_node_id) . node {
344
+ TraitItem_ :: MethodTraitItem ( ref trait_m_sig, _) =>
345
+ trait_m_sig. decl . inputs . iter ( ) ,
346
+ _ => bug ! ( "{:?} is not a MethodTraitItem" , trait_m)
347
+ } ;
348
+
349
+ impl_m_iter. zip ( trait_m_iter) . find ( |& ( ref impl_arg, ref trait_arg) | {
350
+ match ( & impl_arg. ty . node , & trait_arg. ty . node ) {
351
+ ( & Ty_ :: TyRptr ( _, ref impl_mt) , & Ty_ :: TyRptr ( _, ref trait_mt) ) |
352
+ ( & Ty_ :: TyPtr ( ref impl_mt) , & Ty_ :: TyPtr ( ref trait_mt) ) =>
353
+ impl_mt. mutbl != trait_mt. mutbl ,
354
+ _ => false
355
+ }
356
+ } ) . map ( |( ref impl_arg, ref trait_arg) | {
357
+ match ( impl_arg. to_self ( ) , trait_arg. to_self ( ) ) {
358
+ ( Some ( impl_self) , Some ( trait_self) ) =>
359
+ ( impl_self. span , Some ( trait_self. span ) ) ,
360
+ ( None , None ) => ( impl_arg. ty . span , Some ( trait_arg. ty . span ) ) ,
361
+ _ => bug ! ( "impl and trait fns have different first args, \
362
+ impl: {:?}, trait: {:?}", impl_arg, trait_arg)
363
+ }
364
+ } ) . unwrap_or ( ( origin. span ( ) , tcx. map . span_if_local ( trait_m. def_id ) ) )
365
+ } else {
366
+ ( origin. span ( ) , tcx. map . span_if_local ( trait_m. def_id ) )
367
+ }
368
+ }
369
+ TypeError :: Sorts ( ExpectedFound { expected, found } ) => {
370
+ if let Some ( trait_m_node_id) = tcx. map . as_local_node_id ( trait_m. def_id ) {
371
+ let trait_m_iter = match tcx. map . expect_trait_item ( trait_m_node_id) . node {
372
+ TraitItem_ :: MethodTraitItem ( ref trait_m_sig, _) =>
373
+ trait_m_sig. decl . inputs . iter ( ) ,
374
+ _ => bug ! ( "{:?} is not a MethodTraitItem" , trait_m)
375
+ } ;
376
+ let impl_iter = impl_args. iter ( ) ;
377
+ let trait_iter = trait_args. iter ( ) ;
378
+ let arg_idx = impl_iter. zip ( trait_iter)
379
+ . position ( |( impl_arg_ty, trait_arg_ty) | {
380
+ * impl_arg_ty == found && * trait_arg_ty == expected
381
+ } ) . unwrap ( ) ;
382
+ impl_m_iter. zip ( trait_m_iter)
383
+ . nth ( arg_idx)
384
+ . map ( |( impl_arg, trait_arg) |
385
+ ( impl_arg. ty . span , Some ( trait_arg. ty . span ) ) )
386
+ . unwrap_or (
387
+ ( origin. span ( ) , tcx. map . span_if_local ( trait_m. def_id ) ) )
388
+ } else {
389
+ ( origin. span ( ) , tcx. map . span_if_local ( trait_m. def_id ) )
390
+ }
391
+ }
392
+ _ => ( origin. span ( ) , tcx. map . span_if_local ( trait_m. def_id ) )
393
+ } ;
394
+
395
+ let origin = TypeOrigin :: MethodCompatCheck ( impl_err_span) ;
396
+
334
397
let mut diag = struct_span_err ! (
335
398
tcx. sess, origin. span( ) , E0053 ,
336
399
"method `{}` has an incompatible type for trait" , trait_m. name
337
400
) ;
401
+
338
402
infcx. note_type_err (
339
- & mut diag, origin,
403
+ & mut diag,
404
+ origin,
405
+ trait_err_span. map ( |sp| ( sp, format ! ( "original trait requirement" ) ) ) ,
340
406
Some ( infer:: ValuePairs :: Types ( ExpectedFound {
341
- expected : trait_fty,
342
- found : impl_fty
343
- } ) ) , & terr
407
+ expected : trait_fty,
408
+ found : impl_fty
409
+ } ) ) ,
410
+ & terr
344
411
) ;
345
412
diag. emit ( ) ;
346
413
return
@@ -487,12 +554,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
487
554
trait_ty) ;
488
555
489
556
// Locate the Span containing just the type of the offending impl
490
- if let Some ( impl_trait_node) = tcx. map . get_if_local ( impl_c. def_id ) {
491
- if let Node :: NodeImplItem ( impl_trait_item) = impl_trait_node {
492
- if let ImplItemKind :: Const ( ref ty, _) = impl_trait_item. node {
493
- origin = TypeOrigin :: Misc ( ty. span ) ;
494
- }
495
- }
557
+ match tcx. map . expect_impl_item ( impl_c_node_id) . node {
558
+ ImplItemKind :: Const ( ref ty, _) => origin = TypeOrigin :: Misc ( ty. span ) ,
559
+ _ => bug ! ( "{:?} is not a impl const" , impl_c)
496
560
}
497
561
498
562
let mut diag = struct_span_err ! (
@@ -502,16 +566,16 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
502
566
) ;
503
567
504
568
// Add a label to the Span containing just the type of the item
505
- if let Some ( orig_trait_node) = tcx. map . get_if_local ( trait_c. def_id ) {
506
- if let Node :: NodeTraitItem ( orig_trait_item) = orig_trait_node {
507
- if let TraitItem_ :: ConstTraitItem ( ref ty, _) = orig_trait_item. node {
508
- diag. span_label ( ty. span , & format ! ( "original trait requirement" ) ) ;
509
- }
510
- }
511
- }
569
+ let trait_c_node_id = tcx. map . as_local_node_id ( trait_c. def_id ) . unwrap ( ) ;
570
+ let trait_c_span = match tcx. map . expect_trait_item ( trait_c_node_id) . node {
571
+ TraitItem_ :: ConstTraitItem ( ref ty, _) => ty. span ,
572
+ _ => bug ! ( "{:?} is not a trait const" , trait_c)
573
+ } ;
512
574
513
575
infcx. note_type_err (
514
- & mut diag, origin,
576
+ & mut diag,
577
+ origin,
578
+ Some ( ( trait_c_span, format ! ( "original trait requirement" ) ) ) ,
515
579
Some ( infer:: ValuePairs :: Types ( ExpectedFound {
516
580
expected : trait_ty,
517
581
found : impl_ty
0 commit comments