22//! found or is otherwise invalid.
33
44use crate :: check:: FnCtxt ;
5+ use rustc_ast:: ast:: Mutability ;
56use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
67use rustc_errors:: {
78 pluralize, struct_span_err, Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed ,
@@ -30,7 +31,7 @@ use rustc_trait_selection::traits::{
3031use std:: cmp:: Ordering ;
3132use std:: iter;
3233
33- use super :: probe:: { IsSuggestion , Mode , ProbeScope } ;
34+ use super :: probe:: { AutorefOrPtrAdjustment , IsSuggestion , Mode , ProbeScope } ;
3435use super :: { CandidateSource , MethodError , NoMatchData } ;
3536
3637impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -983,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
983984 self . check_for_field_method ( & mut err, source, span, actual, item_name) ;
984985 }
985986
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) ;
987988
988989 bound_spans. sort ( ) ;
989990 bound_spans. dedup ( ) ;
@@ -1395,7 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13951396 }
13961397 }
13971398
1398- fn check_for_unwrap_self (
1399+ fn check_for_inner_self (
13991400 & self ,
14001401 err : & mut Diagnostic ,
14011402 source : SelfSource < ' tcx > ,
@@ -1408,81 +1409,168 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14081409 let call_expr = tcx. hir ( ) . expect_expr ( tcx. hir ( ) . get_parent_node ( expr. hir_id ) ) ;
14091410
14101411 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+ }
14141425
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+ } ;
14211451
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+ _ => { }
14251491 }
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
14441492 }
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 ; } ;
14461505
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 ,
14611530 } ;
1462- if question {
14631531 err. span_suggestion_verbose (
14641532 expr. span . shrink_to_hi ( ) ,
14651533 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} "
14681536 ) ,
1469- "?" ,
1470- Applicability :: MachineApplicable ,
1537+ suggestion ,
1538+ Applicability :: MaybeIncorrect ,
14711539 ) ;
1472- } else {
1540+ } else if tcx . is_diagnostic_item ( sym :: Mutex , inner_id ) {
14731541 err. span_suggestion_verbose (
14741542 expr. span . shrink_to_hi ( ) ,
14751543 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 "
14781546 ) ,
1479- ".expect( \" REASON \" )" ,
1480- Applicability :: HasPlaceholders ,
1547+ ".lock().unwrap( )" ,
1548+ Applicability :: MaybeIncorrect ,
14811549 ) ;
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+ ) ;
14831573 }
1484- // FIXME(compiler-errors): Support suggestions for other matching enum variants
1485- _ => { }
14861574 }
14871575 }
14881576
0 commit comments