@@ -12,10 +12,9 @@ use middle::free_region::FreeRegionMap;
1212use rustc:: infer:: { self , InferOk , TypeOrigin } ;
1313use rustc:: ty;
1414use rustc:: traits:: { self , Reveal } ;
15- use rustc:: ty:: error:: ExpectedFound ;
15+ use rustc:: ty:: error:: { ExpectedFound , TypeError } ;
1616use rustc:: ty:: subst:: { Subst , Substs } ;
17- use rustc:: hir:: map:: Node ;
18- use rustc:: hir:: { ImplItemKind , TraitItem_ } ;
17+ use rustc:: hir:: { ImplItemKind , TraitItem_ , Ty_ } ;
1918
2019use syntax:: ast;
2120use syntax_pos:: Span ;
@@ -300,6 +299,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
300299 impl_m_span,
301300 impl_m_body_id,
302301 & impl_sig) ;
302+ let impl_args = impl_sig. inputs . clone ( ) ;
303303 let impl_fty = tcx. mk_fn_ptr ( tcx. mk_bare_fn ( ty:: BareFnTy {
304304 unsafety : impl_m. fty . unsafety ,
305305 abi : impl_m. fty . abi ,
@@ -318,6 +318,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
318318 impl_m_span,
319319 impl_m_body_id,
320320 & trait_sig) ;
321+ let trait_args = trait_sig. inputs . clone ( ) ;
321322 let trait_fty = tcx. mk_fn_ptr ( tcx. mk_bare_fn ( ty:: BareFnTy {
322323 unsafety : trait_m. fty . unsafety ,
323324 abi : trait_m. fty . abi ,
@@ -331,16 +332,82 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
331332 impl_fty,
332333 trait_fty) ;
333334
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+
334397 let mut diag = struct_span_err ! (
335398 tcx. sess, origin. span( ) , E0053 ,
336399 "method `{}` has an incompatible type for trait" , trait_m. name
337400 ) ;
401+
338402 infcx. note_type_err (
339- & mut diag, origin,
403+ & mut diag,
404+ origin,
405+ trait_err_span. map ( |sp| ( sp, format ! ( "original trait requirement" ) ) ) ,
340406 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
344411 ) ;
345412 diag. emit ( ) ;
346413 return
@@ -487,12 +554,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
487554 trait_ty) ;
488555
489556 // 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)
496560 }
497561
498562 let mut diag = struct_span_err ! (
@@ -502,16 +566,16 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
502566 ) ;
503567
504568 // 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+ } ;
512574
513575 infcx. note_type_err (
514- & mut diag, origin,
576+ & mut diag,
577+ origin,
578+ Some ( ( trait_c_span, format ! ( "original trait requirement" ) ) ) ,
515579 Some ( infer:: ValuePairs :: Types ( ExpectedFound {
516580 expected : trait_ty,
517581 found : impl_ty
0 commit comments