aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_parser/src/grammar/items/traits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_parser/src/grammar/items/traits.rs')
-rw-r--r--crates/ra_parser/src/grammar/items/traits.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs
new file mode 100644
index 000000000..d5a8ccd98
--- /dev/null
+++ b/crates/ra_parser/src/grammar/items/traits.rs
@@ -0,0 +1,137 @@
1use super::*;
2
3// test trait_item
4// trait T<U>: Hash + Clone where U: Copy {}
5pub(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// }
28pub(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_block
44// impl Foo {}
45pub(super) fn impl_block(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_block_neg
56 // impl !Send for X {}
57 p.eat(EXCL);
58 impl_type(p);
59 if p.eat(FOR_KW) {
60 impl_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// }
77pub(crate) fn impl_item_list(p: &mut Parser) {
78 assert!(p.at(L_CURLY));
79 let m = p.start();
80 p.bump();
81 // test impl_inner_attributes
82 // enum F{}
83 // impl F {
84 // //! This is a doc comment
85 // #![doc("This is also a doc comment")]
86 // }
87 attributes::inner_attributes(p);
88
89 while !p.at(EOF) && !p.at(R_CURLY) {
90 if p.at(L_CURLY) {
91 error_block(p, "expected an item");
92 continue;
93 }
94 item_or_macro(p, true, ItemFlavor::Mod);
95 }
96 p.expect(R_CURLY);
97 m.complete(p, ITEM_LIST);
98}
99
100fn choose_type_params_over_qpath(p: &Parser) -> bool {
101 // There's an ambiguity between generic parameters and qualified paths in impls.
102 // If we see `<` it may start both, so we have to inspect some following tokens.
103 // The following combinations can only start generics,
104 // but not qualified paths (with one exception):
105 // `<` `>` - empty generic parameters
106 // `<` `#` - generic parameters with attributes
107 // `<` (LIFETIME|IDENT) `>` - single generic parameter
108 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
109 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
110 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
111 // The only truly ambiguous case is
112 // `<` IDENT `>` `::` IDENT ...
113 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
114 // because this is what almost always expected in practice, qualified paths in impls
115 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
116 if !p.at(L_ANGLE) {
117 return false;
118 }
119 if p.nth(1) == POUND || p.nth(1) == R_ANGLE {
120 return true;
121 }
122 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
123 && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ)
124}
125
126// test_err impl_type
127// impl Type {}
128// impl Trait1 for T {}
129// impl impl NotType {}
130// impl Trait2 for impl NotType {}
131pub(crate) fn impl_type(p: &mut Parser) {
132 if p.at(IMPL_KW) {
133 p.error("expected trait or type");
134 return;
135 }
136 types::type_(p);
137}