aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_parser
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-03-31 10:11:48 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-03-31 10:11:48 +0100
commitc5ca49678f129045e59438df279829902034ec71 (patch)
tree3fd54185e0c064fbd6f718ac345064ce9c559efb /crates/ra_parser
parent23dd53eb35ff50508d0c0fc5878a55754b12d381 (diff)
parent55dcdb7d094f473c73f87ecf997b24f8e35f2a5e (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.rs1
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs43
-rw-r--r--crates/ra_parser/src/grammar/types.rs40
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs4
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 {}
5pub(super) fn trait_def(p: &mut Parser) { 6pub(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
82pub(super) fn bounds_without_colon(p: &mut Parser) { 82pub(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
92pub(super) fn bounds_without_colon(p: &mut Parser) {
93 let m = p.start();
94 bounds_without_colon_m(p, m);
95}
96
97fn 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
271pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { 271pub(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
287fn 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}
232use self::SyntaxKind::*; 234use 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 }