diff options
Diffstat (limited to 'crates/parser/src/grammar/items/traits.rs')
-rw-r--r-- | crates/parser/src/grammar/items/traits.rs | 131 |
1 files changed, 131 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..8394020da --- /dev/null +++ b/crates/parser/src/grammar/items/traits.rs | |||
@@ -0,0 +1,131 @@ | |||
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_(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_generic_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 | assoc_item_list(p); | ||
29 | } else { | ||
30 | p.error("expected `{`"); | ||
31 | } | ||
32 | } | ||
33 | |||
34 | // test impl_def | ||
35 | // impl Foo {} | ||
36 | pub(super) fn impl_(p: &mut Parser) { | ||
37 | assert!(p.at(T![impl])); | ||
38 | p.bump(T![impl]); | ||
39 | if choose_type_params_over_qpath(p) { | ||
40 | type_params::opt_generic_param_list(p); | ||
41 | } | ||
42 | |||
43 | // FIXME: never type | ||
44 | // impl ! {} | ||
45 | |||
46 | // test impl_def_neg | ||
47 | // impl !Send for X {} | ||
48 | p.eat(T![!]); | ||
49 | impl_type(p); | ||
50 | if p.eat(T![for]) { | ||
51 | impl_type(p); | ||
52 | } | ||
53 | type_params::opt_where_clause(p); | ||
54 | if p.at(T!['{']) { | ||
55 | assoc_item_list(p); | ||
56 | } else { | ||
57 | p.error("expected `{`"); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | // test impl_item_list | ||
62 | // impl F { | ||
63 | // type A = i32; | ||
64 | // const B: i32 = 92; | ||
65 | // fn foo() {} | ||
66 | // fn bar(&self) {} | ||
67 | // } | ||
68 | pub(crate) fn assoc_item_list(p: &mut Parser) { | ||
69 | assert!(p.at(T!['{'])); | ||
70 | let m = p.start(); | ||
71 | p.bump(T!['{']); | ||
72 | // test impl_inner_attributes | ||
73 | // enum F{} | ||
74 | // impl F { | ||
75 | // //! This is a doc comment | ||
76 | // #![doc("This is also a doc comment")] | ||
77 | // } | ||
78 | attributes::inner_attrs(p); | ||
79 | |||
80 | while !p.at(EOF) && !p.at(T!['}']) { | ||
81 | if p.at(T!['{']) { | ||
82 | error_block(p, "expected an item"); | ||
83 | continue; | ||
84 | } | ||
85 | item_or_macro(p, true); | ||
86 | } | ||
87 | p.expect(T!['}']); | ||
88 | m.complete(p, ASSOC_ITEM_LIST); | ||
89 | } | ||
90 | |||
91 | // test impl_type_params | ||
92 | // impl<const N: u32> Bar<N> {} | ||
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 | // `<` `const` - const generic parameters | ||
101 | // `<` (LIFETIME|IDENT) `>` - single generic parameter | ||
102 | // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list | ||
103 | // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds | ||
104 | // `<` (LIFETIME|IDENT) `=` - generic parameter with a default | ||
105 | // The only truly ambiguous case is | ||
106 | // `<` IDENT `>` `::` IDENT ... | ||
107 | // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) | ||
108 | // because this is what almost always expected in practice, qualified paths in impls | ||
109 | // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment. | ||
110 | if !p.at(T![<]) { | ||
111 | return false; | ||
112 | } | ||
113 | if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == CONST_KW { | ||
114 | return true; | ||
115 | } | ||
116 | (p.nth(1) == LIFETIME || p.nth(1) == IDENT) | ||
117 | && (p.nth(2) == T![>] || p.nth(2) == T![,] || p.nth(2) == T![:] || p.nth(2) == T![=]) | ||
118 | } | ||
119 | |||
120 | // test_err impl_type | ||
121 | // impl Type {} | ||
122 | // impl Trait1 for T {} | ||
123 | // impl impl NotType {} | ||
124 | // impl Trait2 for impl NotType {} | ||
125 | pub(crate) fn impl_type(p: &mut Parser) { | ||
126 | if p.at(T![impl]) { | ||
127 | p.error("expected trait or type"); | ||
128 | return; | ||
129 | } | ||
130 | types::type_(p); | ||
131 | } | ||