@@ -978,45 +978,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
978
978
label_span_not_found ( & mut err) ;
979
979
}
980
980
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) ;
1010
982
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) ;
1020
984
1021
985
bound_spans. sort ( ) ;
1022
986
bound_spans. dedup ( ) ;
@@ -1343,6 +1307,157 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1343
1307
false
1344
1308
}
1345
1309
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
+
1346
1461
pub ( crate ) fn note_unmet_impls_on_type (
1347
1462
& self ,
1348
1463
err : & mut Diagnostic ,
@@ -1662,13 +1777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1662
1777
( self . tcx . mk_mut_ref ( self . tcx . lifetimes . re_erased , rcvr_ty) , "&mut " ) ,
1663
1778
( self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_erased , rcvr_ty) , "&" ) ,
1664
1779
] {
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 ) {
1672
1781
Ok ( pick) => {
1673
1782
// If the method is defined for the receiver we have, it likely wasn't `use`d.
1674
1783
// 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> {
1700
1809
( self . tcx . mk_diagnostic_item ( * rcvr_ty, sym:: Arc ) , "Arc::new" ) ,
1701
1810
( self . tcx . mk_diagnostic_item ( * rcvr_ty, sym:: Rc ) , "Rc::new" ) ,
1702
1811
] {
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
+ {
1710
1821
debug ! ( "try_alt_rcvr: pick candidate {:?}" , pick) ;
1711
1822
let did = Some ( pick. item . container . id ( ) ) ;
1712
1823
// We don't want to suggest a container type when the missing
0 commit comments