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,159 @@ 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 :: 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+ } ;
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- } ;
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) {
14631547 err. span_suggestion_verbose (
14641548 expr. span . shrink_to_hi ( ) ,
14651549 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 "
14681552 ) ,
1469- "? " ,
1470- Applicability :: MachineApplicable ,
1553+ ".lock().unwrap() " ,
1554+ Applicability :: MaybeIncorrect ,
14711555 ) ;
14721556 } 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+ ) ;
14831564 }
1484- // FIXME(compiler-errors): Support suggestions for other matching enum variants
1485- _ => { }
14861565 }
14871566 }
14881567
0 commit comments