aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar/items/traits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/grammar/items/traits.rs')
-rw-r--r--crates/parser/src/grammar/items/traits.rs153
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
3use 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 {}
8pub(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// }
41pub(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 {}
58pub(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// }
90pub(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> {}
115fn 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 {}
147pub(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}