diff options
Diffstat (limited to 'crates/ra_syntax/src/grammar/items/traits.rs')
-rw-r--r-- | crates/ra_syntax/src/grammar/items/traits.rs | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/grammar/items/traits.rs b/crates/ra_syntax/src/grammar/items/traits.rs new file mode 100644 index 000000000..c21cfb1a9 --- /dev/null +++ b/crates/ra_syntax/src/grammar/items/traits.rs | |||
@@ -0,0 +1,117 @@ | |||
1 | use super::*; | ||
2 | |||
3 | // test trait_item | ||
4 | // trait T<U>: Hash + Clone where U: Copy {} | ||
5 | pub(super) fn trait_def(p: &mut Parser) { | ||
6 | assert!(p.at(TRAIT_KW)); | ||
7 | p.bump(); | ||
8 | name_r(p, ITEM_RECOVERY_SET); | ||
9 | type_params::opt_type_param_list(p); | ||
10 | if p.at(COLON) { | ||
11 | type_params::bounds(p); | ||
12 | } | ||
13 | type_params::opt_where_clause(p); | ||
14 | if p.at(L_CURLY) { | ||
15 | trait_item_list(p); | ||
16 | } else { | ||
17 | p.error("expected `{`"); | ||
18 | } | ||
19 | } | ||
20 | |||
21 | // test trait_item_list | ||
22 | // impl F { | ||
23 | // type A: Clone; | ||
24 | // const B: i32; | ||
25 | // fn foo() {} | ||
26 | // fn bar(&self); | ||
27 | // } | ||
28 | pub(crate) fn trait_item_list(p: &mut Parser) { | ||
29 | assert!(p.at(L_CURLY)); | ||
30 | let m = p.start(); | ||
31 | p.bump(); | ||
32 | while !p.at(EOF) && !p.at(R_CURLY) { | ||
33 | if p.at(L_CURLY) { | ||
34 | error_block(p, "expected an item"); | ||
35 | continue; | ||
36 | } | ||
37 | item_or_macro(p, true, ItemFlavor::Trait); | ||
38 | } | ||
39 | p.expect(R_CURLY); | ||
40 | m.complete(p, ITEM_LIST); | ||
41 | } | ||
42 | |||
43 | // test impl_item | ||
44 | // impl Foo {} | ||
45 | pub(super) fn impl_item(p: &mut Parser) { | ||
46 | assert!(p.at(IMPL_KW)); | ||
47 | p.bump(); | ||
48 | if choose_type_params_over_qpath(p) { | ||
49 | type_params::opt_type_param_list(p); | ||
50 | } | ||
51 | |||
52 | // TODO: never type | ||
53 | // impl ! {} | ||
54 | |||
55 | // test impl_item_neg | ||
56 | // impl !Send for X {} | ||
57 | p.eat(EXCL); | ||
58 | types::type_(p); | ||
59 | if p.eat(FOR_KW) { | ||
60 | types::type_(p); | ||
61 | } | ||
62 | type_params::opt_where_clause(p); | ||
63 | if p.at(L_CURLY) { | ||
64 | impl_item_list(p); | ||
65 | } else { | ||
66 | p.error("expected `{`"); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // test impl_item_list | ||
71 | // impl F { | ||
72 | // type A = i32; | ||
73 | // const B: i32 = 92; | ||
74 | // fn foo() {} | ||
75 | // fn bar(&self) {} | ||
76 | // } | ||
77 | pub(crate) fn impl_item_list(p: &mut Parser) { | ||
78 | assert!(p.at(L_CURLY)); | ||
79 | let m = p.start(); | ||
80 | p.bump(); | ||
81 | |||
82 | while !p.at(EOF) && !p.at(R_CURLY) { | ||
83 | if p.at(L_CURLY) { | ||
84 | error_block(p, "expected an item"); | ||
85 | continue; | ||
86 | } | ||
87 | item_or_macro(p, true, ItemFlavor::Mod); | ||
88 | } | ||
89 | p.expect(R_CURLY); | ||
90 | m.complete(p, ITEM_LIST); | ||
91 | } | ||
92 | |||
93 | fn choose_type_params_over_qpath(p: &Parser) -> bool { | ||
94 | // There's an ambiguity between generic parameters and qualified paths in impls. | ||
95 | // If we see `<` it may start both, so we have to inspect some following tokens. | ||
96 | // The following combinations can only start generics, | ||
97 | // but not qualified paths (with one exception): | ||
98 | // `<` `>` - empty generic parameters | ||
99 | // `<` `#` - generic parameters with attributes | ||
100 | // `<` (LIFETIME|IDENT) `>` - single generic parameter | ||
101 | // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list | ||
102 | // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds | ||
103 | // `<` (LIFETIME|IDENT) `=` - generic parameter with a default | ||
104 | // The only truly ambiguous case is | ||
105 | // `<` IDENT `>` `::` IDENT ... | ||
106 | // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) | ||
107 | // because this is what almost always expected in practice, qualified paths in impls | ||
108 | // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment. | ||
109 | if !p.at(L_ANGLE) { | ||
110 | return false; | ||
111 | } | ||
112 | if p.nth(1) == POUND || p.nth(1) == R_ANGLE { | ||
113 | return true; | ||
114 | } | ||
115 | (p.nth(1) == LIFETIME || p.nth(1) == IDENT) | ||
116 | && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ) | ||
117 | } | ||