@@ -904,6 +904,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
904
904
// Keep track of which fields have already appeared in the pattern.
905
905
let mut used_fields = FxHashMap ( ) ;
906
906
907
+ let mut inexistent_fields = vec ! [ ] ;
907
908
// Typecheck each field.
908
909
for & Spanned { node : ref field, span } in fields {
909
910
let field_ty = match used_fields. entry ( field. name ) {
@@ -927,34 +928,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
927
928
self . field_ty ( span, f, substs)
928
929
} )
929
930
. unwrap_or_else ( || {
930
- let mut err = struct_span_err ! (
931
- tcx. sess,
932
- span,
933
- E0026 ,
934
- "{} `{}` does not have a field named `{}`" ,
935
- kind_name,
936
- tcx. item_path_str( variant. did) ,
937
- field. name
938
- ) ;
939
- err. span_label ( span,
940
- format ! ( "{} `{}` does not have field `{}`" ,
941
- kind_name,
942
- tcx. item_path_str( variant. did) ,
943
- field. name) ) ;
944
- if tcx. sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
945
- err. note (
946
- "This error indicates that a struct pattern attempted to \
947
- extract a non-existent field from a struct. Struct fields \
948
- are identified by the name used before the colon : so struct \
949
- patterns should resemble the declaration of the struct type \
950
- being matched.\n \n \
951
- If you are using shorthand field patterns but want to refer \
952
- to the struct field by a different name, you should rename \
953
- it explicitly."
954
- ) ;
955
- }
956
- err. emit ( ) ;
957
-
931
+ inexistent_fields. push ( ( span, field. name ) ) ;
958
932
tcx. types . err
959
933
} )
960
934
}
@@ -963,6 +937,47 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
963
937
self . check_pat_walk ( & field. pat , field_ty, def_bm, true ) ;
964
938
}
965
939
940
+ if inexistent_fields. len ( ) > 0 {
941
+ let ( field_names, t, plural) = if inexistent_fields. len ( ) == 1 {
942
+ ( format ! ( "a field named `{}`" , inexistent_fields[ 0 ] . 1 ) , "this" , "" )
943
+ } else {
944
+ ( format ! ( "fields named {}" ,
945
+ inexistent_fields. iter( )
946
+ . map( |( _, name) | format!( "`{}`" , name) )
947
+ . collect:: <Vec <String >>( )
948
+ . join( ", " ) ) , "these" , "s" )
949
+ } ;
950
+ let spans = inexistent_fields. iter ( ) . map ( |( span, _) | * span) . collect :: < Vec < _ > > ( ) ;
951
+ let mut err = struct_span_err ! ( tcx. sess,
952
+ spans,
953
+ E0026 ,
954
+ "{} `{}` does not have {}" ,
955
+ kind_name,
956
+ tcx. item_path_str( variant. did) ,
957
+ field_names) ;
958
+ if let Some ( ( span, _) ) = inexistent_fields. last ( ) {
959
+ err. span_label ( * span,
960
+ format ! ( "{} `{}` does not have {} field{}" ,
961
+ kind_name,
962
+ tcx. item_path_str( variant. did) ,
963
+ t,
964
+ plural) ) ;
965
+ }
966
+ if tcx. sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
967
+ err. note (
968
+ "This error indicates that a struct pattern attempted to \
969
+ extract a non-existent field from a struct. Struct fields \
970
+ are identified by the name used before the colon : so struct \
971
+ patterns should resemble the declaration of the struct type \
972
+ being matched.\n \n \
973
+ If you are using shorthand field patterns but want to refer \
974
+ to the struct field by a different name, you should rename \
975
+ it explicitly."
976
+ ) ;
977
+ }
978
+ err. emit ( ) ;
979
+ }
980
+
966
981
// Require `..` if struct has non_exhaustive attribute.
967
982
if adt. is_struct ( ) && adt. is_non_exhaustive ( ) && !adt. did . is_local ( ) && !etc {
968
983
span_err ! ( tcx. sess, span, E0638 ,
@@ -979,13 +994,25 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
979
994
tcx. sess . span_err ( span, "`..` cannot be used in union patterns" ) ;
980
995
}
981
996
} else if !etc {
982
- for field in variant. fields
997
+ let unmentioned_fields = variant. fields
983
998
. iter ( )
984
- . filter ( |field| !used_fields. contains_key ( & field. name ) ) {
999
+ . map ( |field| field. name )
1000
+ . filter ( |field| !used_fields. contains_key ( & field) )
1001
+ . collect :: < Vec < _ > > ( ) ;
1002
+ if unmentioned_fields. len ( ) > 0 {
1003
+ let field_names = if unmentioned_fields. len ( ) == 1 {
1004
+ format ! ( "field `{}`" , unmentioned_fields[ 0 ] )
1005
+ } else {
1006
+ format ! ( "fields {}" ,
1007
+ unmentioned_fields. iter( )
1008
+ . map( |name| format!( "`{}`" , name) )
1009
+ . collect:: <Vec <String >>( )
1010
+ . join( ", " ) )
1011
+ } ;
985
1012
let mut diag = struct_span_err ! ( tcx. sess, span, E0027 ,
986
- "pattern does not mention field `{}` " ,
987
- field . name ) ;
988
- diag. span_label ( span, format ! ( "missing field `{}` " , field . name ) ) ;
1013
+ "pattern does not mention {} " ,
1014
+ field_names ) ;
1015
+ diag. span_label ( span, format ! ( "missing {} " , field_names ) ) ;
989
1016
if variant. ctor_kind == CtorKind :: Fn {
990
1017
diag. note ( "trying to match a tuple variant with a struct variant pattern" ) ;
991
1018
}
0 commit comments