@@ -808,15 +808,15 @@ fn check_matcher_core(sess: &ParseSess,
808808 if let TokenTree :: MetaVarDecl ( _, ref name, ref frag_spec) = * token {
809809 for next_token in & suffix_first. tokens {
810810 match is_in_follow ( next_token, & frag_spec. as_str ( ) ) {
811- Err ( ( msg, help) ) => {
811+ IsInFollow :: Invalid ( msg, help) => {
812812 sess. span_diagnostic . struct_span_err ( next_token. span ( ) , & msg)
813813 . help ( help) . emit ( ) ;
814814 // don't bother reporting every source of
815815 // conflict for a particular element of `last`.
816816 continue ' each_last;
817817 }
818- Ok ( true ) => { }
819- Ok ( false ) => {
818+ IsInFollow :: Yes => { }
819+ IsInFollow :: No ( ref possible ) => {
820820 let may_be = if last. tokens . len ( ) == 1 &&
821821 suffix_first. tokens . len ( ) == 1
822822 {
@@ -825,15 +825,41 @@ fn check_matcher_core(sess: &ParseSess,
825825 "may be"
826826 } ;
827827
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,
830831 & format ! ( "`${name}:{frag}` {may_be} followed by `{next}`, which \
831832 is not allowed for `{frag}` fragments",
832833 name=name,
833834 frag=frag_spec,
834835 next=quoted_tt_to_string( next_token) ,
835- may_be=may_be)
836+ may_be=may_be) ,
836837 ) ;
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 ( ) ;
837863 }
838864 }
839865 }
@@ -876,6 +902,12 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool {
876902 }
877903}
878904
905+ enum IsInFollow {
906+ Yes ,
907+ No ( Vec < & ' static str > ) ,
908+ Invalid ( String , & ' static str ) ,
909+ }
910+
879911/// True if `frag` can legally be followed by the token `tok`. For
880912/// fragments that can consume an unbounded number of tokens, `tok`
881913/// 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 {
884916/// break macros that were relying on that binary operator as a
885917/// separator.
886918// 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 {
888920 use self :: quoted:: TokenTree ;
889921
890922 if let TokenTree :: Token ( _, token:: CloseDelim ( _) ) = * tok {
891923 // closing a token tree can never be matched by any fragment;
892924 // iow, we always require that `(` and `)` match, etc.
893- Ok ( true )
925+ IsInFollow :: Yes
894926 } else {
895927 match frag {
896928 "item" => {
897929 // since items *must* be followed by either a `;` or a `}`, we can
898930 // accept anything after them
899- Ok ( true )
931+ IsInFollow :: Yes
900932 } ,
901933 "block" => {
902934 // anything can follow block, the braces provide an easy boundary to
903935 // maintain
904- Ok ( true )
936+ IsInFollow :: Yes
905937 } ,
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+ }
912947 } ,
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+ }
920958 } ,
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+ }
931976 } ,
932977 "ident" | "lifetime" => {
933978 // being a single token, idents and lifetimes are harmless
934- Ok ( true )
979+ IsInFollow :: Yes
935980 } ,
936981 "literal" => {
937982 // literals may be of a single token, or two tokens (negative numbers)
938- Ok ( true )
983+ IsInFollow :: Yes
939984 } ,
940985 "meta" | "tt" => {
941986 // being either a single token or a delimited sequence, tt is
942987 // harmless
943- Ok ( true )
988+ IsInFollow :: Yes
944989 } ,
945990 "vis" => {
946991 // Explicitly disallow `priv`, on the off chance it comes back.
992+ let tokens = vec ! [ "`,`" , "an ident" , "a type" ] ;
947993 match * tok {
948994 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+ }
9521002 } ,
9531003 TokenTree :: MetaVarDecl ( _, _, frag) if frag. name == "ident"
9541004 || frag. name == "ty"
955- || frag. name == "path" => Ok ( true ) ,
956- _ => Ok ( false )
1005+ || frag. name == "path" => IsInFollow :: Yes ,
1006+ _ => IsInFollow :: No ( tokens ) ,
9571007 }
9581008 } ,
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 ) ,
9621012 }
9631013 }
9641014}
0 commit comments