2
2
//! found or is otherwise invalid.
3
3
4
4
use crate :: check:: FnCtxt ;
5
+ use rustc_ast:: ast:: Mutability ;
5
6
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
6
7
use rustc_errors:: {
7
8
pluralize, struct_span_err, Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed ,
@@ -30,7 +31,7 @@ use rustc_trait_selection::traits::{
30
31
use std:: cmp:: Ordering ;
31
32
use std:: iter;
32
33
33
- use super :: probe:: { IsSuggestion , Mode , ProbeScope } ;
34
+ use super :: probe:: { AutorefOrPtrAdjustment , IsSuggestion , Mode , ProbeScope } ;
34
35
use super :: { CandidateSource , MethodError , NoMatchData } ;
35
36
36
37
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -983,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
983
984
self . check_for_field_method ( & mut err, source, span, actual, item_name) ;
984
985
}
985
986
986
- self . check_for_unwrap_self ( & mut err, source, span, actual, item_name) ;
987
+ self . check_for_inner_self ( & mut err, source, span, actual, item_name) ;
987
988
988
989
bound_spans. sort ( ) ;
989
990
bound_spans. dedup ( ) ;
@@ -1395,7 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1395
1396
}
1396
1397
}
1397
1398
1398
- fn check_for_unwrap_self (
1399
+ fn check_for_inner_self (
1399
1400
& self ,
1400
1401
err : & mut Diagnostic ,
1401
1402
source : SelfSource < ' tcx > ,
@@ -1408,81 +1409,159 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1408
1409
let call_expr = tcx. hir ( ) . expect_expr ( tcx. hir ( ) . get_parent_node ( expr. hir_id ) ) ;
1409
1410
1410
1411
let ty:: Adt ( kind, substs) = actual. kind ( ) else { return ; } ;
1411
- if !kind. is_enum ( ) {
1412
- return ;
1413
- }
1412
+ match kind. adt_kind ( ) {
1413
+ ty:: AdtKind :: Enum => {
1414
+ let matching_variants: Vec < _ > = kind
1415
+ . variants ( )
1416
+ . iter ( )
1417
+ . flat_map ( |variant| {
1418
+ let [ field] = & variant. fields [ ..] else { return None ; } ;
1419
+ let field_ty = field. ty ( tcx, substs) ;
1420
+
1421
+ // Skip `_`, since that'll just lead to ambiguity.
1422
+ if self . resolve_vars_if_possible ( field_ty) . is_ty_var ( ) {
1423
+ return None ;
1424
+ }
1414
1425
1415
- let matching_variants: Vec < _ > = kind
1416
- . variants ( )
1417
- . iter ( )
1418
- . flat_map ( |variant| {
1419
- let [ field] = & variant. fields [ ..] else { return None ; } ;
1420
- let field_ty = field. ty ( tcx, substs) ;
1426
+ self . lookup_probe (
1427
+ span,
1428
+ item_name,
1429
+ field_ty,
1430
+ call_expr,
1431
+ ProbeScope :: AllTraits ,
1432
+ )
1433
+ . ok ( )
1434
+ . map ( |pick| ( variant, field, pick) )
1435
+ } )
1436
+ . collect ( ) ;
1437
+
1438
+ let ret_ty_matches = |diagnostic_item| {
1439
+ if let Some ( ret_ty) = self
1440
+ . ret_coercion
1441
+ . as_ref ( )
1442
+ . map ( |c| self . resolve_vars_if_possible ( c. borrow ( ) . expected_ty ( ) ) )
1443
+ && let ty:: Adt ( kind, _) = ret_ty. kind ( )
1444
+ && tcx. get_diagnostic_item ( diagnostic_item) == Some ( kind. did ( ) )
1445
+ {
1446
+ true
1447
+ } else {
1448
+ false
1449
+ }
1450
+ } ;
1421
1451
1422
- // Skip `_`, since that'll just lead to ambiguity.
1423
- if self . resolve_vars_if_possible ( field_ty) . is_ty_var ( ) {
1424
- return None ;
1452
+ match & matching_variants[ ..] {
1453
+ [ ( _, field, pick) ] => {
1454
+ let self_ty = field. ty ( tcx, substs) ;
1455
+ err. span_note (
1456
+ tcx. def_span ( pick. item . def_id ) ,
1457
+ & format ! ( "the method `{item_name}` exists on the type `{self_ty}`" ) ,
1458
+ ) ;
1459
+ let ( article, kind, variant, question) =
1460
+ if tcx. is_diagnostic_item ( sym:: Result , kind. did ( ) ) {
1461
+ ( "a" , "Result" , "Err" , ret_ty_matches ( sym:: Result ) )
1462
+ } else if tcx. is_diagnostic_item ( sym:: Option , kind. did ( ) ) {
1463
+ ( "an" , "Option" , "None" , ret_ty_matches ( sym:: Option ) )
1464
+ } else {
1465
+ return ;
1466
+ } ;
1467
+ if question {
1468
+ err. span_suggestion_verbose (
1469
+ expr. span . shrink_to_hi ( ) ,
1470
+ format ! (
1471
+ "use the `?` operator to extract the `{self_ty}` value, propagating \
1472
+ {article} `{kind}::{variant}` value to the caller"
1473
+ ) ,
1474
+ "?" ,
1475
+ Applicability :: MachineApplicable ,
1476
+ ) ;
1477
+ } else {
1478
+ err. span_suggestion_verbose (
1479
+ expr. span . shrink_to_hi ( ) ,
1480
+ format ! (
1481
+ "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
1482
+ panicking if the value is {article} `{kind}::{variant}`"
1483
+ ) ,
1484
+ ".expect(\" REASON\" )" ,
1485
+ Applicability :: HasPlaceholders ,
1486
+ ) ;
1487
+ }
1488
+ }
1489
+ // FIXME(compiler-errors): Support suggestions for other matching enum variants
1490
+ _ => { }
1425
1491
}
1426
-
1427
- self . lookup_probe ( span, item_name, field_ty, call_expr, ProbeScope :: AllTraits )
1428
- . ok ( )
1429
- . map ( |pick| ( variant, field, pick) )
1430
- } )
1431
- . collect ( ) ;
1432
-
1433
- let ret_ty_matches = |diagnostic_item| {
1434
- if let Some ( ret_ty) = self
1435
- . ret_coercion
1436
- . as_ref ( )
1437
- . map ( |c| self . resolve_vars_if_possible ( c. borrow ( ) . expected_ty ( ) ) )
1438
- && let ty:: Adt ( kind, _) = ret_ty. kind ( )
1439
- && tcx. get_diagnostic_item ( diagnostic_item) == Some ( kind. did ( ) )
1440
- {
1441
- true
1442
- } else {
1443
- false
1444
1492
}
1445
- } ;
1446
-
1447
- match & matching_variants[ ..] {
1448
- [ ( _, field, pick) ] => {
1449
- let self_ty = field. ty ( tcx, substs) ;
1450
- err. span_note (
1451
- tcx. def_span ( pick. item . def_id ) ,
1452
- & format ! ( "the method `{item_name}` exists on the type `{self_ty}`" ) ,
1453
- ) ;
1454
- let ( article, kind, variant, question) =
1455
- if Some ( kind. did ( ) ) == tcx. get_diagnostic_item ( sym:: Result ) {
1456
- ( "a" , "Result" , "Err" , ret_ty_matches ( sym:: Result ) )
1457
- } else if Some ( kind. did ( ) ) == tcx. get_diagnostic_item ( sym:: Option ) {
1458
- ( "an" , "Option" , "None" , ret_ty_matches ( sym:: Option ) )
1459
- } else {
1460
- return ;
1461
- } ;
1462
- if question {
1493
+ // Target wrapper types - types that wrap or pretend to wrap another type,
1494
+ // perhaps this inner type is meant to be called?
1495
+ ty:: AdtKind :: Struct | ty:: AdtKind :: Union => {
1496
+ let [ first] = * * * substs else { return ; } ;
1497
+ let ty:: GenericArgKind :: Type ( ty) = first. unpack ( ) else { return ; } ;
1498
+ let Ok ( pick) = self . lookup_probe (
1499
+ span,
1500
+ item_name,
1501
+ ty,
1502
+ call_expr,
1503
+ ProbeScope :: AllTraits ,
1504
+ ) else { return ; } ;
1505
+
1506
+ let name = self . ty_to_value_string ( actual) ;
1507
+ let inner_id = kind. did ( ) ;
1508
+
1509
+ if tcx. is_diagnostic_item ( sym:: LocalKey , inner_id) {
1510
+ err. help ( "use `with` or `try_with` to access the contents of threadlocals" ) ;
1511
+ } else if Some ( kind. did ( ) ) == tcx. lang_items ( ) . maybe_uninit ( ) {
1512
+ err. help ( format ! (
1513
+ "if this `{name}` has been initialized, \
1514
+ use one of the `assume_init` methods to access the inner value"
1515
+ ) ) ;
1516
+ } else if tcx. is_diagnostic_item ( sym:: RefCell , inner_id) {
1517
+ match pick. autoref_or_ptr_adjustment {
1518
+ Some ( AutorefOrPtrAdjustment :: Autoref {
1519
+ mutbl : Mutability :: Not , ..
1520
+ } ) => {
1521
+ err. span_suggestion_verbose (
1522
+ expr. span . shrink_to_hi ( ) ,
1523
+ format ! (
1524
+ "use `.borrow()` to borrow the {ty}, \
1525
+ panicking if any outstanding mutable borrows exist."
1526
+ ) ,
1527
+ ".borrow()" ,
1528
+ Applicability :: MaybeIncorrect ,
1529
+ ) ;
1530
+ }
1531
+ Some ( AutorefOrPtrAdjustment :: Autoref {
1532
+ mutbl : Mutability :: Mut , ..
1533
+ } ) => {
1534
+ err. span_suggestion_verbose (
1535
+ expr. span . shrink_to_hi ( ) ,
1536
+ format ! (
1537
+ "use `.borrow_mut()` to mutably borrow the {ty}, \
1538
+ panicking if any outstanding borrows exist."
1539
+ ) ,
1540
+ ".borrow_mut()" ,
1541
+ Applicability :: MaybeIncorrect ,
1542
+ ) ;
1543
+ }
1544
+ _ => return ,
1545
+ }
1546
+ } else if tcx. is_diagnostic_item ( sym:: Mutex , inner_id) {
1463
1547
err. span_suggestion_verbose (
1464
1548
expr. span . shrink_to_hi ( ) ,
1465
1549
format ! (
1466
- "use the `?` operator to extract the `{self_ty}` value, propagating \
1467
- {article} `{kind}::{variant}` value to the caller "
1550
+ "use `.lock()` to borrow the {ty}, \
1551
+ blocking the current thread until it can be acquired "
1468
1552
) ,
1469
- "? " ,
1470
- Applicability :: MachineApplicable ,
1553
+ ".lock().unwrap() " ,
1554
+ Applicability :: MaybeIncorrect ,
1471
1555
) ;
1472
1556
} else {
1473
- err. span_suggestion_verbose (
1474
- expr. span . shrink_to_hi ( ) ,
1475
- format ! (
1476
- "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
1477
- panicking if the value is {article} `{kind}::{variant}`"
1478
- ) ,
1479
- ".expect(\" REASON\" )" ,
1480
- Applicability :: HasPlaceholders ,
1481
- ) ;
1482
- }
1557
+ return ;
1558
+ } ;
1559
+
1560
+ err. span_note (
1561
+ tcx. def_span ( pick. item . def_id ) ,
1562
+ & format ! ( "the method `{item_name}` exists on the type `{ty}`" ) ,
1563
+ ) ;
1483
1564
}
1484
- // FIXME(compiler-errors): Support suggestions for other matching enum variants
1485
- _ => { }
1486
1565
}
1487
1566
}
1488
1567
0 commit comments