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