aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/grammar/items/traits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/grammar/items/traits.rs')
-rw-r--r--crates/ra_syntax/src/grammar/items/traits.rs117
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 @@
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_item
44// impl Foo {}
45pub(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// }
77pub(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
93fn 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}