@@ -792,15 +792,15 @@ fn check_matcher_core(sess: &ParseSess,
792792 if let TokenTree :: MetaVarDecl ( _, ref name, ref frag_spec) = * token {
793793 for next_token in & suffix_first. tokens {
794794 match is_in_follow ( next_token, & frag_spec. as_str ( ) ) {
795- Err ( ( msg, help) ) => {
795+ IsInFollow :: Invalid ( msg, help) => {
796796 sess. span_diagnostic . struct_span_err ( next_token. span ( ) , & msg)
797797 . help ( help) . emit ( ) ;
798798 // don't bother reporting every source of
799799 // conflict for a particular element of `last`.
800800 continue ' each_last;
801801 }
802- Ok ( true ) => { }
803- Ok ( false ) => {
802+ IsInFollow :: Yes => { }
803+ IsInFollow :: No ( ref possible ) => {
804804 let may_be = if last. tokens . len ( ) == 1 &&
805805 suffix_first. tokens . len ( ) == 1
806806 {
@@ -809,15 +809,41 @@ fn check_matcher_core(sess: &ParseSess,
809809 "may be"
810810 } ;
811811
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,
814815 & format ! ( "`${name}:{frag}` {may_be} followed by `{next}`, which \
815816 is not allowed for `{frag}` fragments",
816817 name=name,
817818 frag=frag_spec,
818819 next=quoted_tt_to_string( next_token) ,
819- may_be=may_be)
820+ may_be=may_be) ,
820821 ) ;
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 ( ) ;
821847 }
822848 }
823849 }
@@ -860,6 +886,12 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool {
860886 }
861887}
862888
889+ enum IsInFollow {
890+ Yes ,
891+ No ( Vec < & ' static str > ) ,
892+ Invalid ( String , & ' static str ) ,
893+ }
894+
863895/// True if `frag` can legally be followed by the token `tok`. For
864896/// fragments that can consume an unbounded number of tokens, `tok`
865897/// 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 {
868900/// break macros that were relying on that binary operator as a
869901/// separator.
870902// 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 {
872904 use self :: quoted:: TokenTree ;
873905
874906 if let TokenTree :: Token ( _, token:: CloseDelim ( _) ) = * tok {
875907 // closing a token tree can never be matched by any fragment;
876908 // iow, we always require that `(` and `)` match, etc.
877- Ok ( true )
909+ IsInFollow :: Yes
878910 } else {
879911 match frag {
880912 "item" => {
881913 // since items *must* be followed by either a `;` or a `}`, we can
882914 // accept anything after them
883- Ok ( true )
915+ IsInFollow :: Yes
884916 } ,
885917 "block" => {
886918 // anything can follow block, the braces provide an easy boundary to
887919 // maintain
888- Ok ( true )
920+ IsInFollow :: Yes
889921 } ,
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+ }
896931 } ,
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+ }
904942 } ,
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+ }
915960 } ,
916961 "ident" | "lifetime" => {
917962 // being a single token, idents and lifetimes are harmless
918- Ok ( true )
963+ IsInFollow :: Yes
919964 } ,
920965 "literal" => {
921966 // literals may be of a single token, or two tokens (negative numbers)
922- Ok ( true )
967+ IsInFollow :: Yes
923968 } ,
924969 "meta" | "tt" => {
925970 // being either a single token or a delimited sequence, tt is
926971 // harmless
927- Ok ( true )
972+ IsInFollow :: Yes
928973 } ,
929974 "vis" => {
930975 // Explicitly disallow `priv`, on the off chance it comes back.
976+ let tokens = vec ! [ "`,`" , "an ident" , "a type" ] ;
931977 match * tok {
932978 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+ }
936986 } ,
937987 TokenTree :: MetaVarDecl ( _, _, frag) if frag. name == "ident"
938988 || frag. name == "ty"
939- || frag. name == "path" => Ok ( true ) ,
940- _ => Ok ( false )
989+ || frag. name == "path" => IsInFollow :: Yes ,
990+ _ => IsInFollow :: No ( tokens ) ,
941991 }
942992 } ,
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 ) ,
946996 }
947997 }
948998}
0 commit comments