@@ -12,7 +12,7 @@ use rustc_middle::ty::adjustment::{
12
12
Adjust , Adjustment , AllowTwoPhase , AutoBorrow , AutoBorrowMutability ,
13
13
} ;
14
14
use 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 } ;
16
16
use rustc_span:: source_map:: Spanned ;
17
17
use rustc_span:: symbol:: { sym, Ident } ;
18
18
use rustc_span:: Span ;
@@ -310,10 +310,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
310
310
// error types are considered "builtin"
311
311
Err ( _) if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) => self . tcx . ty_error ( ) ,
312
312
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 {
317
318
IsAssign :: Yes => {
318
319
let mut err = struct_span_err ! (
319
320
self . tcx. sess,
@@ -328,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
328
329
format ! ( "cannot use `{}=` on type `{}`" , op. node. as_str( ) , lhs_ty) ,
329
330
) ;
330
331
self . note_unmet_impls_on_type ( & mut err, errors) ;
331
- ( err, false )
332
+ ( err, None )
332
333
}
333
334
IsAssign :: No => {
334
335
let message = match op. node {
@@ -368,19 +369,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368
369
lhs_ty
369
370
) ,
370
371
} ;
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 ( )
376
380
} ) ;
377
381
let mut err = struct_span_err ! ( self . tcx. sess, op. span, E0369 , "{message}" ) ;
378
382
if !lhs_expr. span . eq ( & rhs_expr. span ) {
379
383
err. span_label ( lhs_expr. span , lhs_ty. to_string ( ) ) ;
380
384
err. span_label ( rhs_expr. span , rhs_ty. to_string ( ) ) ;
381
385
}
382
386
self . note_unmet_impls_on_type ( & mut err, errors) ;
383
- ( err, use_output )
387
+ ( err, output_def_id )
384
388
}
385
389
} ;
386
390
@@ -488,20 +492,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
488
492
if let Some ( trait_pred) =
489
493
error. obligation . predicate . to_opt_poly_trait_pred ( )
490
494
{
491
- let proj_pred = match error. obligation . cause . code ( ) {
495
+ let output_associated_item = match error. obligation . cause . code ( )
496
+ {
492
497
ObligationCauseCode :: BinOp {
493
- output_pred : Some ( output_pred ) ,
498
+ output_ty : Some ( output_ty ) ,
494
499
..
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
+ }
497
510
}
498
511
_ => None ,
499
512
} ;
500
513
501
514
self . suggest_restricting_param_bound (
502
515
& mut err,
503
516
trait_pred,
504
- proj_pred ,
517
+ output_associated_item ,
505
518
self . body_id ,
506
519
) ;
507
520
}
0 commit comments