diff options
Diffstat (limited to 'crates/parser/src/grammar/items/traits.rs')
-rw-r--r-- | crates/parser/src/grammar/items/traits.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/items/traits.rs b/crates/parser/src/grammar/items/traits.rs new file mode 100644 index 000000000..751ce65f2 --- /dev/null +++ b/crates/parser/src/grammar/items/traits.rs | |||
@@ -0,0 +1,153 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | // test trait_item | ||
6 | // trait T<U>: Hash + Clone where U: Copy {} | ||
7 | // trait X<U: Debug + Display>: Hash + Clone where U: Copy {} | ||
8 | pub(super) fn trait_def(p: &mut Parser) { | ||
9 | assert!(p.at(T![trait])); | ||
10 | p.bump(T![trait]); | ||
11 | name_r(p, ITEM_RECOVERY_SET); | ||
12 | type_params::opt_type_param_list(p); | ||
13 | // test trait_alias | ||
14 | // trait Z<U> = T<U>; | ||
15 | // trait Z<U> = T<U> where U: Copy; | ||
16 | // trait Z<U> = where Self: T<U>; | ||
17 | if p.eat(T![=]) { | ||
18 | type_params::bounds_without_colon(p); | ||
19 | type_params::opt_where_clause(p); | ||
20 | p.expect(T![;]); | ||
21 | return; | ||
22 | } | ||
23 | if p.at(T![:]) { | ||
24 | type_params::bounds(p); | ||
25 | } | ||
26 | type_params::opt_where_clause(p); | ||
27 | if p.at(T!['{']) { | ||
28 | trait_item_list(p); | ||
29 | } else { | ||
30 | p.error("expected `{`"); | ||
31 | } | ||
32 | } | ||
33 | |||
34 | // test trait_item_list | ||
35 | // impl F { | ||
36 | // type A: Clone; | ||
37 | // const B: i32; | ||
38 | // fn foo() {} | ||
39 | // fn bar(&self); | ||
40 | // } | ||
41 | pub(crate) fn trait_item_list(p: &mut Parser) { | ||
42 | assert!(p.at(T!['{'])); | ||
43 | let m = p.start(); | ||
44 | p.bump(T!['{']); | ||
45 | while !p.at(EOF) && !p.at(T!['}']) { | ||
46 | if p.at(T!['{']) { | ||
47 | error_block(p, "expected an item"); | ||
48 | continue; | ||
49 | } | ||
50 | item_or_macro(p, true); | ||
51 | } | ||
52 | p.expect(T!['}']); | ||
53 | m.complete(p, ASSOC_ITEM_LIST); | ||
54 | } | ||
55 | |||
56 | // test impl_def | ||
57 | // impl Foo {} | ||
58 | pub(super) fn impl_def(p: &mut Parser) { | ||
59 | assert!(p.at(T![impl])); | ||
60 | p.bump(T![impl]); | ||
61 | if choose_type_params_over_qpath(p) { | ||
62 | type_params::opt_type_param_list(p); | ||
63 | } | ||
64 | |||
65 | // FIXME: never type | ||
66 | // impl ! {} | ||
67 | |||
68 | // test impl_def_neg | ||
69 | // impl !Send for X {} | ||
70 | p.eat(T![!]); | ||
71 | impl_type(p); | ||
72 | if p.eat(T![for]) { | ||
73 | impl_type(p); | ||
74 | } | ||
75 | type_params::opt_where_clause(p); | ||
76 | if p.at(T!['{']) { | ||
77 | impl_item_list(p); | ||
78 | } else { | ||
79 | p.error("expected `{`"); | ||
80 | } | ||
81 | } | ||
82 | |||
83 | // test impl_item_list | ||
84 | // impl F { | ||
85 | // type A = i32; | ||
86 | // const B: i32 = 92; | ||
87 | // fn foo() {} | ||
88 | // fn bar(&self) {} | ||
89 | // } | ||
90 | pub(crate) fn impl_item_list(p: &mut Parser) { | ||
91 | assert!(p.at(T!['{'])); | ||
92 | let m = p.start(); | ||
93 | p.bump(T!['{']); | ||
94 | // test impl_inner_attributes | ||
95 | // enum F{} | ||
96 | // impl F { | ||
97 | // //! This is a doc comment | ||
98 | // #![doc("This is also a doc comment")] | ||
99 | // } | ||
100 | attributes::inner_attributes(p); | ||
101 | |||
102 | while !p.at(EOF) && !p.at(T!['}']) { | ||
103 | if p.at(T!['{']) { | ||
104 | error_block(p, "expected an item"); | ||
105 | continue; | ||
106 | } | ||
107 | item_or_macro(p, true); | ||
108 | } | ||
109 | p.expect(T!['}']); | ||
110 | m.complete(p, ASSOC_ITEM_LIST); | ||
111 | } | ||
112 | |||
113 | // test impl_type_params | ||
114 | // impl<const N: u32> Bar<N> {} | ||
115 | fn choose_type_params_over_qpath(p: &Parser) -> bool { | ||
116 | // There's an ambiguity between generic parameters and qualified paths in impls. | ||
117 | // If we see `<` it may start both, so we have to inspect some following tokens. | ||
118 | // The following combinations can only start generics, | ||
119 | // but not qualified paths (with one exception): | ||
120 | // `<` `>` - empty generic parameters | ||
121 | // `<` `#` - generic parameters with attributes | ||
122 | // `<` `const` - const generic parameters | ||
123 | // `<` (LIFETIME|IDENT) `>` - single generic parameter | ||
124 | // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list | ||
125 | // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds | ||
126 | // `<` (LIFETIME|IDENT) `=` - generic parameter with a default | ||
127 | // The only truly ambiguous case is | ||
128 | // `<` IDENT `>` `::` IDENT ... | ||
129 | // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) | ||
130 | // because this is what almost always expected in practice, qualified paths in impls | ||
131 | // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment. | ||
132 | if !p.at(T![<]) { | ||
133 | return false; | ||
134 | } | ||
135 | if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == CONST_KW { | ||
136 | return true; | ||
137 | } | ||
138 | (p.nth(1) == LIFETIME || p.nth(1) == IDENT) | ||
139 | && (p.nth(2) == T![>] || p.nth(2) == T![,] || p.nth(2) == T![:] || p.nth(2) == T![=]) | ||
140 | } | ||
141 | |||
142 | // test_err impl_type | ||
143 | // impl Type {} | ||
144 | // impl Trait1 for T {} | ||
145 | // impl impl NotType {} | ||
146 | // impl Trait2 for impl NotType {} | ||
147 | pub(crate) fn impl_type(p: &mut Parser) { | ||
148 | if p.at(T![impl]) { | ||
149 | p.error("expected trait or type"); | ||
150 | return; | ||
151 | } | ||
152 | types::type_(p); | ||
153 | } | ||