@@ -15,7 +15,7 @@ use rustc_span::hygiene::DesugaringKind;
1515use rustc_span:: lev_distance:: find_best_match_for_name;
1616use rustc_span:: source_map:: { Span , Spanned } ;
1717use rustc_span:: symbol:: Ident ;
18- use rustc_span:: { BytePos , DUMMY_SP } ;
18+ use rustc_span:: { BytePos , MultiSpan , DUMMY_SP } ;
1919use rustc_trait_selection:: autoderef:: Autoderef ;
2020use rustc_trait_selection:: traits:: { ObligationCause , Pattern } ;
2121use ty:: VariantDef ;
@@ -990,10 +990,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
990990 ) {
991991 let subpats_ending = pluralize ! ( subpats. len( ) ) ;
992992 let fields_ending = pluralize ! ( fields. len( ) ) ;
993+
994+ let subpat_spans = if subpats. is_empty ( ) {
995+ vec ! [ pat_span]
996+ } else {
997+ subpats. iter ( ) . map ( |p| p. span ) . collect ( )
998+ } ;
999+ let last_subpat_span = * subpat_spans. last ( ) . unwrap ( ) ;
9931000 let res_span = self . tcx . def_span ( res. def_id ( ) ) ;
1001+ let def_ident_span = self . tcx . def_ident_span ( res. def_id ( ) ) . unwrap_or ( res_span) ;
1002+ let field_def_spans = if fields. is_empty ( ) {
1003+ vec ! [ res_span]
1004+ } else {
1005+ fields. iter ( ) . map ( |f| f. ident . span ) . collect ( )
1006+ } ;
1007+ let last_field_def_span = * field_def_spans. last ( ) . unwrap ( ) ;
1008+
9941009 let mut err = struct_span_err ! (
9951010 self . tcx. sess,
996- pat_span ,
1011+ MultiSpan :: from_spans ( subpat_spans . clone ( ) ) ,
9971012 E0023 ,
9981013 "this pattern has {} field{}, but the corresponding {} has {} field{}" ,
9991014 subpats. len( ) ,
@@ -1003,10 +1018,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10031018 fields_ending,
10041019 ) ;
10051020 err. span_label (
1006- pat_span,
1007- format ! ( "expected {} field{}, found {}" , fields. len( ) , fields_ending, subpats. len( ) , ) ,
1008- )
1009- . span_label ( res_span, format ! ( "{} defined here" , res. descr( ) ) ) ;
1021+ last_subpat_span,
1022+ & format ! ( "expected {} field{}, found {}" , fields. len( ) , fields_ending, subpats. len( ) ) ,
1023+ ) ;
1024+ if self . tcx . sess . source_map ( ) . is_multiline ( qpath. span ( ) . between ( last_subpat_span) ) {
1025+ err. span_label ( qpath. span ( ) , "" ) ;
1026+ }
1027+ if self . tcx . sess . source_map ( ) . is_multiline ( def_ident_span. between ( last_field_def_span) ) {
1028+ err. span_label ( def_ident_span, format ! ( "{} defined here" , res. descr( ) ) ) ;
1029+ }
1030+ for span in & field_def_spans[ ..field_def_spans. len ( ) - 1 ] {
1031+ err. span_label ( * span, "" ) ;
1032+ }
1033+ err. span_label (
1034+ last_field_def_span,
1035+ & format ! ( "{} has {} field{}" , res. descr( ) , fields. len( ) , fields_ending) ,
1036+ ) ;
10101037
10111038 // Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
10121039 // More generally, the expected type wants a tuple variant with one field of an
0 commit comments