@@ -221,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
221221    } 
222222
223223    /// Notes the point at which a variable is constrained to some type incompatible 
224-      /// with `expected_ty `. 
224+      /// with some expectation given by `source `. 
225225     pub  fn  note_source_of_type_mismatch_constraint ( 
226226        & self , 
227227        err :  & mut  Diagnostic , 
@@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
265265
266266        use  rustc_infer:: infer:: type_variable:: * ; 
267267        use  rustc_middle:: infer:: unify_key:: * ; 
268- 
268+          // Replaces all of the variables in the given type with a fresh inference variable. 
269269        let  mut  fudger = BottomUpFolder  { 
270270            tcx :  self . tcx , 
271271            ty_op :  |ty| { 
@@ -301,7 +301,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
301301
302302        let  expected_ty = match  source { 
303303            TypeMismatchSource :: Ty ( expected_ty)  => expected_ty, 
304-             TypeMismatchSource :: Arg ( call_expr,  idx)  => { 
304+             // Try to deduce what the possible value of `expr` would be if the 
305+             // incompatible arg were compatible. For example, given `Vec<i32>` 
306+             // and `vec.push(1u32)`, we ideally want to deduce that the type of 
307+             // `vec` *should* have been `Vec<u32>`. This will allow us to then 
308+             // run the subsequent code with this expectation, finding out exactly 
309+             // when this type diverged from our expectation. 
310+             TypeMismatchSource :: Arg  {  call_expr,  incompatible_arg :  idx }  => { 
305311                let  hir:: ExprKind :: MethodCall ( segment,  _,  args,  _)  = call_expr. kind  else  { 
306312                    return  false ; 
307313                } ; 
@@ -310,6 +316,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
310316                } ; 
311317                let  possible_rcvr_ty = expr_finder. uses . iter ( ) . find_map ( |binding| { 
312318                    let  possible_rcvr_ty = self . node_ty_opt ( binding. hir_id ) ?; 
319+                     // Fudge the receiver, so we can do new inference on it. 
313320                    let  possible_rcvr_ty = possible_rcvr_ty. fold_with ( & mut  fudger) ; 
314321                    let  method = self 
315322                        . lookup_method ( 
@@ -321,6 +328,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
321328                            args, 
322329                        ) 
323330                        . ok ( ) ?; 
331+                     // Unify the method signature with our incompatible arg, to 
332+                     // do inference in the *opposite* direction and to find out 
333+                     // what our ideal rcvr ty would look like. 
324334                    let  _ = self 
325335                        . at ( & ObligationCause :: dummy ( ) ,  self . param_env ) 
326336                        . eq ( DefineOpaqueTypes :: No ,  method. sig . inputs ( ) [ idx + 1 ] ,  arg_ty) 
@@ -339,11 +349,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
339349            } 
340350        } ; 
341351
352+         // If our expected_ty does not equal init_ty, then it *began* as incompatible. 
353+         // No need to note in this case... 
342354        if  !self . can_eq ( self . param_env ,  expected_ty,  init_ty. fold_with ( & mut  fudger) )  { 
343355            return  false ; 
344356        } 
345357
346358        for  window in  expr_finder. uses . windows ( 2 )  { 
359+             // Bindings always update their recorded type after the fact, so we 
360+             // need to look at the *following* usage's type to see when the 
361+             // binding became incompatible. 
347362            let  [ binding,  next_usage]  = * window else  {  continue ;  } ; 
348363
349364            // Don't go past the binding (always gonna be a nonsense label if so) 
@@ -363,6 +378,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
363378                && let  hir:: ExprKind :: MethodCall ( segment,  rcvr,  args,  _)  = parent_expr. kind 
364379                && rcvr. hir_id  == binding. hir_id 
365380            { 
381+                 // If our binding became incompatible while it was a receiver 
382+                 // to a method call, we may be able to make a better guess to 
383+                 // the source of a type mismatch. 
366384                let  Some ( rcvr_ty)  = self . node_ty_opt ( rcvr. hir_id )  else  {  continue ;  } ; 
367385                let  rcvr_ty = rcvr_ty. fold_with ( & mut  fudger) ; 
368386                let  Ok ( method)  =
@@ -371,14 +389,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
371389                    continue ; 
372390                } ; 
373391
374-                 // NOTE: For future removers of `fudge_inference_if_ok`, you 
375-                 // can replace  this with another call to `lookup_method` but 
376-                 // using `expected_ty` as the rcvr. 
377-                 let  ideal_method_sig:  Result < _ ,  TypeError < ' tcx > >  = self . fudge_inference_if_ok ( || { 
378-                     let  _ = self . at ( & ObligationCause :: dummy ( ) ,  self . param_env ) . eq ( rcvr_ty,  expected_ty) ?; 
379-                     Ok ( method. sig ) 
380-                 } ) ; 
392+                 let  ideal_rcvr_ty = rcvr_ty. fold_with ( & mut  fudger) ; 
393+                 let  ideal_method = self 
394+                     . lookup_method ( ideal_rcvr_ty,  segment,  DUMMY_SP ,  parent_expr,  rcvr,  args) 
395+                     . ok ( ) 
396+                     . and_then ( |method| { 
397+                         let  _ = self . at ( & ObligationCause :: dummy ( ) ,  self . param_env ) 
398+                             . eq ( DefineOpaqueTypes :: No ,  ideal_rcvr_ty,  expected_ty) 
399+                             . ok ( ) ?; 
400+                         Some ( method) 
401+                     } ) ; 
381402
403+                 // Find what argument caused our rcvr to become incompatible 
404+                 // with the expected ty. 
382405                for  ( idx,  ( expected_arg_ty,  arg_expr) )  in 
383406                    std:: iter:: zip ( & method. sig . inputs ( ) [ 1 ..] ,  args) . enumerate ( ) 
384407                { 
@@ -391,35 +414,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
391414                        AllowTwoPhase :: No , 
392415                        None , 
393416                    ) ; 
417+                     self . select_obligations_where_possible ( |errs| { 
418+                         // Yeet the errors, we're already reporting errors. 
419+                         errs. clear ( ) ; 
420+                     } ) ; 
421+                     // If our rcvr, after inference due to unifying the signature 
422+                     // with the expected argument type, is still compatible with 
423+                     // the rcvr, then it must've not been the source of blame. 
394424                    if  self . can_eq ( self . param_env ,  rcvr_ty,  expected_ty)  { 
395425                        continue ; 
396426                    } 
397-                     err. span_label ( 
398-                         arg_expr. span , 
399-                         format ! ( "this argument has type `{arg_ty}`..." ) , 
400-                     ) ; 
427+                     err. span_label ( arg_expr. span ,  format ! ( "this argument has type `{arg_ty}`..." ) ) ; 
401428                    err. span_label ( 
402429                        binding. span , 
403-                         format ! ( 
404-                             "... which constrains `{ident}` to have type `{next_use_ty}`" 
405-                         ) , 
430+                         format ! ( "... which causes `{ident}` to have type `{next_use_ty}`" ) , 
406431                    ) ; 
432+                     // Using our "ideal" method signature, suggest a fix to this 
433+                     // blame arg, if possible. Don't do this if we're coming from 
434+                     // arg mismatch code, because we'll possibly suggest a mutually 
435+                     // incompatible fix at the original mismatch site. 
407436                    if  matches ! ( source,  TypeMismatchSource :: Ty ( _) ) 
408-                         && let  Ok ( ideal_method_sig )  = ideal_method_sig 
437+                         && let  Some ( ideal_method )  = ideal_method 
409438                    { 
410439                        self . emit_type_mismatch_suggestions ( 
411440                            err, 
412441                            arg_expr, 
413442                            arg_ty, 
414-                             ideal_method_sig . inputs ( ) [ idx + 1 ] , 
443+                             self . resolve_vars_if_possible ( ideal_method . sig . inputs ( ) [ idx + 1 ] ) , 
415444                            None , 
416445                            None , 
417446                        ) ; 
418447                    } 
419448                    return  true ; 
420449                } 
421450            } 
422- 
423451            err. span_label ( 
424452                binding. span , 
425453                format ! ( "here the type of `{ident}` is inferred to be `{next_use_ty}`" ) , 
@@ -2092,6 +2120,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20922120} 
20932121
20942122pub  enum  TypeMismatchSource < ' tcx >  { 
2123+     /// Expected the binding to have the given type, but it was found to have 
2124+      /// a different type. Find out when that type first became incompatible. 
20952125     Ty ( Ty < ' tcx > ) , 
2096-     Arg ( & ' tcx  hir:: Expr < ' tcx > ,  usize ) , 
2126+     /// When we fail during method argument checking, try to find out if a previous 
2127+      /// expression has constrained the method's receiver in a way that makes the 
2128+      /// argument's type incompatible. 
2129+      Arg  {  call_expr :  & ' tcx  hir:: Expr < ' tcx > ,  incompatible_arg :  usize  } , 
20972130} 
0 commit comments