@@ -4772,21 +4772,13 @@ impl<'a> Parser<'a> {
47724772 }
47734773 let lo = self . prev_span ;
47744774
4775- // This is a temporary future proofing.
4776- //
47774775 // We are considering adding generics to the `where` keyword as an alternative higher-rank
47784776 // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
4779- // change, for now we refuse to parse `where < (ident | lifetime) (> | , | :)`.
4780- if token:: Lt == self . token {
4781- let ident_or_lifetime = self . look_ahead ( 1 , |t| t. is_ident ( ) || t. is_lifetime ( ) ) ;
4782- if ident_or_lifetime {
4783- let gt_comma_or_colon = self . look_ahead ( 2 , |t| {
4784- * t == token:: Gt || * t == token:: Comma || * t == token:: Colon
4785- } ) ;
4786- if gt_comma_or_colon {
4787- self . span_err ( self . span , "syntax `where<T>` is reserved for future use" ) ;
4788- }
4789- }
4777+ // change we parse those generics now, but report an error.
4778+ if self . choose_generics_over_qpath ( ) {
4779+ let generics = self . parse_generics ( ) ?;
4780+ self . span_err ( generics. span ,
4781+ "generic parameters on `where` clauses are reserved for future use" ) ;
47904782 }
47914783
47924784 loop {
@@ -5348,6 +5340,29 @@ impl<'a> Parser<'a> {
53485340 }
53495341 }
53505342
5343+ fn choose_generics_over_qpath ( & self ) -> bool {
5344+ // There's an ambiguity between generic parameters and qualified paths in impls.
5345+ // If we see `<` it may start both, so we have to inspect some following tokens.
5346+ // The following combinations can only start generics,
5347+ // but not qualified paths (with one exception):
5348+ // `<` `>` - empty generic parameters
5349+ // `<` `#` - generic parameters with attributes
5350+ // `<` (LIFETIME|IDENT) `>` - single generic parameter
5351+ // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
5352+ // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
5353+ // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
5354+ // The only truly ambiguous case is
5355+ // `<` IDENT `>` `::` IDENT ...
5356+ // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
5357+ // because this is what almost always expected in practice, qualified paths in impls
5358+ // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
5359+ self . token == token:: Lt &&
5360+ ( self . look_ahead ( 1 , |t| t == & token:: Pound || t == & token:: Gt ) ||
5361+ self . look_ahead ( 1 , |t| t. is_lifetime ( ) || t. is_ident ( ) ) &&
5362+ self . look_ahead ( 2 , |t| t == & token:: Gt || t == & token:: Comma ||
5363+ t == & token:: Colon || t == & token:: Eq ) )
5364+ }
5365+
53515366 fn parse_impl_body ( & mut self ) -> PResult < ' a , ( Vec < ImplItem > , Vec < Attribute > ) > {
53525367 self . expect ( & token:: OpenDelim ( token:: Brace ) ) ?;
53535368 let attrs = self . parse_inner_attributes ( ) ?;
@@ -5378,8 +5393,11 @@ impl<'a> Parser<'a> {
53785393 fn parse_item_impl ( & mut self , unsafety : Unsafety , defaultness : Defaultness )
53795394 -> PResult < ' a , ItemInfo > {
53805395 // First, parse generic parameters if necessary.
5381- // FIXME: Disambiguate generic parameters and qualified paths (`impl <A as B>::C {}`).
5382- let mut generics = self . parse_generics ( ) ?;
5396+ let mut generics = if self . choose_generics_over_qpath ( ) {
5397+ self . parse_generics ( ) ?
5398+ } else {
5399+ ast:: Generics :: default ( )
5400+ } ;
53835401
53845402 // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
53855403 let polarity = if self . check ( & token:: Not ) && self . look_ahead ( 1 , |t| t. can_begin_type ( ) ) {
0 commit comments