@@ -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,145 @@ 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
+ . flat_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 self . resolve_vars_if_possible ( field_ty) . is_ty_var ( ) {
1384
+ return None ;
1385
+ }
1386
+
1387
+ self . lookup_probe ( span, item_name, field_ty, call_expr, ProbeScope :: AllTraits )
1388
+ . ok ( )
1389
+ . map ( |pick| ( variant, field, pick) )
1390
+ } )
1391
+ . collect ( ) ;
1392
+
1393
+ let ret_ty_matches = |diagnostic_item| {
1394
+ if let Some ( ret_ty) = self
1395
+ . ret_coercion
1396
+ . as_ref ( )
1397
+ . map ( |c| self . resolve_vars_if_possible ( c. borrow ( ) . expected_ty ( ) ) )
1398
+ && let ty:: Adt ( kind, _) = ret_ty. kind ( )
1399
+ && tcx. get_diagnostic_item ( diagnostic_item) == Some ( kind. did ( ) )
1400
+ {
1401
+ true
1402
+ } else {
1403
+ false
1404
+ }
1405
+ } ;
1406
+
1407
+ match & matching_variants[ ..] {
1408
+ [ ( _, field, pick) ] => {
1409
+ let self_ty = field. ty ( tcx, substs) ;
1410
+ err. span_note (
1411
+ tcx. def_span ( pick. item . def_id ) ,
1412
+ & format ! ( "the method `{item_name}` exists on the type `{self_ty}`" ) ,
1413
+ ) ;
1414
+ let ( article, kind, variant, question) =
1415
+ if Some ( kind. did ( ) ) == tcx. get_diagnostic_item ( sym:: Result ) {
1416
+ ( "a" , "Result" , "Err" , ret_ty_matches ( sym:: Result ) )
1417
+ } else if Some ( kind. did ( ) ) == tcx. get_diagnostic_item ( sym:: Option ) {
1418
+ ( "an" , "Option" , "None" , ret_ty_matches ( sym:: Option ) )
1419
+ } else {
1420
+ return ;
1421
+ } ;
1422
+ if question {
1423
+ err. span_suggestion_verbose (
1424
+ expr. span . shrink_to_hi ( ) ,
1425
+ format ! (
1426
+ "use the `?` operator to extract the `{self_ty}` value, propagating \
1427
+ {article} `{kind}::{variant}` value to the caller"
1428
+ ) ,
1429
+ "?" . to_owned ( ) ,
1430
+ Applicability :: MachineApplicable ,
1431
+ ) ;
1432
+ } else {
1433
+ err. span_suggestion_verbose (
1434
+ expr. span . shrink_to_hi ( ) ,
1435
+ format ! (
1436
+ "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
1437
+ panicking if the value is {article} `{kind}::{variant}`"
1438
+ ) ,
1439
+ ".expect(\" REASON\" )" . to_owned ( ) ,
1440
+ Applicability :: HasPlaceholders ,
1441
+ ) ;
1442
+ }
1443
+ }
1444
+ // FIXME(compiler-errors): Support suggestions for other matching enum variants
1445
+ _ => { }
1446
+ }
1447
+ }
1448
+
1346
1449
pub ( crate ) fn note_unmet_impls_on_type (
1347
1450
& self ,
1348
1451
err : & mut Diagnostic ,
@@ -1662,13 +1765,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1662
1765
( self . tcx . mk_mut_ref ( self . tcx . lifetimes . re_erased , rcvr_ty) , "&mut " ) ,
1663
1766
( self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_erased , rcvr_ty) , "&" ) ,
1664
1767
] {
1665
- match self . lookup_probe (
1666
- span,
1667
- item_name,
1668
- * rcvr_ty,
1669
- rcvr,
1670
- crate :: check:: method:: probe:: ProbeScope :: AllTraits ,
1671
- ) {
1768
+ match self . lookup_probe ( span, item_name, * rcvr_ty, rcvr, ProbeScope :: AllTraits ) {
1672
1769
Ok ( pick) => {
1673
1770
// If the method is defined for the receiver we have, it likely wasn't `use`d.
1674
1771
// We point at the method, but we just skip the rest of the check for arbitrary
@@ -1700,13 +1797,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1700
1797
( self . tcx . mk_diagnostic_item ( * rcvr_ty, sym:: Arc ) , "Arc::new" ) ,
1701
1798
( self . tcx . mk_diagnostic_item ( * rcvr_ty, sym:: Rc ) , "Rc::new" ) ,
1702
1799
] {
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
- ) {
1800
+ if let Some ( new_rcvr_t) = * rcvr_ty
1801
+ && let Ok ( pick) = self . lookup_probe (
1802
+ span,
1803
+ item_name,
1804
+ new_rcvr_t,
1805
+ rcvr,
1806
+ ProbeScope :: AllTraits ,
1807
+ )
1808
+ {
1710
1809
debug ! ( "try_alt_rcvr: pick candidate {:?}" , pick) ;
1711
1810
let did = Some ( pick. item . container . id ( ) ) ;
1712
1811
// We don't want to suggest a container type when the missing
0 commit comments