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,168 @@ 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 :: TraitsInScope ,
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
- } ;
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 :: TraitsInScope ,
1504
+ ) else { return ; } ;
1446
1505
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 ;
1506
+ let name = self . ty_to_value_string ( actual) ;
1507
+ let inner_id = kind. did ( ) ;
1508
+ let mutable = if let Some ( AutorefOrPtrAdjustment :: Autoref { mutbl, .. } ) =
1509
+ pick. autoref_or_ptr_adjustment
1510
+ {
1511
+ Some ( mutbl)
1512
+ } else {
1513
+ None
1514
+ } ;
1515
+
1516
+ if tcx. is_diagnostic_item ( sym:: LocalKey , inner_id) {
1517
+ err. help ( "use `with` or `try_with` to access thread local storage" ) ;
1518
+ } else if Some ( kind. did ( ) ) == tcx. lang_items ( ) . maybe_uninit ( ) {
1519
+ err. help ( format ! (
1520
+ "if this `{name}` has been initialized, \
1521
+ use one of the `assume_init` methods to access the inner value"
1522
+ ) ) ;
1523
+ } else if tcx. is_diagnostic_item ( sym:: RefCell , inner_id) {
1524
+ let ( suggestion, borrow_kind, panic_if) = match mutable {
1525
+ Some ( Mutability :: Not ) => ( ".borrow()" , "borrow" , "a mutable borrow exists" ) ,
1526
+ Some ( Mutability :: Mut ) => {
1527
+ ( ".borrow_mut()" , "mutably borrow" , "any borrows exist" )
1528
+ }
1529
+ None => return ,
1461
1530
} ;
1462
- if question {
1463
1531
err. span_suggestion_verbose (
1464
1532
expr. span . shrink_to_hi ( ) ,
1465
1533
format ! (
1466
- "use the `?` operator to extract the `{self_ty}` value, propagating \
1467
- {article} `{kind}::{variant}` value to the caller "
1534
+ "use `{suggestion}` to {borrow_kind} the `{ty}`, \
1535
+ panicking if {panic_if} "
1468
1536
) ,
1469
- "?" ,
1470
- Applicability :: MachineApplicable ,
1537
+ suggestion ,
1538
+ Applicability :: MaybeIncorrect ,
1471
1539
) ;
1472
- } else {
1540
+ } else if tcx . is_diagnostic_item ( sym :: Mutex , inner_id ) {
1473
1541
err. span_suggestion_verbose (
1474
1542
expr. span . shrink_to_hi ( ) ,
1475
1543
format ! (
1476
- "consider using `{kind}::expect ` to unwrap the `{self_ty}` value , \
1477
- panicking if the value is {article} `{kind}::{variant}` "
1544
+ "use `.lock().unwrap() ` to borrow the `{ty}` , \
1545
+ blocking the current thread until it can be acquired "
1478
1546
) ,
1479
- ".expect( \" REASON \" )" ,
1480
- Applicability :: HasPlaceholders ,
1547
+ ".lock().unwrap( )" ,
1548
+ Applicability :: MaybeIncorrect ,
1481
1549
) ;
1482
- }
1550
+ } else if tcx. is_diagnostic_item ( sym:: RwLock , inner_id) {
1551
+ let ( suggestion, borrow_kind) = match mutable {
1552
+ Some ( Mutability :: Not ) => ( ".read().unwrap()" , "borrow" ) ,
1553
+ Some ( Mutability :: Mut ) => ( ".write().unwrap()" , "mutably borrow" ) ,
1554
+ None => return ,
1555
+ } ;
1556
+ err. span_suggestion_verbose (
1557
+ expr. span . shrink_to_hi ( ) ,
1558
+ format ! (
1559
+ "use `{suggestion}` to {borrow_kind} the `{ty}`, \
1560
+ blocking the current thread until it can be acquired"
1561
+ ) ,
1562
+ suggestion,
1563
+ Applicability :: MaybeIncorrect ,
1564
+ ) ;
1565
+ } else {
1566
+ return ;
1567
+ } ;
1568
+
1569
+ err. span_note (
1570
+ tcx. def_span ( pick. item . def_id ) ,
1571
+ & format ! ( "the method `{item_name}` exists on the type `{ty}`" ) ,
1572
+ ) ;
1483
1573
}
1484
- // FIXME(compiler-errors): Support suggestions for other matching enum variants
1485
- _ => { }
1486
1574
}
1487
1575
}
1488
1576
0 commit comments