@@ -1187,6 +1187,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11871187 has_custom_message : bool ,
11881188 ) -> bool {
11891189 let span = obligation. cause . span ;
1190+ let param_env = obligation. param_env ;
1191+
1192+ let mk_result = |trait_pred_and_new_ty| {
1193+ let obligation =
1194+ self . mk_trait_obligation_with_new_self_ty ( param_env, trait_pred_and_new_ty) ;
1195+ self . predicate_must_hold_modulo_regions ( & obligation)
1196+ } ;
11901197
11911198 let code = match obligation. cause . code ( ) {
11921199 ObligationCauseCode :: FunctionArg { parent_code, .. } => parent_code,
@@ -1195,13 +1202,74 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11951202 c @ ObligationCauseCode :: WhereClauseInExpr ( _, _, hir_id, _)
11961203 if self . tcx . hir_span ( * hir_id) . lo ( ) == span. lo ( ) =>
11971204 {
1205+ // `hir_id` corresponds to the HIR node that introduced a `where`-clause obligation.
1206+ // If that obligation comes from a type in an associated method call, we need
1207+ // special handling here.
11981208 if let hir:: Node :: Expr ( expr) = self . tcx . parent_hir_node ( * hir_id)
11991209 && let hir:: ExprKind :: Call ( base, _) = expr. kind
1200- && let hir:: ExprKind :: Path ( hir:: QPath :: TypeRelative ( ty, _) ) = base. kind
1210+ && let hir:: ExprKind :: Path ( hir:: QPath :: TypeRelative ( ty, segment) ) = base. kind
1211+ && let hir:: Node :: Expr ( outer) = self . tcx . parent_hir_node ( expr. hir_id )
1212+ && let hir:: ExprKind :: AddrOf ( hir:: BorrowKind :: Ref , mtbl, _) = outer. kind
12011213 && ty. span == span
12021214 {
1203- // Do not suggest borrowing when we already do so. This would happen with
1204- // `let _ = &str::from("");` where the expression corresponds to the `str`.
1215+ // We've encountered something like `&str::from("")`, where the intended code
1216+ // was likely `<&str>::from("")`. The former is interpreted as "call method
1217+ // `from` on `str` and borrow the result", while the latter means "call method
1218+ // `from` on `&str`".
1219+
1220+ let trait_pred_and_imm_ref = poly_trait_pred. map_bound ( |p| {
1221+ ( p, Ty :: new_imm_ref ( self . tcx , self . tcx . lifetimes . re_static , p. self_ty ( ) ) )
1222+ } ) ;
1223+ let trait_pred_and_mut_ref = poly_trait_pred. map_bound ( |p| {
1224+ ( p, Ty :: new_mut_ref ( self . tcx , self . tcx . lifetimes . re_static , p. self_ty ( ) ) )
1225+ } ) ;
1226+
1227+ let imm_ref_self_ty_satisfies_pred = mk_result ( trait_pred_and_imm_ref) ;
1228+ let mut_ref_self_ty_satisfies_pred = mk_result ( trait_pred_and_mut_ref) ;
1229+ let sugg_msg = |pre : & str | {
1230+ format ! (
1231+ "you likely meant to call the associated function `{FN}` for type \
1232+ `&{pre}{TY}`, but the code as written calls associated function `{FN}` on \
1233+ type `{TY}`",
1234+ FN = segment. ident,
1235+ TY = poly_trait_pred. self_ty( ) ,
1236+ )
1237+ } ;
1238+ match ( imm_ref_self_ty_satisfies_pred, mut_ref_self_ty_satisfies_pred, mtbl) {
1239+ ( true , _, hir:: Mutability :: Not ) | ( _, true , hir:: Mutability :: Mut ) => {
1240+ err. multipart_suggestion_verbose (
1241+ sugg_msg ( mtbl. prefix_str ( ) ) ,
1242+ vec ! [
1243+ ( outer. span. shrink_to_lo( ) , "<" . to_string( ) ) ,
1244+ ( span. shrink_to_hi( ) , ">" . to_string( ) ) ,
1245+ ] ,
1246+ Applicability :: MachineApplicable ,
1247+ ) ;
1248+ }
1249+ ( true , _, hir:: Mutability :: Mut ) => {
1250+ // There's an associated function found on the immutable borrow of the
1251+ err. multipart_suggestion_verbose (
1252+ sugg_msg ( "mut " ) ,
1253+ vec ! [
1254+ ( outer. span. shrink_to_lo( ) . until( span) , "<&" . to_string( ) ) ,
1255+ ( span. shrink_to_hi( ) , ">" . to_string( ) ) ,
1256+ ] ,
1257+ Applicability :: MachineApplicable ,
1258+ ) ;
1259+ }
1260+ ( _, true , hir:: Mutability :: Not ) => {
1261+ err. multipart_suggestion_verbose (
1262+ sugg_msg ( "" ) ,
1263+ vec ! [
1264+ ( outer. span. shrink_to_lo( ) . until( span) , "<&mut " . to_string( ) ) ,
1265+ ( span. shrink_to_hi( ) , ">" . to_string( ) ) ,
1266+ ] ,
1267+ Applicability :: MachineApplicable ,
1268+ ) ;
1269+ }
1270+ _ => { }
1271+ }
1272+ // If we didn't return early here, we would instead suggest `&&str::from("")`.
12051273 return false ;
12061274 }
12071275 c
@@ -1229,8 +1297,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12291297 never_suggest_borrow. push ( def_id) ;
12301298 }
12311299
1232- let param_env = obligation. param_env ;
1233-
12341300 // Try to apply the original trait bound by borrowing.
12351301 let mut try_borrowing = |old_pred : ty:: PolyTraitPredicate < ' tcx > ,
12361302 blacklist : & [ DefId ] |
@@ -1252,11 +1318,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12521318 )
12531319 } ) ;
12541320
1255- let mk_result = |trait_pred_and_new_ty| {
1256- let obligation =
1257- self . mk_trait_obligation_with_new_self_ty ( param_env, trait_pred_and_new_ty) ;
1258- self . predicate_must_hold_modulo_regions ( & obligation)
1259- } ;
12601321 let imm_ref_self_ty_satisfies_pred = mk_result ( trait_pred_and_imm_ref) ;
12611322 let mut_ref_self_ty_satisfies_pred = mk_result ( trait_pred_and_mut_ref) ;
12621323
0 commit comments