@@ -65,6 +65,7 @@ use rustc_hir::def_id::DefId;
65
65
use rustc_hir:: lang_items:: LangItem ;
66
66
use rustc_hir:: { Item , ItemKind , Node } ;
67
67
use rustc_middle:: dep_graph:: DepContext ;
68
+ use rustc_middle:: ty:: print:: with_no_trimmed_paths;
68
69
use rustc_middle:: ty:: {
69
70
self ,
70
71
error:: TypeError ,
@@ -1736,6 +1737,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1736
1737
} ;
1737
1738
1738
1739
if should_suggest_fixes {
1740
+ self . suggest_tuple_pattern ( cause, & exp_found, diag) ;
1739
1741
self . suggest_as_ref_where_appropriate ( span, & exp_found, diag) ;
1740
1742
self . suggest_accessing_field_where_appropriate ( cause, & exp_found, diag) ;
1741
1743
self . suggest_await_on_expect_found ( cause, span, & exp_found, diag) ;
@@ -1766,6 +1768,73 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1766
1768
self . note_error_origin ( diag, cause, exp_found, terr) ;
1767
1769
}
1768
1770
1771
+ fn suggest_tuple_pattern (
1772
+ & self ,
1773
+ cause : & ObligationCause < ' tcx > ,
1774
+ exp_found : & ty:: error:: ExpectedFound < Ty < ' tcx > > ,
1775
+ diag : & mut Diagnostic ,
1776
+ ) {
1777
+ // Heavily inspired by `FnCtxt::suggest_compatible_variants`, with
1778
+ // some modifications due to that being in typeck and this being in infer.
1779
+ if let ObligationCauseCode :: Pattern { .. } = cause. code ( ) {
1780
+ if let ty:: Adt ( expected_adt, substs) = exp_found. expected . kind ( ) {
1781
+ let compatible_variants: Vec < _ > = expected_adt
1782
+ . variants ( )
1783
+ . iter ( )
1784
+ . filter ( |variant| {
1785
+ variant. fields . len ( ) == 1 && variant. ctor_kind == hir:: def:: CtorKind :: Fn
1786
+ } )
1787
+ . filter_map ( |variant| {
1788
+ let sole_field = & variant. fields [ 0 ] ;
1789
+ let sole_field_ty = sole_field. ty ( self . tcx , substs) ;
1790
+ if same_type_modulo_infer ( sole_field_ty, exp_found. found ) {
1791
+ let variant_path =
1792
+ with_no_trimmed_paths ! ( self . tcx. def_path_str( variant. def_id) ) ;
1793
+ // FIXME #56861: DRYer prelude filtering
1794
+ if let Some ( path) = variant_path. strip_prefix ( "std::prelude::" ) {
1795
+ if let Some ( ( _, path) ) = path. split_once ( "::" ) {
1796
+ return Some ( path. to_string ( ) ) ;
1797
+ }
1798
+ }
1799
+ Some ( variant_path)
1800
+ } else {
1801
+ None
1802
+ }
1803
+ } )
1804
+ . collect ( ) ;
1805
+ match & compatible_variants[ ..] {
1806
+ [ ] => { }
1807
+ [ variant] => {
1808
+ diag. multipart_suggestion_verbose (
1809
+ & format ! ( "try wrapping the pattern in `{}`" , variant) ,
1810
+ vec ! [
1811
+ ( cause. span. shrink_to_lo( ) , format!( "{}(" , variant) ) ,
1812
+ ( cause. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
1813
+ ] ,
1814
+ Applicability :: MaybeIncorrect ,
1815
+ ) ;
1816
+ }
1817
+ _ => {
1818
+ // More than one matching variant.
1819
+ diag. multipart_suggestions (
1820
+ & format ! (
1821
+ "try wrapping the pattern in a variant of `{}`" ,
1822
+ self . tcx. def_path_str( expected_adt. did( ) )
1823
+ ) ,
1824
+ compatible_variants. into_iter ( ) . map ( |variant| {
1825
+ vec ! [
1826
+ ( cause. span. shrink_to_lo( ) , format!( "{}(" , variant) ) ,
1827
+ ( cause. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
1828
+ ]
1829
+ } ) ,
1830
+ Applicability :: MaybeIncorrect ,
1831
+ ) ;
1832
+ }
1833
+ }
1834
+ }
1835
+ }
1836
+ }
1837
+
1769
1838
pub fn get_impl_future_output_ty ( & self , ty : Ty < ' tcx > ) -> Option < Binder < ' tcx , Ty < ' tcx > > > {
1770
1839
if let ty:: Opaque ( def_id, substs) = ty. kind ( ) {
1771
1840
let future_trait = self . tcx . require_lang_item ( LangItem :: Future , None ) ;
0 commit comments