@@ -65,6 +65,7 @@ use rustc_hir::def_id::DefId;
6565use rustc_hir:: lang_items:: LangItem ;
6666use rustc_hir:: { Item , ItemKind , Node } ;
6767use rustc_middle:: dep_graph:: DepContext ;
68+ use rustc_middle:: ty:: print:: with_no_trimmed_paths;
6869use rustc_middle:: ty:: {
6970 self ,
7071 error:: TypeError ,
@@ -1736,6 +1737,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17361737 } ;
17371738
17381739 if should_suggest_fixes {
1740+ self . suggest_tuple_pattern ( cause, & exp_found, diag) ;
17391741 self . suggest_as_ref_where_appropriate ( span, & exp_found, diag) ;
17401742 self . suggest_accessing_field_where_appropriate ( cause, & exp_found, diag) ;
17411743 self . suggest_await_on_expect_found ( cause, span, & exp_found, diag) ;
@@ -1766,6 +1768,73 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17661768 self . note_error_origin ( diag, cause, exp_found, terr) ;
17671769 }
17681770
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+
17691838 pub fn get_impl_future_output_ty ( & self , ty : Ty < ' tcx > ) -> Option < Binder < ' tcx , Ty < ' tcx > > > {
17701839 if let ty:: Opaque ( def_id, substs) = ty. kind ( ) {
17711840 let future_trait = self . tcx . require_lang_item ( LangItem :: Future , None ) ;
0 commit comments