@@ -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