@@ -1052,80 +1052,69 @@ impl<'a> Parser<'a> {
10521052 }
10531053 }
10541054
1055- /// Is there an `[ impl(in? path) ]? trait` item `dist` tokens ahead?
1056- fn is_trait_with_maybe_impl_restriction_in_front ( & self , dist : usize ) -> bool {
1057- // `trait`
1058- if self . is_keyword_ahead ( dist, & [ kw:: Trait ] ) {
1059- return true ;
1060- }
1061- // `impl(`
1062- if !self . is_keyword_ahead ( dist, & [ kw:: Impl ] )
1063- || !self . look_ahead ( dist + 1 , |t| t == & token:: OpenParen )
1064- {
1065- return false ;
1066- }
1067- // `crate | super | self) trait`
1068- if self . is_keyword_ahead ( dist + 2 , & [ kw:: Crate , kw:: Super , kw:: SelfLower ] )
1069- && self . look_ahead ( dist + 3 , |t| t == & token:: CloseParen )
1070- && self . is_keyword_ahead ( dist + 4 , & [ kw:: Trait ] )
1071- {
1072- return true ;
1073- }
1074- // `impl(in? something) trait`
1075- // We catch cases where the `in` keyword is missing to provide a
1076- // better error message. This is handled later in
1077- // `self.recover_incorrect_impl_restriction`.
1078- self . tree_look_ahead ( dist + 2 , |t| {
1079- if let TokenTree :: Token ( token, _) = t { token. is_keyword ( kw:: Trait ) } else { false }
1080- } )
1081- . unwrap_or ( false )
1082- }
1083-
1084- /// Is this an `(const unsafe? auto? [ impl(in? path) ]? | unsafe auto? [ impl(in? path) ]? | auto [ impl(in? path) ]? | [ impl(in? path) ]?) trait` item?
1055+ /// Is this an `[impl(in? path)]? const? unsafe? auto? trait` item?
10851056 fn check_trait_front_matter ( & mut self ) -> bool {
1086- // `[ impl(in? path) ]? trait`
1087- if self . is_trait_with_maybe_impl_restriction_in_front ( 0 ) {
1088- return true ;
1089- }
1090- // `auto [ impl(in? path) ]? trait`
1091- if self . check_keyword ( exp ! ( Auto ) ) && self . is_trait_with_maybe_impl_restriction_in_front ( 1 ) {
1092- return true ;
1093- }
1094- // `unsafe auto? [ impl(in? path) ]? trait`
1095- if self . check_keyword ( exp ! ( Unsafe ) )
1096- && ( self . is_trait_with_maybe_impl_restriction_in_front ( 1 )
1097- || self . is_keyword_ahead ( 1 , & [ kw:: Auto ] )
1098- && self . is_trait_with_maybe_impl_restriction_in_front ( 2 ) )
1099- {
1100- return true ;
1101- }
1102- // `const` ...
1103- if !self . check_keyword ( exp ! ( Const ) ) {
1104- return false ;
1105- }
1106- // `const [ impl(in? path) ]? trait`
1107- if self . is_trait_with_maybe_impl_restriction_in_front ( 1 ) {
1108- return true ;
1109- }
1110- // `const (unsafe | auto) [ impl(in? path) ]? trait`
1111- if self . is_keyword_ahead ( 1 , & [ kw:: Unsafe , kw:: Auto ] )
1112- && self . is_trait_with_maybe_impl_restriction_in_front ( 2 )
1113- {
1114- return true ;
1057+ const SUFFIXES : & [ & [ Symbol ] ] = & [
1058+ & [ kw:: Trait ] ,
1059+ & [ kw:: Auto , kw:: Trait ] ,
1060+ & [ kw:: Unsafe , kw:: Trait ] ,
1061+ & [ kw:: Unsafe , kw:: Auto , kw:: Trait ] ,
1062+ & [ kw:: Const , kw:: Trait ] ,
1063+ & [ kw:: Const , kw:: Auto , kw:: Trait ] ,
1064+ & [ kw:: Const , kw:: Unsafe , kw:: Trait ] ,
1065+ & [ kw:: Const , kw:: Unsafe , kw:: Auto , kw:: Trait ] ,
1066+ ] ;
1067+ // `impl(`
1068+ if self . check_keyword ( exp ! ( Impl ) ) && self . look_ahead ( 1 , |t| t == & token:: OpenParen ) {
1069+ // `impl(in` unambiguously introduces an `impl` restriction
1070+ if self . is_keyword_ahead ( 2 , & [ kw:: In ] ) {
1071+ return true ;
1072+ }
1073+ // `impl(crate | self | super)` + SUFFIX
1074+ if self . is_keyword_ahead ( 2 , & [ kw:: Crate , kw:: SelfLower , kw:: Super ] )
1075+ && self . look_ahead ( 3 , |t| t == & token:: CloseParen )
1076+ && SUFFIXES . iter ( ) . any ( |suffix| {
1077+ suffix. iter ( ) . enumerate ( ) . all ( |( i, kw) | self . is_keyword_ahead ( i + 4 , & [ * kw] ) )
1078+ } )
1079+ {
1080+ return true ;
1081+ }
1082+ // Recover cases like `impl(path::to::module)` + SUFFIX to suggest inserting `in`.
1083+ SUFFIXES . iter ( ) . any ( |suffix| {
1084+ suffix. iter ( ) . enumerate ( ) . all ( |( i, kw) | {
1085+ self . tree_look_ahead ( i + 2 , |t| {
1086+ if let TokenTree :: Token ( token, _) = t {
1087+ token. is_keyword ( * kw)
1088+ } else {
1089+ false
1090+ }
1091+ } )
1092+ . unwrap_or ( false )
1093+ } )
1094+ } )
1095+ } else {
1096+ SUFFIXES . iter ( ) . any ( |suffix| {
1097+ suffix. iter ( ) . enumerate ( ) . all ( |( i, kw) | {
1098+ // We use `check_keyword` for the first token to include it in the expected tokens.
1099+ if i == 0 {
1100+ match * kw {
1101+ kw:: Const => self . check_keyword ( exp ! ( Const ) ) ,
1102+ kw:: Unsafe => self . check_keyword ( exp ! ( Unsafe ) ) ,
1103+ kw:: Auto => self . check_keyword ( exp ! ( Auto ) ) ,
1104+ kw:: Trait => self . check_keyword ( exp ! ( Trait ) ) ,
1105+ _ => unreachable ! ( ) ,
1106+ }
1107+ } else {
1108+ self . is_keyword_ahead ( i, & [ * kw] )
1109+ }
1110+ } )
1111+ } )
11151112 }
1116- // `const unsafe auto [ impl(in? path) ]? trait`
1117- self . is_keyword_ahead ( 1 , & [ kw:: Unsafe ] )
1118- && self . is_keyword_ahead ( 2 , & [ kw:: Auto ] )
1119- && self . is_trait_with_maybe_impl_restriction_in_front ( 3 )
11201113 }
11211114
1122- /// Parses `const? unsafe? auto? [impl(in? path)]? trait Foo { ... }` or `trait Foo = Bar;`.
1123- ///
1124- /// FIXME(restrictions): The current keyword order follows the grammar specified in RFC 3323.
1125- /// However, whether the restriction should be grouped closer to the visibility modifier
1126- /// (e.g., `pub impl(crate) const unsafe auto trait`) remains an unresolved design question.
1127- /// This ordering must be kept in sync with the logic in `check_trait_front_matter`.
1115+ /// Parses `[impl(in? path)]? const? unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
11281116 fn parse_item_trait ( & mut self , attrs : & mut AttrVec , lo : Span ) -> PResult < ' a , ItemKind > {
1117+ let impl_restriction = self . parse_impl_restriction ( ) ?;
11291118 let constness = self . parse_constness ( Case :: Sensitive ) ;
11301119 if let Const :: Yes ( span) = constness {
11311120 self . psess . gated_spans . gate ( sym:: const_trait_impl, span) ;
@@ -1139,8 +1128,6 @@ impl<'a> Parser<'a> {
11391128 IsAuto :: No
11401129 } ;
11411130
1142- let impl_restriction = self . parse_impl_restriction ( ) ?;
1143-
11441131 self . expect_keyword ( exp ! ( Trait ) ) ?;
11451132 let ident = self . parse_ident ( ) ?;
11461133 let mut generics = self . parse_generics ( ) ?;
@@ -1181,10 +1168,10 @@ impl<'a> Parser<'a> {
11811168 generics. where_clause = self . parse_where_clause ( ) ?;
11821169 let items = self . parse_item_list ( attrs, |p| p. parse_trait_item ( ForceCollect :: No ) ) ?;
11831170 Ok ( ItemKind :: Trait ( Box :: new ( Trait {
1171+ impl_restriction,
11841172 constness,
11851173 is_auto,
11861174 safety,
1187- impl_restriction,
11881175 ident,
11891176 generics,
11901177 bounds,
@@ -2966,7 +2953,7 @@ impl<'a> Parser<'a> {
29662953 && !self . is_unsafe_foreign_mod ( )
29672954 // Rule out `async gen {` and `async gen move {`
29682955 && !self . is_async_gen_block ( )
2969- // Rule out `const unsafe auto` and `const unsafe trait` and `const unsafe impl`.
2956+ // Rule out `const unsafe auto` and `const unsafe trait` and `const unsafe impl`
29702957 && !self . is_keyword_ahead ( 2 , & [ kw:: Auto , kw:: Trait , kw:: Impl ] )
29712958 )
29722959 } )
0 commit comments