From 23fdc562bf06bd001ec728d63a8f5b945bd96700 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Sat, 30 Mar 2019 17:11:21 +0200 Subject: Add 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 +. --- crates/ra_parser/src/grammar/items/traits.rs | 1 + crates/ra_parser/src/grammar/type_params.rs | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'crates/ra_parser/src/grammar') 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::*; // test trait_item // trait T: Hash + Clone where U: Copy {} +// trait X: Hash + Clone where U: Copy {} pub(super) fn trait_def(p: &mut Parser) { assert!(p.at(TRAIT_KW)); p.bump(); diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs index 40f998682..e28c124cd 100644 --- a/crates/ra_parser/src/grammar/type_params.rs +++ b/crates/ra_parser/src/grammar/type_params.rs @@ -80,22 +80,29 @@ fn lifetime_bounds(p: &mut Parser) { } pub(super) fn bounds_without_colon(p: &mut Parser) { + let outer = p.start(); loop { + let inner = p.start(); let has_paren = p.eat(L_PAREN); p.eat(QUESTION); match p.current() { LIFETIME => p.bump(), FOR_KW => types::for_type(p), - _ if paths::is_path_start(p) => types::path_type(p), - _ => break, + _ if paths::is_path_start(p) => types::path_type_(p, false), + _ => { + inner.abandon(p); + break; + } } if has_paren { p.expect(R_PAREN); } + inner.complete(p, TYPE_BOUND); if !p.eat(PLUS) { break; } } + outer.complete(p, TYPE_BOUND_LIST); } // test where_clause -- cgit v1.2.3 From e3f9d6555beec6fb4bebf6aef3e983149f7aee3a Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Sat, 30 Mar 2019 17:23:54 +0200 Subject: Move parsing a single TYPE_BOUND to a separate function --- crates/ra_parser/src/grammar/type_params.rs | 45 +++++++++++++++++------------ 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'crates/ra_parser/src/grammar') diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs index e28c124cd..01175c0a3 100644 --- a/crates/ra_parser/src/grammar/type_params.rs +++ b/crates/ra_parser/src/grammar/type_params.rs @@ -80,29 +80,36 @@ fn lifetime_bounds(p: &mut Parser) { } pub(super) fn bounds_without_colon(p: &mut Parser) { - let outer = p.start(); - loop { - let inner = p.start(); - let has_paren = p.eat(L_PAREN); - p.eat(QUESTION); - match p.current() { - LIFETIME => p.bump(), - FOR_KW => types::for_type(p), - _ if paths::is_path_start(p) => types::path_type_(p, false), - _ => { - inner.abandon(p); - break; - } - } - if has_paren { - p.expect(R_PAREN); - } - inner.complete(p, TYPE_BOUND); + let m = p.start(); + + while type_bound(p) { if !p.eat(PLUS) { break; } } - outer.complete(p, TYPE_BOUND_LIST); + + m.complete(p, TYPE_BOUND_LIST); +} + +fn type_bound(p: &mut Parser) -> bool { + let m = p.start(); + let has_paren = p.eat(L_PAREN); + p.eat(QUESTION); + match p.current() { + LIFETIME => p.bump(), + FOR_KW => types::for_type(p), + _ if paths::is_path_start(p) => types::path_type_(p, false), + _ => { + m.abandon(p); + return false; + } + } + if has_paren { + p.expect(R_PAREN); + } + m.complete(p, TYPE_BOUND); + + true } // test where_clause -- cgit v1.2.3 From 98cff6ecec1b0af2cb9cead544526a0dbf2760f5 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Sun, 31 Mar 2019 10:35:55 +0300 Subject: Change parsing bounds in path_types Now bounds inside a path are parsed as DYN_TRAIT_TYPE, previously they would be parsed as `PATH_TYPE` followed by `TYPE_BOUND_LIST`. Basically this means `Box` is now parsed almost the same as `Box` with the exception of not having the `dyn` keyword. --- crates/ra_parser/src/grammar/type_params.rs | 11 +++++--- crates/ra_parser/src/grammar/types.rs | 40 ++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 11 deletions(-) (limited to 'crates/ra_parser/src/grammar') diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs index 01175c0a3..42763fc87 100644 --- a/crates/ra_parser/src/grammar/type_params.rs +++ b/crates/ra_parser/src/grammar/type_params.rs @@ -79,16 +79,19 @@ fn lifetime_bounds(p: &mut Parser) { } } -pub(super) fn bounds_without_colon(p: &mut Parser) { - let m = p.start(); - +pub(super) fn bounds_without_colon_m(p: &mut Parser, marker: Marker) -> CompletedMarker { while type_bound(p) { if !p.eat(PLUS) { break; } } - m.complete(p, TYPE_BOUND_LIST); + marker.complete(p, TYPE_BOUND_LIST) +} + +pub(super) fn bounds_without_colon(p: &mut Parser) { + let m = p.start(); + bounds_without_colon_m(p, m); } fn type_bound(p: &mut Parser) -> bool { 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) { PATH_TYPE }; - if allow_bounds && p.eat(PLUS) { - type_params::bounds_without_colon(p); - } + let path = m.complete(p, kind); - m.complete(p, kind); + if allow_bounds { + opt_path_type_bounds_as_dyn_trait_type(p, path); + } } pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { assert!(paths::is_path_start(p) || p.at(L_ANGLE)); let m = p.start(); paths::type_path(p); + // test path_type_with_bounds // fn foo() -> Box {} - if allow_bounds && p.eat(PLUS) { - type_params::bounds_without_colon(p); + // fn foo() -> Box {} + let path = m.complete(p, PATH_TYPE); + if allow_bounds { + opt_path_type_bounds_as_dyn_trait_type(p, path); } - m.complete(p, PATH_TYPE); +} + +/// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE +/// with a TYPE_BOUND_LIST +fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) { + if !p.at(PLUS) { + return; + } + + // First create a TYPE_BOUND from the completed PATH_TYPE + let m = path_type_marker.precede(p).complete(p, TYPE_BOUND); + + // Next setup a marker for the TYPE_BOUND_LIST + let m = m.precede(p); + + // This gets consumed here so it gets properly set + // in the TYPE_BOUND_LIST + p.eat(PLUS); + + // Parse rest of the bounds into the TYPE_BOUND_LIST + let m = type_params::bounds_without_colon_m(p, m); + + // Finally precede everything with DYN_TRAIT_TYPE + m.precede(p).complete(p, DYN_TRAIT_TYPE); } -- cgit v1.2.3