diff options
Diffstat (limited to 'src/parser/grammar/items/traits.rs')
-rw-r--r-- | src/parser/grammar/items/traits.rs | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/src/parser/grammar/items/traits.rs b/src/parser/grammar/items/traits.rs index 7fd011ffd..c7450b761 100644 --- a/src/parser/grammar/items/traits.rs +++ b/src/parser/grammar/items/traits.rs | |||
@@ -14,7 +14,47 @@ pub(super) fn trait_item(p: &mut Parser) { | |||
14 | pub(super) fn impl_item(p: &mut Parser) { | 14 | pub(super) fn impl_item(p: &mut Parser) { |
15 | assert!(p.at(IMPL_KW)); | 15 | assert!(p.at(IMPL_KW)); |
16 | p.bump(); | 16 | p.bump(); |
17 | p.expect(IDENT); | 17 | if choose_type_params_over_qpath(p) { |
18 | type_params::list(p); | ||
19 | } | ||
20 | |||
21 | // TODO: never type | ||
22 | // impl ! {} | ||
23 | |||
24 | // test impl_item_neg | ||
25 | // impl !Send for X {} | ||
26 | p.eat(EXCL); | ||
27 | types::type_(p); | ||
28 | if p.eat(FOR_KW) { | ||
29 | types::type_(p); | ||
30 | } | ||
31 | type_params::where_clause(p); | ||
18 | p.expect(L_CURLY); | 32 | p.expect(L_CURLY); |
19 | p.expect(R_CURLY); | 33 | p.expect(R_CURLY); |
20 | } | 34 | } |
35 | |||
36 | fn choose_type_params_over_qpath(p: &Parser) -> bool { | ||
37 | // There's an ambiguity between generic parameters and qualified paths in impls. | ||
38 | // If we see `<` it may start both, so we have to inspect some following tokens. | ||
39 | // The following combinations can only start generics, | ||
40 | // but not qualified paths (with one exception): | ||
41 | // `<` `>` - empty generic parameters | ||
42 | // `<` `#` - generic parameters with attributes | ||
43 | // `<` (LIFETIME|IDENT) `>` - single generic parameter | ||
44 | // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list | ||
45 | // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds | ||
46 | // `<` (LIFETIME|IDENT) `=` - generic parameter with a default | ||
47 | // The only truly ambiguous case is | ||
48 | // `<` IDENT `>` `::` IDENT ... | ||
49 | // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) | ||
50 | // because this is what almost always expected in practice, qualified paths in impls | ||
51 | // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment. | ||
52 | if !p.at(L_ANGLE) { | ||
53 | return false; | ||
54 | } | ||
55 | if p.nth(1) == POUND || p.nth(1) == R_ANGLE { | ||
56 | return true; | ||
57 | } | ||
58 | (p.nth(1) == LIFETIME || p.nth(1) == IDENT) | ||
59 | && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ) | ||
60 | } | ||