@@ -1321,7 +1321,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13211321            let  imm_ref_self_ty_satisfies_pred = mk_result ( trait_pred_and_imm_ref) ; 
13221322            let  mut_ref_self_ty_satisfies_pred = mk_result ( trait_pred_and_mut_ref) ; 
13231323
1324-             let  ( ref_inner_ty_satisfies_pred,  ref_inner_ty_mut )  =
1324+             let  ( ref_inner_ty_satisfies_pred,  ref_inner_ty_is_mut )  =
13251325                if  let  ObligationCauseCode :: WhereClauseInExpr ( ..)  = obligation. cause . code ( ) 
13261326                    && let  ty:: Ref ( _,  ty,  mutability)  = old_pred. self_ty ( ) . skip_binder ( ) . kind ( ) 
13271327                { 
@@ -1333,117 +1333,139 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13331333                    ( false ,  false ) 
13341334                } ; 
13351335
1336-             if  imm_ref_self_ty_satisfies_pred
1337-                 || mut_ref_self_ty_satisfies_pred
1338-                 || ref_inner_ty_satisfies_pred
1339-             { 
1340-                 if  let  Ok ( snippet)  = self . tcx . sess . source_map ( ) . span_to_snippet ( span)  { 
1341-                     // We don't want a borrowing suggestion on the fields in structs, 
1342-                     // ``` 
1343-                     // struct Foo { 
1344-                     //  the_foos: Vec<Foo> 
1345-                     // } 
1346-                     // ``` 
1347-                     if  !matches ! ( 
1348-                         span. ctxt( ) . outer_expn_data( ) . kind, 
1349-                         ExpnKind :: Root  | ExpnKind :: Desugaring ( DesugaringKind :: ForLoop ) 
1350-                     )  { 
1351-                         return  false ; 
1352-                     } 
1353-                     if  snippet. starts_with ( '&' )  { 
1354-                         // This is already a literal borrow and the obligation is failing 
1355-                         // somewhere else in the obligation chain. Do not suggest non-sense. 
1356-                         return  false ; 
1357-                     } 
1358-                     // We have a very specific type of error, where just borrowing this argument 
1359-                     // might solve the problem. In cases like this, the important part is the 
1360-                     // original type obligation, not the last one that failed, which is arbitrary. 
1361-                     // Because of this, we modify the error to refer to the original obligation and 
1362-                     // return early in the caller. 
1363- 
1364-                     let  msg = format ! ( 
1365-                         "the trait bound `{}` is not satisfied" , 
1366-                         self . tcx. short_string( old_pred,  err. long_ty_path( ) ) , 
1367-                     ) ; 
1368-                     let  self_ty_str =
1369-                         self . tcx . short_string ( old_pred. self_ty ( ) . skip_binder ( ) ,  err. long_ty_path ( ) ) ; 
1370-                     if  has_custom_message { 
1371-                         err. note ( msg) ; 
1372-                     }  else  { 
1373-                         err. messages  = vec ! [ ( rustc_errors:: DiagMessage :: from( msg) ,  Style :: NoStyle ) ] ; 
1374-                     } 
1375-                     err. span_label ( 
1376-                         span, 
1377-                         format ! ( 
1378-                             "the trait `{}` is not implemented for `{self_ty_str}`" , 
1379-                             old_pred. print_modifiers_and_trait_path( ) 
1380-                         ) , 
1381-                     ) ; 
1336+             let  is_immut = imm_ref_self_ty_satisfies_pred
1337+                 || ( ref_inner_ty_satisfies_pred && !ref_inner_ty_is_mut) ; 
1338+             let  is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_is_mut; 
1339+             if  !is_immut && !is_mut { 
1340+                 return  false ; 
1341+             } 
1342+             let  Ok ( _snippet)  = self . tcx . sess . source_map ( ) . span_to_snippet ( span)  else  { 
1343+                 return  false ; 
1344+             } ; 
1345+             // We don't want a borrowing suggestion on the fields in structs 
1346+             // ``` 
1347+             // #[derive(Clone)] 
1348+             // struct Foo { 
1349+             //     the_foos: Vec<Foo> 
1350+             // } 
1351+             // ``` 
1352+             if  !matches ! ( 
1353+                 span. ctxt( ) . outer_expn_data( ) . kind, 
1354+                 ExpnKind :: Root  | ExpnKind :: Desugaring ( DesugaringKind :: ForLoop ) 
1355+             )  { 
1356+                 return  false ; 
1357+             } 
1358+             // We have a very specific type of error, where just borrowing this argument 
1359+             // might solve the problem. In cases like this, the important part is the 
1360+             // original type obligation, not the last one that failed, which is arbitrary. 
1361+             // Because of this, we modify the error to refer to the original obligation and 
1362+             // return early in the caller. 
13821363
1383-                     if  imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred { 
1384-                         err. span_suggestions ( 
1385-                             span. shrink_to_lo ( ) , 
1386-                             "consider borrowing here" , 
1387-                             [ "&" . to_string ( ) ,  "&mut " . to_string ( ) ] , 
1388-                             Applicability :: MaybeIncorrect , 
1389-                         ) ; 
1390-                     }  else  { 
1391-                         let  is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; 
1392-                         let  sugg_prefix = format ! ( "&{}" ,  if  is_mut {  "mut "  }  else {  ""  } ) ; 
1393-                         let  sugg_msg = format ! ( 
1394-                             "consider{} borrowing here" , 
1395-                             if  is_mut {  " mutably"  }  else {  ""  } 
1396-                         ) ; 
1364+             let  mut  label = || { 
1365+                 let  msg = format ! ( 
1366+                     "the trait bound `{}` is not satisfied" , 
1367+                     self . tcx. short_string( old_pred,  err. long_ty_path( ) ) , 
1368+                 ) ; 
1369+                 let  self_ty_str =
1370+                     self . tcx . short_string ( old_pred. self_ty ( ) . skip_binder ( ) ,  err. long_ty_path ( ) ) ; 
1371+                 if  has_custom_message { 
1372+                     err. note ( msg) ; 
1373+                 }  else  { 
1374+                     err. messages  = vec ! [ ( rustc_errors:: DiagMessage :: from( msg) ,  Style :: NoStyle ) ] ; 
1375+                 } 
1376+                 err. span_label ( 
1377+                     span, 
1378+                     format ! ( 
1379+                         "the trait `{}` is not implemented for `{self_ty_str}`" , 
1380+                         old_pred. print_modifiers_and_trait_path( ) 
1381+                     ) , 
1382+                 ) ; 
1383+             } ; 
13971384
1398-                         // Issue #109436, we need to add parentheses properly for method calls 
1399-                         // for example, `foo.into()` should be `(&foo).into()` 
1400-                         if  let  Some ( _)  =
1401-                             self . tcx . sess . source_map ( ) . span_look_ahead ( span,  "." ,  Some ( 50 ) ) 
1402-                         { 
1403-                             err. multipart_suggestion_verbose ( 
1404-                                 sugg_msg, 
1405-                                 vec ! [ 
1406-                                     ( span. shrink_to_lo( ) ,  format!( "({sugg_prefix}" ) ) , 
1407-                                     ( span. shrink_to_hi( ) ,  ")" . to_string( ) ) , 
1408-                                 ] , 
1409-                                 Applicability :: MaybeIncorrect , 
1410-                             ) ; 
1411-                             return  true ; 
1412-                         } 
1385+             let  mut  sugg_prefixes = vec ! [ ] ; 
1386+             if  is_immut { 
1387+                 sugg_prefixes. push ( "&" ) ; 
1388+             } 
1389+             if  is_mut { 
1390+                 sugg_prefixes. push ( "&mut " ) ; 
1391+             } 
1392+             let  sugg_msg = format ! ( 
1393+                 "consider{} borrowing here" , 
1394+                 if  is_mut && !is_immut {  " mutably"  }  else {  ""  } , 
1395+             ) ; 
14131396
1414-                         // Issue #104961, we need to add parentheses properly for compound expressions 
1415-                         // for example, `x.starts_with("hi".to_string() + "you")` 
1416-                         // should be `x.starts_with(&("hi".to_string() + "you"))` 
1417-                         let  Some ( body)  = self . tcx . hir_maybe_body_owned_by ( obligation. cause . body_id ) 
1418-                         else  { 
1419-                             return  false ; 
1420-                         } ; 
1421-                         let  mut  expr_finder = FindExprBySpan :: new ( span,  self . tcx ) ; 
1422-                         expr_finder. visit_expr ( body. value ) ; 
1423-                         let  Some ( expr)  = expr_finder. result  else  { 
1424-                             return  false ; 
1425-                         } ; 
1426-                         let  needs_parens = expr_needs_parens ( expr) ; 
1397+             // Issue #104961, we need to add parentheses properly for compound expressions 
1398+             // for example, `x.starts_with("hi".to_string() + "you")` 
1399+             // should be `x.starts_with(&("hi".to_string() + "you"))` 
1400+             let  Some ( body)  = self . tcx . hir_maybe_body_owned_by ( obligation. cause . body_id )  else  { 
1401+                 return  false ; 
1402+             } ; 
1403+             let  mut  expr_finder = FindExprBySpan :: new ( span,  self . tcx ) ; 
1404+             expr_finder. visit_expr ( body. value ) ; 
14271405
1428-                         let  span = if  needs_parens {  span }  else  {  span. shrink_to_lo ( )  } ; 
1429-                         let  suggestions = if  !needs_parens { 
1430-                             vec ! [ ( span. shrink_to_lo( ) ,  sugg_prefix) ] 
1431-                         }  else  { 
1406+             if  let  Some ( ty)  = expr_finder. ty_result  { 
1407+                 if  let  hir:: Node :: Expr ( expr)  = self . tcx . parent_hir_node ( ty. hir_id ) 
1408+                     && let  hir:: ExprKind :: Path ( hir:: QPath :: TypeRelative ( _,  _) )  = expr. kind 
1409+                     && ty. span  == span
1410+                 { 
1411+                     // We've encountered something like `str::from("")`, where the intended code 
1412+                     // was likely `<&str>::from("")`. #143393. 
1413+                     label ( ) ; 
1414+                     err. multipart_suggestions ( 
1415+                         sugg_msg, 
1416+                         sugg_prefixes. into_iter ( ) . map ( |sugg_prefix| { 
14321417                            vec ! [ 
1433-                                 ( span. shrink_to_lo( ) ,  format!( "{sugg_prefix}( " ) ) , 
1434-                                 ( span. shrink_to_hi( ) ,  ") " . to_string( ) ) , 
1418+                                 ( span. shrink_to_lo( ) ,  format!( "< {sugg_prefix}" ) ) , 
1419+                                 ( span. shrink_to_hi( ) ,  "> " . to_string( ) ) , 
14351420                            ] 
1436-                         } ; 
1437-                         err. multipart_suggestion_verbose ( 
1438-                             sugg_msg, 
1439-                             suggestions, 
1440-                             Applicability :: MaybeIncorrect , 
1441-                         ) ; 
1442-                     } 
1421+                         } ) , 
1422+                         Applicability :: MaybeIncorrect , 
1423+                     ) ; 
14431424                    return  true ; 
14441425                } 
1426+                 return  false ; 
14451427            } 
1446-             return  false ; 
1428+             let  Some ( expr)  = expr_finder. result  else  { 
1429+                 return  false ; 
1430+             } ; 
1431+             if  let  hir:: ExprKind :: AddrOf ( _,  _,  _)  = expr. kind  { 
1432+                 return  false ; 
1433+             } 
1434+             let  needs_parens_post = expr_needs_parens ( expr) ; 
1435+             let  needs_parens_pre = match  self . tcx . parent_hir_node ( expr. hir_id )  { 
1436+                 Node :: Expr ( e) 
1437+                     if  let  hir:: ExprKind :: MethodCall ( _,  base,  _,  _)  = e. kind 
1438+                         && base. hir_id  == expr. hir_id  =>
1439+                 { 
1440+                     true 
1441+                 } 
1442+                 _ => false , 
1443+             } ; 
1444+ 
1445+             label ( ) ; 
1446+             let  suggestions = sugg_prefixes. into_iter ( ) . map ( |sugg_prefix| { 
1447+                 match  ( needs_parens_pre,  needs_parens_post)  { 
1448+                     ( false ,  false )  => vec ! [ ( span. shrink_to_lo( ) ,  sugg_prefix. to_string( ) ) ] , 
1449+                     // We have something like `foo.bar()`, where we want to bororw foo, so we need 
1450+                     // to suggest `(&mut foo).bar()`. 
1451+                     ( false ,  true )  => vec ! [ 
1452+                         ( span. shrink_to_lo( ) ,  format!( "{sugg_prefix}(" ) ) , 
1453+                         ( span. shrink_to_hi( ) ,  ")" . to_string( ) ) , 
1454+                     ] , 
1455+                     // Issue #109436, we need to add parentheses properly for method calls 
1456+                     // for example, `foo.into()` should be `(&foo).into()` 
1457+                     ( true ,  false )  => vec ! [ 
1458+                         ( span. shrink_to_lo( ) ,  format!( "({sugg_prefix}" ) ) , 
1459+                         ( span. shrink_to_hi( ) ,  ")" . to_string( ) ) , 
1460+                     ] , 
1461+                     ( true ,  true )  => vec ! [ 
1462+                         ( span. shrink_to_lo( ) ,  format!( "({sugg_prefix}(" ) ) , 
1463+                         ( span. shrink_to_hi( ) ,  "))" . to_string( ) ) , 
1464+                     ] , 
1465+                 } 
1466+             } ) ; 
1467+             err. multipart_suggestions ( sugg_msg,  suggestions,  Applicability :: MaybeIncorrect ) ; 
1468+             return  true ; 
14471469        } ; 
14481470
14491471        if  let  ObligationCauseCode :: ImplDerived ( cause)  = & * code { 
0 commit comments