@@ -12,7 +12,7 @@ use rustc_middle::ty::adjustment::{
1212 Adjust , Adjustment , AllowTwoPhase , AutoBorrow , AutoBorrowMutability ,
1313} ;
1414use rustc_middle:: ty:: print:: with_no_trimmed_paths;
15- use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeFolder , TypeSuperFoldable , TypeVisitable } ;
15+ use rustc_middle:: ty:: { self , DefIdTree , Ty , TyCtxt , TypeFolder , TypeSuperFoldable , TypeVisitable } ;
1616use rustc_span:: source_map:: Spanned ;
1717use rustc_span:: symbol:: { sym, Ident } ;
1818use rustc_span:: Span ;
@@ -310,10 +310,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
310310 // error types are considered "builtin"
311311 Err ( _) if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) => self . tcx . ty_error ( ) ,
312312 Err ( errors) => {
313- let ( _, item) = lang_item_for_op ( self . tcx , Op :: Binary ( op, is_assign) , op. span ) ;
314- let missing_trait =
315- item. map ( |def_id| with_no_trimmed_paths ! ( self . tcx. def_path_str( def_id) ) ) ;
316- let ( mut err, use_output) = match is_assign {
313+ let ( _, trait_def_id) =
314+ lang_item_for_op ( self . tcx , Op :: Binary ( op, is_assign) , op. span ) ;
315+ let missing_trait = trait_def_id
316+ . map ( |def_id| with_no_trimmed_paths ! ( self . tcx. def_path_str( def_id) ) ) ;
317+ let ( mut err, output_def_id) = match is_assign {
317318 IsAssign :: Yes => {
318319 let mut err = struct_span_err ! (
319320 self . tcx. sess,
@@ -328,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
328329 format ! ( "cannot use `{}=` on type `{}`" , op. node. as_str( ) , lhs_ty) ,
329330 ) ;
330331 self . note_unmet_impls_on_type ( & mut err, errors) ;
331- ( err, false )
332+ ( err, None )
332333 }
333334 IsAssign :: No => {
334335 let message = match op. node {
@@ -368,19 +369,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368369 lhs_ty
369370 ) ,
370371 } ;
371- let use_output = item. map_or ( false , |def_id| {
372- self . tcx . associated_item_def_ids ( def_id) . iter ( ) . any ( |item_def_id| {
373- self . tcx . opt_associated_item ( * item_def_id) . unwrap ( ) . name
374- == sym:: Output
375- } )
372+ let output_def_id = trait_def_id. and_then ( |def_id| {
373+ self . tcx
374+ . associated_item_def_ids ( def_id)
375+ . iter ( )
376+ . find ( |item_def_id| {
377+ self . tcx . associated_item ( * item_def_id) . name == sym:: Output
378+ } )
379+ . cloned ( )
376380 } ) ;
377381 let mut err = struct_span_err ! ( self . tcx. sess, op. span, E0369 , "{message}" ) ;
378382 if !lhs_expr. span . eq ( & rhs_expr. span ) {
379383 err. span_label ( lhs_expr. span , lhs_ty. to_string ( ) ) ;
380384 err. span_label ( rhs_expr. span , rhs_ty. to_string ( ) ) ;
381385 }
382386 self . note_unmet_impls_on_type ( & mut err, errors) ;
383- ( err, use_output )
387+ ( err, output_def_id )
384388 }
385389 } ;
386390
@@ -488,20 +492,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
488492 if let Some ( trait_pred) =
489493 error. obligation . predicate . to_opt_poly_trait_pred ( )
490494 {
491- let proj_pred = match error. obligation . cause . code ( ) {
495+ let output_associated_item = match error. obligation . cause . code ( )
496+ {
492497 ObligationCauseCode :: BinOp {
493- output_pred : Some ( output_pred ) ,
498+ output_ty : Some ( output_ty ) ,
494499 ..
495- } if use_output => {
496- output_pred. to_opt_poly_projection_pred ( )
500+ } => {
501+ // Make sure that we're attaching `Output = ..` to the right trait predicate
502+ if let Some ( output_def_id) = output_def_id
503+ && let Some ( trait_def_id) = trait_def_id
504+ && self . tcx . parent ( output_def_id) == trait_def_id
505+ {
506+ Some ( ( "Output" , * output_ty) )
507+ } else {
508+ None
509+ }
497510 }
498511 _ => None ,
499512 } ;
500513
501514 self . suggest_restricting_param_bound (
502515 & mut err,
503516 trait_pred,
504- proj_pred ,
517+ output_associated_item ,
505518 self . body_id ,
506519 ) ;
507520 }
0 commit comments