diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-31 10:11:48 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-31 10:11:48 +0100 |
commit | c5ca49678f129045e59438df279829902034ec71 (patch) | |
tree | 3fd54185e0c064fbd6f718ac345064ce9c559efb /crates/ra_parser | |
parent | 23dd53eb35ff50508d0c0fc5878a55754b12d381 (diff) | |
parent | 55dcdb7d094f473c73f87ecf997b24f8e35f2a5e (diff) |
Merge #1077
1077: Improve parsing of type bounds r=matklad a=vipentti
This adds new TYPE_BOUND_LIST and TYPE_BOUND syntax kinds. These are now used when parsing type bounds. In addition parsing paths inside a bound now does not recursively parse paths, rather they are treated as separate bounds, separated by +.
Basically now the generic params `struct S<T: 'a + ?Sized + (Copy)>;` in will be parsed as
```
TYPE_PARAM_LIST@[8; 33)
L_ANGLE@[8; 9)
TYPE_PARAM@[9; 32)
NAME@[9; 10)
IDENT@[9; 10) "T"
COLON@[10; 11)
WHITESPACE@[11; 12)
TYPE_BOUND_LIST@[12; 32)
TYPE_BOUND@[12; 14)
LIFETIME@[12; 14) "'a"
WHITESPACE@[14; 15)
PLUS@[15; 16)
WHITESPACE@[16; 17)
TYPE_BOUND@[17; 23)
QUESTION@[17; 18)
PATH_TYPE@[18; 23)
PATH@[18; 23)
PATH_SEGMENT@[18; 23)
NAME_REF@[18; 23)
IDENT@[18; 23) "Sized"
WHITESPACE@[23; 24)
PLUS@[24; 25)
WHITESPACE@[25; 26)
TYPE_BOUND@[26; 32)
L_PAREN@[26; 27)
PATH_TYPE@[27; 31)
PATH@[27; 31)
PATH_SEGMENT@[27; 31)
NAME_REF@[27; 31)
IDENT@[27; 31) "Copy"
R_PAREN@[31; 32)
R_ANGLE@[32; 33)
```
Previously it was parsed, with the paths nested:
```
TYPE_PARAM_LIST@[8; 33)
L_ANGLE@[8; 9)
TYPE_PARAM@[9; 32)
NAME@[9; 10)
IDENT@[9; 10) "T"
COLON@[10; 11)
WHITESPACE@[11; 12)
LIFETIME@[12; 14) "'a"
WHITESPACE@[14; 15)
PLUS@[15; 16)
WHITESPACE@[16; 17)
QUESTION@[17; 18)
PATH_TYPE@[18; 32)
PATH@[18; 23)
PATH_SEGMENT@[18; 23)
NAME_REF@[18; 23)
IDENT@[18; 23) "Sized"
WHITESPACE@[23; 24)
PLUS@[24; 25)
WHITESPACE@[25; 26)
L_PAREN@[26; 27)
PATH_TYPE@[27; 31)
PATH@[27; 31)
PATH_SEGMENT@[27; 31)
NAME_REF@[27; 31)
IDENT@[27; 31) "Copy"
R_PAREN@[31; 32)
R_ANGLE@[32; 33)
```
Looking for feedback.
Co-authored-by: Ville Penttinen <[email protected]>
Diffstat (limited to 'crates/ra_parser')
-rw-r--r-- | crates/ra_parser/src/grammar/items/traits.rs | 1 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar/type_params.rs | 43 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar/types.rs | 40 | ||||
-rw-r--r-- | crates/ra_parser/src/syntax_kind/generated.rs | 4 |
4 files changed, 68 insertions, 20 deletions
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs index f49615f6b..d03a6be0d 100644 --- a/crates/ra_parser/src/grammar/items/traits.rs +++ b/crates/ra_parser/src/grammar/items/traits.rs | |||
@@ -2,6 +2,7 @@ use super::*; | |||
2 | 2 | ||
3 | // test trait_item | 3 | // test trait_item |
4 | // trait T<U>: Hash + Clone where U: Copy {} | 4 | // trait T<U>: Hash + Clone where U: Copy {} |
5 | // trait X<U: Debug + Display>: Hash + Clone where U: Copy {} | ||
5 | pub(super) fn trait_def(p: &mut Parser) { | 6 | pub(super) fn trait_def(p: &mut Parser) { |
6 | assert!(p.at(TRAIT_KW)); | 7 | assert!(p.at(TRAIT_KW)); |
7 | p.bump(); | 8 | p.bump(); |
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs index 40f998682..42763fc87 100644 --- a/crates/ra_parser/src/grammar/type_params.rs +++ b/crates/ra_parser/src/grammar/type_params.rs | |||
@@ -79,23 +79,40 @@ fn lifetime_bounds(p: &mut Parser) { | |||
79 | } | 79 | } |
80 | } | 80 | } |
81 | 81 | ||
82 | pub(super) fn bounds_without_colon(p: &mut Parser) { | 82 | pub(super) fn bounds_without_colon_m(p: &mut Parser, marker: Marker) -> CompletedMarker { |
83 | loop { | 83 | while type_bound(p) { |
84 | let has_paren = p.eat(L_PAREN); | ||
85 | p.eat(QUESTION); | ||
86 | match p.current() { | ||
87 | LIFETIME => p.bump(), | ||
88 | FOR_KW => types::for_type(p), | ||
89 | _ if paths::is_path_start(p) => types::path_type(p), | ||
90 | _ => break, | ||
91 | } | ||
92 | if has_paren { | ||
93 | p.expect(R_PAREN); | ||
94 | } | ||
95 | if !p.eat(PLUS) { | 84 | if !p.eat(PLUS) { |
96 | break; | 85 | break; |
97 | } | 86 | } |
98 | } | 87 | } |
88 | |||
89 | marker.complete(p, TYPE_BOUND_LIST) | ||
90 | } | ||
91 | |||
92 | pub(super) fn bounds_without_colon(p: &mut Parser) { | ||
93 | let m = p.start(); | ||
94 | bounds_without_colon_m(p, m); | ||
95 | } | ||
96 | |||
97 | fn type_bound(p: &mut Parser) -> bool { | ||
98 | let m = p.start(); | ||
99 | let has_paren = p.eat(L_PAREN); | ||
100 | p.eat(QUESTION); | ||
101 | match p.current() { | ||
102 | LIFETIME => p.bump(), | ||
103 | FOR_KW => types::for_type(p), | ||
104 | _ if paths::is_path_start(p) => types::path_type_(p, false), | ||
105 | _ => { | ||
106 | m.abandon(p); | ||
107 | return false; | ||
108 | } | ||
109 | } | ||
110 | if has_paren { | ||
111 | p.expect(R_PAREN); | ||
112 | } | ||
113 | m.complete(p, TYPE_BOUND); | ||
114 | |||
115 | true | ||
99 | } | 116 | } |
100 | 117 | ||
101 | // test where_clause | 118 | // test where_clause |
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs index fdd4f2c52..a46da9b44 100644 --- a/crates/ra_parser/src/grammar/types.rs +++ b/crates/ra_parser/src/grammar/types.rs | |||
@@ -261,21 +261,47 @@ fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) { | |||
261 | PATH_TYPE | 261 | PATH_TYPE |
262 | }; | 262 | }; |
263 | 263 | ||
264 | if allow_bounds && p.eat(PLUS) { | 264 | let path = m.complete(p, kind); |
265 | type_params::bounds_without_colon(p); | ||
266 | } | ||
267 | 265 | ||
268 | m.complete(p, kind); | 266 | if allow_bounds { |
267 | opt_path_type_bounds_as_dyn_trait_type(p, path); | ||
268 | } | ||
269 | } | 269 | } |
270 | 270 | ||
271 | pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { | 271 | pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { |
272 | assert!(paths::is_path_start(p) || p.at(L_ANGLE)); | 272 | assert!(paths::is_path_start(p) || p.at(L_ANGLE)); |
273 | let m = p.start(); | 273 | let m = p.start(); |
274 | paths::type_path(p); | 274 | paths::type_path(p); |
275 | |||
275 | // test path_type_with_bounds | 276 | // test path_type_with_bounds |
276 | // fn foo() -> Box<T + 'f> {} | 277 | // fn foo() -> Box<T + 'f> {} |
277 | if allow_bounds && p.eat(PLUS) { | 278 | // fn foo() -> Box<dyn T + 'f> {} |
278 | type_params::bounds_without_colon(p); | 279 | let path = m.complete(p, PATH_TYPE); |
280 | if allow_bounds { | ||
281 | opt_path_type_bounds_as_dyn_trait_type(p, path); | ||
279 | } | 282 | } |
280 | m.complete(p, PATH_TYPE); | 283 | } |
284 | |||
285 | /// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE | ||
286 | /// with a TYPE_BOUND_LIST | ||
287 | fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) { | ||
288 | if !p.at(PLUS) { | ||
289 | return; | ||
290 | } | ||
291 | |||
292 | // First create a TYPE_BOUND from the completed PATH_TYPE | ||
293 | let m = path_type_marker.precede(p).complete(p, TYPE_BOUND); | ||
294 | |||
295 | // Next setup a marker for the TYPE_BOUND_LIST | ||
296 | let m = m.precede(p); | ||
297 | |||
298 | // This gets consumed here so it gets properly set | ||
299 | // in the TYPE_BOUND_LIST | ||
300 | p.eat(PLUS); | ||
301 | |||
302 | // Parse rest of the bounds into the TYPE_BOUND_LIST | ||
303 | let m = type_params::bounds_without_colon_m(p, m); | ||
304 | |||
305 | // Finally precede everything with DYN_TRAIT_TYPE | ||
306 | m.precede(p).complete(p, DYN_TRAIT_TYPE); | ||
281 | } | 307 | } |
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs index 03247ae38..547af1b27 100644 --- a/crates/ra_parser/src/syntax_kind/generated.rs +++ b/crates/ra_parser/src/syntax_kind/generated.rs | |||
@@ -228,6 +228,8 @@ pub enum SyntaxKind { | |||
228 | PARAM, | 228 | PARAM, |
229 | SELF_PARAM, | 229 | SELF_PARAM, |
230 | ARG_LIST, | 230 | ARG_LIST, |
231 | TYPE_BOUND, | ||
232 | TYPE_BOUND_LIST, | ||
231 | } | 233 | } |
232 | use self::SyntaxKind::*; | 234 | use self::SyntaxKind::*; |
233 | 235 | ||
@@ -567,6 +569,8 @@ impl SyntaxKind { | |||
567 | PARAM => &SyntaxInfo { name: "PARAM" }, | 569 | PARAM => &SyntaxInfo { name: "PARAM" }, |
568 | SELF_PARAM => &SyntaxInfo { name: "SELF_PARAM" }, | 570 | SELF_PARAM => &SyntaxInfo { name: "SELF_PARAM" }, |
569 | ARG_LIST => &SyntaxInfo { name: "ARG_LIST" }, | 571 | ARG_LIST => &SyntaxInfo { name: "ARG_LIST" }, |
572 | TYPE_BOUND => &SyntaxInfo { name: "TYPE_BOUND" }, | ||
573 | TYPE_BOUND_LIST => &SyntaxInfo { name: "TYPE_BOUND_LIST" }, | ||
570 | TOMBSTONE => &SyntaxInfo { name: "TOMBSTONE" }, | 574 | TOMBSTONE => &SyntaxInfo { name: "TOMBSTONE" }, |
571 | EOF => &SyntaxInfo { name: "EOF" }, | 575 | EOF => &SyntaxInfo { name: "EOF" }, |
572 | } | 576 | } |