@@ -808,15 +808,15 @@ fn check_matcher_core(sess: &ParseSess,
808
808
if let TokenTree :: MetaVarDecl ( _, ref name, ref frag_spec) = * token {
809
809
for next_token in & suffix_first. tokens {
810
810
match is_in_follow ( next_token, & frag_spec. as_str ( ) ) {
811
- Err ( ( msg, help) ) => {
811
+ IsInFollow :: Invalid ( msg, help) => {
812
812
sess. span_diagnostic . struct_span_err ( next_token. span ( ) , & msg)
813
813
. help ( help) . emit ( ) ;
814
814
// don't bother reporting every source of
815
815
// conflict for a particular element of `last`.
816
816
continue ' each_last;
817
817
}
818
- Ok ( true ) => { }
819
- Ok ( false ) => {
818
+ IsInFollow :: Yes => { }
819
+ IsInFollow :: No ( ref possible ) => {
820
820
let may_be = if last. tokens . len ( ) == 1 &&
821
821
suffix_first. tokens . len ( ) == 1
822
822
{
@@ -825,15 +825,41 @@ fn check_matcher_core(sess: &ParseSess,
825
825
"may be"
826
826
} ;
827
827
828
- sess. span_diagnostic . span_err (
829
- next_token. span ( ) ,
828
+ let sp = next_token. span ( ) ;
829
+ let mut err = sess. span_diagnostic . struct_span_err (
830
+ sp,
830
831
& format ! ( "`${name}:{frag}` {may_be} followed by `{next}`, which \
831
832
is not allowed for `{frag}` fragments",
832
833
name=name,
833
834
frag=frag_spec,
834
835
next=quoted_tt_to_string( next_token) ,
835
- may_be=may_be)
836
+ may_be=may_be) ,
836
837
) ;
838
+ err. span_label (
839
+ sp,
840
+ format ! ( "not allowed after `{}` fragments" , frag_spec) ,
841
+ ) ;
842
+ let msg = "allowed there are: " ;
843
+ match & possible[ ..] {
844
+ & [ ] => { }
845
+ & [ t] => {
846
+ err. note ( & format ! (
847
+ "only {} is allowed after `{}` fragments" ,
848
+ t,
849
+ frag_spec,
850
+ ) ) ;
851
+ }
852
+ ts => {
853
+ err. note ( & format ! (
854
+ "{}{} or {}" ,
855
+ msg,
856
+ ts[ ..ts. len( ) - 1 ] . iter( ) . map( |s| * s)
857
+ . collect:: <Vec <_>>( ) . join( ", " ) ,
858
+ ts[ ts. len( ) - 1 ] ,
859
+ ) ) ;
860
+ }
861
+ }
862
+ err. emit ( ) ;
837
863
}
838
864
}
839
865
}
@@ -876,6 +902,12 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool {
876
902
}
877
903
}
878
904
905
+ enum IsInFollow {
906
+ Yes ,
907
+ No ( Vec < & ' static str > ) ,
908
+ Invalid ( String , & ' static str ) ,
909
+ }
910
+
879
911
/// True if `frag` can legally be followed by the token `tok`. For
880
912
/// fragments that can consume an unbounded number of tokens, `tok`
881
913
/// must be within a well-defined follow set. This is intended to
@@ -884,81 +916,99 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool {
884
916
/// break macros that were relying on that binary operator as a
885
917
/// separator.
886
918
// when changing this do not forget to update doc/book/macros.md!
887
- fn is_in_follow ( tok : & quoted:: TokenTree , frag : & str ) -> Result < bool , ( String , & ' static str ) > {
919
+ fn is_in_follow ( tok : & quoted:: TokenTree , frag : & str ) -> IsInFollow {
888
920
use self :: quoted:: TokenTree ;
889
921
890
922
if let TokenTree :: Token ( _, token:: CloseDelim ( _) ) = * tok {
891
923
// closing a token tree can never be matched by any fragment;
892
924
// iow, we always require that `(` and `)` match, etc.
893
- Ok ( true )
925
+ IsInFollow :: Yes
894
926
} else {
895
927
match frag {
896
928
"item" => {
897
929
// since items *must* be followed by either a `;` or a `}`, we can
898
930
// accept anything after them
899
- Ok ( true )
931
+ IsInFollow :: Yes
900
932
} ,
901
933
"block" => {
902
934
// anything can follow block, the braces provide an easy boundary to
903
935
// maintain
904
- Ok ( true )
936
+ IsInFollow :: Yes
905
937
} ,
906
- "stmt" | "expr" => match * tok {
907
- TokenTree :: Token ( _, ref tok) => match * tok {
908
- FatArrow | Comma | Semi => Ok ( true ) ,
909
- _ => Ok ( false )
910
- } ,
911
- _ => Ok ( false ) ,
938
+ "stmt" | "expr" => {
939
+ let tokens = vec ! [ "`=>`" , "`,`" , "`;`" ] ;
940
+ match * tok {
941
+ TokenTree :: Token ( _, ref tok) => match * tok {
942
+ FatArrow | Comma | Semi => IsInFollow :: Yes ,
943
+ _ => IsInFollow :: No ( tokens) ,
944
+ } ,
945
+ _ => IsInFollow :: No ( tokens) ,
946
+ }
912
947
} ,
913
- "pat" => match * tok {
914
- TokenTree :: Token ( _, ref tok) => match * tok {
915
- FatArrow | Comma | Eq | BinOp ( token:: Or ) => Ok ( true ) ,
916
- Ident ( i, false ) if i. name == "if" || i. name == "in" => Ok ( true ) ,
917
- _ => Ok ( false )
918
- } ,
919
- _ => Ok ( false ) ,
948
+ "pat" => {
949
+ let tokens = vec ! [ "`=>`" , "`,`" , "`=`" , "`|`" , "`if`" , "`in`" ] ;
950
+ match * tok {
951
+ TokenTree :: Token ( _, ref tok) => match * tok {
952
+ FatArrow | Comma | Eq | BinOp ( token:: Or ) => IsInFollow :: Yes ,
953
+ Ident ( i, false ) if i. name == "if" || i. name == "in" => IsInFollow :: Yes ,
954
+ _ => IsInFollow :: No ( tokens) ,
955
+ } ,
956
+ _ => IsInFollow :: No ( tokens) ,
957
+ }
920
958
} ,
921
- "path" | "ty" => match * tok {
922
- TokenTree :: Token ( _, ref tok) => match * tok {
923
- OpenDelim ( token:: DelimToken :: Brace ) | OpenDelim ( token:: DelimToken :: Bracket ) |
924
- Comma | FatArrow | Colon | Eq | Gt | BinOp ( token:: Shr ) | Semi |
925
- BinOp ( token:: Or ) => Ok ( true ) ,
926
- Ident ( i, false ) if i. name == "as" || i. name == "where" => Ok ( true ) ,
927
- _ => Ok ( false )
928
- } ,
929
- TokenTree :: MetaVarDecl ( _, _, frag) if frag. name == "block" => Ok ( true ) ,
930
- _ => Ok ( false ) ,
959
+ "path" | "ty" => {
960
+ let tokens = vec ! [
961
+ "`{`" , "`[`" , "`=>`" , "`,`" , "`>`" , "`=`" , "`:`" , "`;`" , "`|`" , "`as`" ,
962
+ "`where`" ,
963
+ ] ;
964
+ match * tok {
965
+ TokenTree :: Token ( _, ref tok) => match * tok {
966
+ OpenDelim ( token:: DelimToken :: Brace ) |
967
+ OpenDelim ( token:: DelimToken :: Bracket ) |
968
+ Comma | FatArrow | Colon | Eq | Gt | BinOp ( token:: Shr ) | Semi |
969
+ BinOp ( token:: Or ) => IsInFollow :: Yes ,
970
+ Ident ( i, false ) if i. name == "as" || i. name == "where" => IsInFollow :: Yes ,
971
+ _ => IsInFollow :: No ( tokens) ,
972
+ } ,
973
+ TokenTree :: MetaVarDecl ( _, _, frag) if frag. name == "block" => IsInFollow :: Yes ,
974
+ _ => IsInFollow :: No ( tokens) ,
975
+ }
931
976
} ,
932
977
"ident" | "lifetime" => {
933
978
// being a single token, idents and lifetimes are harmless
934
- Ok ( true )
979
+ IsInFollow :: Yes
935
980
} ,
936
981
"literal" => {
937
982
// literals may be of a single token, or two tokens (negative numbers)
938
- Ok ( true )
983
+ IsInFollow :: Yes
939
984
} ,
940
985
"meta" | "tt" => {
941
986
// being either a single token or a delimited sequence, tt is
942
987
// harmless
943
- Ok ( true )
988
+ IsInFollow :: Yes
944
989
} ,
945
990
"vis" => {
946
991
// Explicitly disallow `priv`, on the off chance it comes back.
992
+ let tokens = vec ! [ "`,`" , "an ident" , "a type" ] ;
947
993
match * tok {
948
994
TokenTree :: Token ( _, ref tok) => match * tok {
949
- Comma => Ok ( true ) ,
950
- Ident ( i, is_raw) if is_raw || i. name != "priv" => Ok ( true ) ,
951
- ref tok => Ok ( tok. can_begin_type ( ) )
995
+ Comma => IsInFollow :: Yes ,
996
+ Ident ( i, is_raw) if is_raw || i. name != "priv" => IsInFollow :: Yes ,
997
+ ref tok => if tok. can_begin_type ( ) {
998
+ IsInFollow :: Yes
999
+ } else {
1000
+ IsInFollow :: No ( tokens)
1001
+ }
952
1002
} ,
953
1003
TokenTree :: MetaVarDecl ( _, _, frag) if frag. name == "ident"
954
1004
|| frag. name == "ty"
955
- || frag. name == "path" => Ok ( true ) ,
956
- _ => Ok ( false )
1005
+ || frag. name == "path" => IsInFollow :: Yes ,
1006
+ _ => IsInFollow :: No ( tokens ) ,
957
1007
}
958
1008
} ,
959
- "" => Ok ( true ) , // keywords::Invalid
960
- _ => Err ( ( format ! ( "invalid fragment specifier `{}`" , frag) ,
961
- VALID_FRAGMENT_NAMES_MSG ) )
1009
+ "" => IsInFollow :: Yes , // keywords::Invalid
1010
+ _ => IsInFollow :: Invalid ( format ! ( "invalid fragment specifier `{}`" , frag) ,
1011
+ VALID_FRAGMENT_NAMES_MSG ) ,
962
1012
}
963
1013
}
964
1014
}
0 commit comments