@@ -978,45 +978,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
978978 label_span_not_found ( & mut err) ;
979979 }
980980
981- if let SelfSource :: MethodCall ( expr) = source
982- && let Some ( ( fields, substs) ) = self . get_field_candidates ( span, actual)
983- {
984- let call_expr =
985- self . tcx . hir ( ) . expect_expr ( self . tcx . hir ( ) . get_parent_node ( expr. hir_id ) ) ;
986- for candidate_field in fields. iter ( ) {
987- if let Some ( field_path) = self . check_for_nested_field_satisfying (
988- span,
989- & |_, field_ty| {
990- self . lookup_probe (
991- span,
992- item_name,
993- field_ty,
994- call_expr,
995- ProbeScope :: AllTraits ,
996- )
997- . is_ok ( )
998- } ,
999- candidate_field,
1000- substs,
1001- vec ! [ ] ,
1002- self . tcx . parent_module ( expr. hir_id ) . to_def_id ( ) ,
1003- ) {
1004- let field_path_str = field_path
1005- . iter ( )
1006- . map ( |id| id. name . to_ident_string ( ) )
1007- . collect :: < Vec < String > > ( )
1008- . join ( "." ) ;
1009- debug ! ( "field_path_str: {:?}" , field_path_str) ;
981+ self . check_for_field_method ( & mut err, source, span, actual, item_name) ;
1010982
1011- err. span_suggestion_verbose (
1012- item_name. span . shrink_to_lo ( ) ,
1013- "one of the expressions' fields has a method of the same name" ,
1014- format ! ( "{field_path_str}." ) ,
1015- Applicability :: MaybeIncorrect ,
1016- ) ;
1017- }
1018- }
1019- }
983+ self . check_for_unwrap_self ( & mut err, source, span, actual, item_name) ;
1020984
1021985 bound_spans. sort ( ) ;
1022986 bound_spans. dedup ( ) ;
@@ -1343,6 +1307,157 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13431307 false
13441308 }
13451309
1310+ fn check_for_field_method (
1311+ & self ,
1312+ err : & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ,
1313+ source : SelfSource < ' tcx > ,
1314+ span : Span ,
1315+ actual : Ty < ' tcx > ,
1316+ item_name : Ident ,
1317+ ) {
1318+ if let SelfSource :: MethodCall ( expr) = source
1319+ && let Some ( ( fields, substs) ) = self . get_field_candidates ( span, actual)
1320+ {
1321+ let call_expr = self . tcx . hir ( ) . expect_expr ( self . tcx . hir ( ) . get_parent_node ( expr. hir_id ) ) ;
1322+ for candidate_field in fields. iter ( ) {
1323+ if let Some ( field_path) = self . check_for_nested_field_satisfying (
1324+ span,
1325+ & |_, field_ty| {
1326+ self . lookup_probe (
1327+ span,
1328+ item_name,
1329+ field_ty,
1330+ call_expr,
1331+ ProbeScope :: AllTraits ,
1332+ )
1333+ . is_ok ( )
1334+ } ,
1335+ candidate_field,
1336+ substs,
1337+ vec ! [ ] ,
1338+ self . tcx . parent_module ( expr. hir_id ) . to_def_id ( ) ,
1339+ ) {
1340+ let field_path_str = field_path
1341+ . iter ( )
1342+ . map ( |id| id. name . to_ident_string ( ) )
1343+ . collect :: < Vec < String > > ( )
1344+ . join ( "." ) ;
1345+ debug ! ( "field_path_str: {:?}" , field_path_str) ;
1346+
1347+ err. span_suggestion_verbose (
1348+ item_name. span . shrink_to_lo ( ) ,
1349+ "one of the expressions' fields has a method of the same name" ,
1350+ format ! ( "{field_path_str}." ) ,
1351+ Applicability :: MaybeIncorrect ,
1352+ ) ;
1353+ }
1354+ }
1355+ }
1356+ }
1357+
1358+ fn check_for_unwrap_self (
1359+ & self ,
1360+ err : & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ,
1361+ source : SelfSource < ' tcx > ,
1362+ span : Span ,
1363+ actual : Ty < ' tcx > ,
1364+ item_name : Ident ,
1365+ ) {
1366+ let tcx = self . tcx ;
1367+ let SelfSource :: MethodCall ( expr) = source else { return ; } ;
1368+ let call_expr = tcx. hir ( ) . expect_expr ( tcx. hir ( ) . get_parent_node ( expr. hir_id ) ) ;
1369+
1370+ let ty:: Adt ( kind, substs) = actual. kind ( ) else { return ; } ;
1371+ if !kind. is_enum ( ) {
1372+ return ;
1373+ }
1374+
1375+ let matching_variants: Vec < _ > = kind
1376+ . variants ( )
1377+ . iter ( )
1378+ . filter_map ( |variant| {
1379+ let [ field] = & variant. fields [ ..] else { return None ; } ;
1380+ let field_ty = field. ty ( tcx, substs) ;
1381+
1382+ // Skip `_`, since that'll just lead to ambiguity.
1383+ if matches ! ( self . resolve_vars_if_possible( field_ty) . kind( ) , ty:: Infer ( _) ) {
1384+ return None ;
1385+ }
1386+
1387+ if let Ok ( pick) =
1388+ self . lookup_probe ( span, item_name, field_ty, call_expr, ProbeScope :: AllTraits )
1389+ {
1390+ Some ( ( variant, field, pick) )
1391+ } else {
1392+ None
1393+ }
1394+ } )
1395+ . collect ( ) ;
1396+
1397+ let ret_ty_matches = |diagnostic_item| {
1398+ if let Some ( ret_ty) = self
1399+ . ret_coercion
1400+ . as_ref ( )
1401+ . map ( |c| self . resolve_vars_if_possible ( c. borrow ( ) . expected_ty ( ) ) )
1402+ && let ty:: Adt ( kind, _) = ret_ty. kind ( )
1403+ && tcx. get_diagnostic_item ( diagnostic_item) == Some ( kind. did ( ) )
1404+ {
1405+ true
1406+ } else {
1407+ false
1408+ }
1409+ } ;
1410+
1411+ match & matching_variants[ ..] {
1412+ [ ( _, field, pick) ] if Some ( kind. did ( ) ) == tcx. get_diagnostic_item ( sym:: Result ) => {
1413+ let self_ty = field. ty ( tcx, substs) ;
1414+ err. span_note (
1415+ tcx. def_span ( pick. item . def_id ) ,
1416+ & format ! ( "the method `{item_name}` exists on the type `{self_ty}`" ) ,
1417+ ) ;
1418+ if ret_ty_matches ( sym:: Result ) {
1419+ err. span_suggestion_verbose (
1420+ expr. span . shrink_to_hi ( ) ,
1421+ format ! ( "use the `?` operator to extract the `{self_ty}` value, propagating a `Result::Err` value to the caller" ) ,
1422+ "?" . to_owned ( ) ,
1423+ Applicability :: MachineApplicable ,
1424+ ) ;
1425+ } else {
1426+ err. span_suggestion_verbose (
1427+ expr. span . shrink_to_hi ( ) ,
1428+ format ! ( "consider using `Result::expect` to unwrap the `{self_ty}` value, panicking if the value is an `Err`" ) ,
1429+ ".expect(\" REASON\" )" . to_owned ( ) ,
1430+ Applicability :: HasPlaceholders ,
1431+ ) ;
1432+ }
1433+ }
1434+ [ ( _, field, pick) ] if Some ( kind. did ( ) ) == tcx. get_diagnostic_item ( sym:: Option ) => {
1435+ let self_ty = field. ty ( tcx, substs) ;
1436+ err. span_note (
1437+ tcx. def_span ( pick. item . def_id ) ,
1438+ & format ! ( "the method `{item_name}` exists on the type `{self_ty}`" ) ,
1439+ ) ;
1440+ if ret_ty_matches ( sym:: Option ) {
1441+ err. span_suggestion_verbose (
1442+ expr. span . shrink_to_hi ( ) ,
1443+ format ! ( "use the `?` operator to extract the `{self_ty}` value, propagating a `None` to the caller" ) ,
1444+ "?" . to_owned ( ) ,
1445+ Applicability :: MachineApplicable ,
1446+ ) ;
1447+ } else {
1448+ err. span_suggestion_verbose (
1449+ expr. span . shrink_to_hi ( ) ,
1450+ format ! ( "consider using `Option::expect` to unwrap the `{self_ty}` value, panicking if the value is `None`" ) ,
1451+ ".expect(\" REASON\" )" . to_owned ( ) ,
1452+ Applicability :: HasPlaceholders ,
1453+ ) ;
1454+ }
1455+ }
1456+ // FIXME(compiler-errors): Support suggestions for other matching enum variants
1457+ _ => { }
1458+ }
1459+ }
1460+
13461461 pub ( crate ) fn note_unmet_impls_on_type (
13471462 & self ,
13481463 err : & mut Diagnostic ,
@@ -1662,13 +1777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16621777 ( self . tcx . mk_mut_ref ( self . tcx . lifetimes . re_erased , rcvr_ty) , "&mut " ) ,
16631778 ( self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_erased , rcvr_ty) , "&" ) ,
16641779 ] {
1665- match self . lookup_probe (
1666- span,
1667- item_name,
1668- * rcvr_ty,
1669- rcvr,
1670- crate :: check:: method:: probe:: ProbeScope :: AllTraits ,
1671- ) {
1780+ match self . lookup_probe ( span, item_name, * rcvr_ty, rcvr, ProbeScope :: AllTraits ) {
16721781 Ok ( pick) => {
16731782 // If the method is defined for the receiver we have, it likely wasn't `use`d.
16741783 // We point at the method, but we just skip the rest of the check for arbitrary
@@ -1700,13 +1809,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17001809 ( self . tcx . mk_diagnostic_item ( * rcvr_ty, sym:: Arc ) , "Arc::new" ) ,
17011810 ( self . tcx . mk_diagnostic_item ( * rcvr_ty, sym:: Rc ) , "Rc::new" ) ,
17021811 ] {
1703- if let Some ( new_rcvr_t) = * rcvr_ty && let Ok ( pick) = self . lookup_probe (
1704- span,
1705- item_name,
1706- new_rcvr_t,
1707- rcvr,
1708- crate :: check:: method:: probe:: ProbeScope :: AllTraits ,
1709- ) {
1812+ if let Some ( new_rcvr_t) = * rcvr_ty
1813+ && let Ok ( pick) = self . lookup_probe (
1814+ span,
1815+ item_name,
1816+ new_rcvr_t,
1817+ rcvr,
1818+ ProbeScope :: AllTraits ,
1819+ )
1820+ {
17101821 debug ! ( "try_alt_rcvr: pick candidate {:?}" , pick) ;
17111822 let did = Some ( pick. item . container . id ( ) ) ;
17121823 // We don't want to suggest a container type when the missing
0 commit comments