Repository: rust-analyzer/rust-analyzer
Pull request #2551 (2019-12-13 13:56:35)

Refactor tt::Subtree delimiter
Refactor to : 
```
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct Subtree {
    pub delimiter: Option<Delimiter>,
    pub token_trees: Vec<TokenTree>,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Delimiter {
    Parenthesis,
    Brace,
    Bracket,
}
```


Patch:
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs
index 4f698ff134..aa8a5f23fd 100644
--- a/crates/ra_hir_expand/src/quote.rs
+++ b/crates/ra_hir_expand/src/quote.rs
@@ -16,7 +16,7 @@ macro_rules! __quote {
         {
             let children = $crate::__quote!($($tt)*);
             let subtree = tt::Subtree {
-                delimiter: tt::Delimiter::$delim,
+                delimiter: Some(tt::Delimiter::$delim),
                 token_trees: $crate::quote::IntoTt::to_tokens(children),
             };
             subtree
@@ -124,7 +124,7 @@ pub(crate) trait IntoTt {
 
 impl IntoTt for Vec<tt::TokenTree> {
     fn to_subtree(self) -> tt::Subtree {
-        tt::Subtree { delimiter: tt::Delimiter::None, token_trees: self }
+        tt::Subtree { delimiter: None, token_trees: self }
     }
 
     fn to_tokens(self) -> Vec<tt::TokenTree> {
@@ -254,7 +254,8 @@ mod tests {
         let fields =
             fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten();
 
-        let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() };
+        let list =
+            tt::Subtree { delimiter: Some(tt::Delimiter::Brace), token_trees: fields.collect() };
 
         let quoted = quote! {
             impl Clone for #struct_name {
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index bbddebe67f..0d2d43bef4 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -159,14 +159,14 @@ impl Rule {
             .expect_subtree()
             .map_err(|()| ParseError::Expected("expected subtree".to_string()))?
             .clone();
-        lhs.delimiter = tt::Delimiter::None;
+        lhs.delimiter = None;
         src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?;
         src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?;
         let mut rhs = src
             .expect_subtree()
             .map_err(|()| ParseError::Expected("expected subtree".to_string()))?
             .clone();
-        rhs.delimiter = tt::Delimiter::None;
+        rhs.delimiter = None;
         Ok(crate::Rule { lhs, rhs })
     }
 }
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs
index 33b9d483d2..3f51364780 100644
--- a/crates/ra_mbe/src/mbe_expander/matcher.rs
+++ b/crates/ra_mbe/src/mbe_expander/matcher.rs
@@ -16,7 +16,7 @@ impl Bindings {
     fn push_optional(&mut self, name: &SmolStr) {
         // FIXME: Do we have a better way to represent an empty token ?
         // Insert an empty subtree for empty token
-        let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into();
+        let tt = tt::Subtree::default().into();
         self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
     }
 
@@ -65,7 +65,7 @@ macro_rules! bail {
 }
 
 pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> {
-    assert!(pattern.delimiter == tt::Delimiter::None);
+    assert!(pattern.delimiter == None);
 
     let mut res = Bindings::default();
     let mut src = TtIter::new(src);
@@ -210,7 +210,7 @@ impl<'a> TtIter<'a> {
             0 => Err(()),
             1 => Ok(res[0].clone()),
             _ => Ok(tt::TokenTree::Subtree(tt::Subtree {
-                delimiter: tt::Delimiter::None,
+                delimiter: None,
                 token_trees: res.into_iter().cloned().collect(),
             })),
         }
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs
index ed094d5bb4..f7636db11b 100644
--- a/crates/ra_mbe/src/mbe_expander/transcriber.rs
+++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs
@@ -50,7 +50,7 @@ pub(super) fn transcribe(
     template: &tt::Subtree,
     bindings: &Bindings,
 ) -> Result<tt::Subtree, ExpandError> {
-    assert!(template.delimiter == tt::Delimiter::None);
+    assert!(template.delimiter == None);
     let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false };
     expand_subtree(&mut ctx, template)
 }
@@ -106,7 +106,7 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError>
         // ```
         // We just treat it a normal tokens
         let tt = tt::Subtree {
-            delimiter: tt::Delimiter::None,
+            delimiter: None,
             token_trees: vec![
                 tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone }).into(),
                 tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() })
@@ -147,7 +147,7 @@ fn expand_repeat(
     ctx.var_expanded = false;
 
     while let Ok(mut t) = expand_subtree(ctx, template) {
-        t.delimiter = tt::Delimiter::None;
+        t.delimiter = None;
         // if no var expanded in the child, we count it as a fail
         if !ctx.var_expanded {
             break;
@@ -212,7 +212,7 @@ fn expand_repeat(
 
     // Check if it is a single token subtree without any delimiter
     // e.g {Delimiter:None> ['>'] /Delimiter:None>}
-    let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into();
+    let tt = tt::Subtree { delimiter: None, token_trees: buf }.into();
     Ok(Fragment::Tokens(tt))
 }
 
@@ -225,7 +225,7 @@ fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
 
 fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
     match tt.delimiter {
-        tt::Delimiter::None => buf.extend(tt.token_trees),
+        None => buf.extend(tt.token_trees),
         _ => buf.push(tt.into()),
     }
 }
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs
index 7ef45f6dc4..061e9f20b2 100644
--- a/crates/ra_mbe/src/subtree_source.rs
+++ b/crates/ra_mbe/src/subtree_source.rs
@@ -114,12 +114,12 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> {
     }
 }
 
-fn convert_delim(d: tt::Delimiter, closing: bool) -> TtToken {
+fn convert_delim(d: Option<tt::Delimiter>, closing: bool) -> TtToken {
     let (kinds, texts) = match d {
-        tt::Delimiter::Parenthesis => ([T!['('], T![')']], "()"),
-        tt::Delimiter::Brace => ([T!['{'], T!['}']], "{}"),
-        tt::Delimiter::Bracket => ([T!['['], T![']']], "[]"),
-        tt::Delimiter::None => ([L_DOLLAR, R_DOLLAR], ""),
+        Some(tt::Delimiter::Parenthesis) => ([T!['('], T![')']], "()"),
+        Some(tt::Delimiter::Brace) => ([T!['{'], T!['}']], "{}"),
+        Some(tt::Delimiter::Bracket) => ([T!['['], T![']']], "[]"),
+        None => ([L_DOLLAR, R_DOLLAR], ""),
     };
 
     let idx = closing as usize;
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 66c1f0337d..b8e2cfc1d8 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -51,7 +51,7 @@ pub fn token_tree_to_syntax_node(
 ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> {
     let tmp;
     let tokens = match tt {
-        tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(),
+        tt::Subtree { delimiter: None, token_trees } => token_trees.as_slice(),
         _ => {
             tmp = [tt.clone().into()];
             &tmp[..]
@@ -121,7 +121,7 @@ fn convert_doc_comment(token: &ra_syntax::SyntaxToken) -> Option<Vec<tt::TokenTr
         token_trees.push(mk_punct('!'));
     }
     token_trees.push(tt::TokenTree::from(tt::Subtree {
-        delimiter: tt::Delimiter::Bracket,
+        delimiter: Some(tt::Delimiter::Bracket),
         token_trees: meta_tkns,
     }));
 
@@ -156,7 +156,7 @@ impl Convertor {
     fn go(&mut self, tt: &SyntaxNode) -> Option<tt::Subtree> {
         // This tree is empty
         if tt.first_child_or_token().is_none() {
-            return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None });
+            return Some(tt::Subtree { token_trees: vec![], delimiter: None });
         }
 
         let first_child = tt.first_child_or_token()?;
@@ -173,7 +173,7 @@ impl Convertor {
         .last()
         .unwrap();
         if first_child.kind().is_trivia() {
-            return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None });
+            return Some(tt::Subtree { token_trees: vec![], delimiter: None });
         }
 
         let last_child = successors(Some(last_child), |it| {
@@ -187,10 +187,10 @@ impl Convertor {
         .unwrap();
 
         let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) {
-            (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true),
-            (T!['{'], T!['}']) => (tt::Delimiter::Brace, true),
-            (T!['['], T![']']) => (tt::Delimiter::Bracket, true),
-            _ => (tt::Delimiter::None, false),
+            (T!['('], T![')']) => (Some(tt::Delimiter::Parenthesis), true),
+            (T!['{'], T!['}']) => (Some(tt::Delimiter::Brace), true),
+            (T!['['], T![']']) => (Some(tt::Delimiter::Bracket), true),
+            _ => (None, false),
         };
 
         let mut token_trees = Vec::new();
@@ -246,9 +246,7 @@ impl Convertor {
                 }
                 NodeOrToken::Node(node) => {
                     let child_subtree = self.go(&node)?;
-                    if child_subtree.delimiter == tt::Delimiter::None
-                        && node.kind() != SyntaxKind::TOKEN_TREE
-                    {
+                    if child_subtree.delimiter.is_none() && node.kind() != SyntaxKind::TOKEN_TREE {
                         token_trees.extend(child_subtree.token_trees);
                     } else {
                         token_trees.push(child_subtree.into());
@@ -299,16 +297,16 @@ impl<'a> TtTreeSink<'a> {
     }
 }
 
-fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr {
+fn delim_to_str(d: Option<tt::Delimiter>, closing: bool) -> SmolStr {
     let texts = match d {
-        tt::Delimiter::Parenthesis => "()",
-        tt::Delimiter::Brace => "{}",
-        tt::Delimiter::Bracket => "[]",
-        tt::Delimiter::None => "",
+        Some(tt::Delimiter::Parenthesis) => "()",
+        Some(tt::Delimiter::Brace) => "{}",
+        Some(tt::Delimiter::Bracket) => "[]",
+        None => return "".into(),
     };
 
     let idx = closing as usize;
-    let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" };
+    let text = &texts[idx..texts.len() - (1 - idx)];
     text.into()
 }
 
@@ -497,7 +495,7 @@ mod tests {
         let token_tree = ast::TokenTree::cast(token_tree).unwrap();
         let tt = ast_to_token_tree(&token_tree).unwrap().0;
 
-        assert_eq!(tt.delimiter, tt::Delimiter::Brace);
+        assert_eq!(tt.delimiter, Some(tt::Delimiter::Brace));
     }
 
     #[test]
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index 4c00b8f302..e7bfd5fd29 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -48,9 +48,9 @@ pub enum Leaf {
 }
 impl_froms!(Leaf: Literal, Punct, Ident);
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
 pub struct Subtree {
-    pub delimiter: Delimiter,
+    pub delimiter: Option<Delimiter>,
     pub token_trees: Vec<TokenTree>,
 }
 
@@ -59,7 +59,6 @@ pub enum Delimiter {
     Parenthesis,
     Brace,
     Bracket,
-    None,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -97,10 +96,10 @@ impl fmt::Display for TokenTree {
 impl fmt::Display for Subtree {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let (l, r) = match self.delimiter {
-            Delimiter::Parenthesis => ("(", ")"),
-            Delimiter::Brace => ("{", "}"),
-            Delimiter::Bracket => ("[", "]"),
-            Delimiter::None => ("", ""),
+            Some(Delimiter::Parenthesis) => ("(", ")"),
+            Some(Delimiter::Brace) => ("{", "}"),
+            Some(Delimiter::Bracket) => ("[", "]"),
+            None => ("", ""),
         };
         f.write_str(l)?;
         let mut needs_space = false;


Test patch:
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index 0109a4d980..148cc26254 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -1463,7 +1463,7 @@ pub(crate) fn assert_expansion(
         let wrapped = ast::SourceFile::parse(&wrapped);
         let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
         let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
-        wrapped.delimiter = tt::Delimiter::None;
+        wrapped.delimiter = None;
         wrapped
     };
     let (expanded_tree, expected_tree) = match kind {