@@ -4772,21 +4772,13 @@ impl<'a> Parser<'a> {
4772
4772
}
4773
4773
let lo = self . prev_span ;
4774
4774
4775
- // This is a temporary future proofing.
4776
- //
4777
4775
// We are considering adding generics to the `where` keyword as an alternative higher-rank
4778
4776
// 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" ) ;
4790
4782
}
4791
4783
4792
4784
loop {
@@ -5348,6 +5340,29 @@ impl<'a> Parser<'a> {
5348
5340
}
5349
5341
}
5350
5342
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
+
5351
5366
fn parse_impl_body ( & mut self ) -> PResult < ' a , ( Vec < ImplItem > , Vec < Attribute > ) > {
5352
5367
self . expect ( & token:: OpenDelim ( token:: Brace ) ) ?;
5353
5368
let attrs = self . parse_inner_attributes ( ) ?;
@@ -5378,8 +5393,11 @@ impl<'a> Parser<'a> {
5378
5393
fn parse_item_impl ( & mut self , unsafety : Unsafety , defaultness : Defaultness )
5379
5394
-> PResult < ' a , ItemInfo > {
5380
5395
// 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
+ } ;
5383
5401
5384
5402
// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
5385
5403
let polarity = if self . check ( & token:: Not ) && self . look_ahead ( 1 , |t| t. can_begin_type ( ) ) {
0 commit comments