@@ -15,7 +15,7 @@ use rustc_span::hygiene::DesugaringKind;
15
15
use rustc_span:: lev_distance:: find_best_match_for_name;
16
16
use rustc_span:: source_map:: { Span , Spanned } ;
17
17
use rustc_span:: symbol:: Ident ;
18
- use rustc_span:: { BytePos , DUMMY_SP } ;
18
+ use rustc_span:: { BytePos , MultiSpan , DUMMY_SP } ;
19
19
use rustc_trait_selection:: autoderef:: Autoderef ;
20
20
use rustc_trait_selection:: traits:: { ObligationCause , Pattern } ;
21
21
use ty:: VariantDef ;
@@ -990,10 +990,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
990
990
) {
991
991
let subpats_ending = pluralize ! ( subpats. len( ) ) ;
992
992
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 ( ) ;
993
1000
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
+
994
1009
let mut err = struct_span_err ! (
995
1010
self . tcx. sess,
996
- pat_span ,
1011
+ MultiSpan :: from_spans ( subpat_spans . clone ( ) ) ,
997
1012
E0023 ,
998
1013
"this pattern has {} field{}, but the corresponding {} has {} field{}" ,
999
1014
subpats. len( ) ,
@@ -1003,10 +1018,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1003
1018
fields_ending,
1004
1019
) ;
1005
1020
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
+ ) ;
1010
1037
1011
1038
// Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
1012
1039
// More generally, the expected type wants a tuple variant with one field of an
0 commit comments