diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-07 00:32:56 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-07 00:32:56 +0000 |
commit | f0b7c02f16f717744e7edc79a405db14110393cf (patch) | |
tree | c0aaf8373aa42ce3b4037fad2f42efba07680f53 /crates/proc_macro_srv/src/rustc_server.rs | |
parent | 07a54f7ae451451292e3282f1e7defb4391b766f (diff) | |
parent | aea974939064b0f7b83de371a93ee4190c80e544 (diff) |
Merge #7892
7892: Fix TokenStream::from_str for input consisting of a single group with delimiter r=edwin0cheng a=kevinmehall
TokenStream holds a `tt::Subtree` but assumes its `delimiter` is always `None`. In particular, the iterator implementation iterates over the inner `token_trees` and ignores the `delimiter`.
However, `TokenStream::from_str` violated this assumption when the input consists of a single group by producing a Subtree with an outer delimiter, which was ignored as seen by a procedural macro.
`tt::Subtree` is just `pub delimiter: Option<Delimiter>, pub token_trees: Vec<TokenTree>`, so a Subtree that is statically guaranteed not to have a delimiter is just `Vec<TokenTree>`.
Fixes #7810
Fixes #7875
Co-authored-by: Kevin Mehall <[email protected]>
Diffstat (limited to 'crates/proc_macro_srv/src/rustc_server.rs')
-rw-r--r-- | crates/proc_macro_srv/src/rustc_server.rs | 141 |
1 files changed, 84 insertions, 57 deletions
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs index 14c853c77..ceefd187d 100644 --- a/crates/proc_macro_srv/src/rustc_server.rs +++ b/crates/proc_macro_srv/src/rustc_server.rs | |||
@@ -25,27 +25,35 @@ type Span = tt::TokenId; | |||
25 | 25 | ||
26 | #[derive(Debug, Clone)] | 26 | #[derive(Debug, Clone)] |
27 | pub struct TokenStream { | 27 | pub struct TokenStream { |
28 | pub subtree: tt::Subtree, | 28 | pub token_trees: Vec<TokenTree>, |
29 | } | 29 | } |
30 | 30 | ||
31 | impl TokenStream { | 31 | impl TokenStream { |
32 | pub fn new() -> Self { | 32 | pub fn new() -> Self { |
33 | TokenStream { subtree: Default::default() } | 33 | TokenStream { token_trees: Default::default() } |
34 | } | 34 | } |
35 | 35 | ||
36 | pub fn with_subtree(subtree: tt::Subtree) -> Self { | 36 | pub fn with_subtree(subtree: tt::Subtree) -> Self { |
37 | TokenStream { subtree } | 37 | if subtree.delimiter.is_some() { |
38 | TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } | ||
39 | } else { | ||
40 | TokenStream { token_trees: subtree.token_trees } | ||
41 | } | ||
42 | } | ||
43 | |||
44 | pub fn into_subtree(self) -> tt::Subtree { | ||
45 | tt::Subtree { delimiter: None, token_trees: self.token_trees } | ||
38 | } | 46 | } |
39 | 47 | ||
40 | pub fn is_empty(&self) -> bool { | 48 | pub fn is_empty(&self) -> bool { |
41 | self.subtree.token_trees.is_empty() | 49 | self.token_trees.is_empty() |
42 | } | 50 | } |
43 | } | 51 | } |
44 | 52 | ||
45 | /// Creates a token stream containing a single token tree. | 53 | /// Creates a token stream containing a single token tree. |
46 | impl From<TokenTree> for TokenStream { | 54 | impl From<TokenTree> for TokenStream { |
47 | fn from(tree: TokenTree) -> TokenStream { | 55 | fn from(tree: TokenTree) -> TokenStream { |
48 | TokenStream { subtree: tt::Subtree { delimiter: None, token_trees: vec![tree] } } | 56 | TokenStream { token_trees: vec![tree] } |
49 | } | 57 | } |
50 | } | 58 | } |
51 | 59 | ||
@@ -78,10 +86,10 @@ impl Extend<TokenStream> for TokenStream { | |||
78 | for tkn in item { | 86 | for tkn in item { |
79 | match tkn { | 87 | match tkn { |
80 | tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { | 88 | tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { |
81 | self.subtree.token_trees.extend(subtree.token_trees); | 89 | self.token_trees.extend(subtree.token_trees); |
82 | } | 90 | } |
83 | _ => { | 91 | _ => { |
84 | self.subtree.token_trees.push(tkn); | 92 | self.token_trees.push(tkn); |
85 | } | 93 | } |
86 | } | 94 | } |
87 | } | 95 | } |
@@ -164,7 +172,7 @@ pub mod token_stream { | |||
164 | type IntoIter = super::IntoIter<TokenTree>; | 172 | type IntoIter = super::IntoIter<TokenTree>; |
165 | 173 | ||
166 | fn into_iter(self) -> Self::IntoIter { | 174 | fn into_iter(self) -> Self::IntoIter { |
167 | self.subtree.token_trees.into_iter() | 175 | self.token_trees.into_iter() |
168 | } | 176 | } |
169 | } | 177 | } |
170 | 178 | ||
@@ -185,28 +193,22 @@ pub mod token_stream { | |||
185 | mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; | 193 | mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; |
186 | 194 | ||
187 | let subtree = subtree_replace_token_ids_with_unspecified(subtree); | 195 | let subtree = subtree_replace_token_ids_with_unspecified(subtree); |
188 | Ok(TokenStream { subtree }) | 196 | Ok(TokenStream::with_subtree(subtree)) |
189 | } | 197 | } |
190 | } | 198 | } |
191 | 199 | ||
192 | impl ToString for TokenStream { | 200 | impl ToString for TokenStream { |
193 | fn to_string(&self) -> String { | 201 | fn to_string(&self) -> String { |
194 | let tt = self.subtree.clone().into(); | 202 | return tokentrees_to_text(&self.token_trees[..]); |
195 | to_text(&tt) | ||
196 | } | ||
197 | } | ||
198 | 203 | ||
199 | fn to_text(tkn: &tt::TokenTree) -> String { | 204 | fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String { |
200 | match tkn { | 205 | tkns.iter() |
201 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(), | ||
202 | tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(), | ||
203 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char), | ||
204 | tt::TokenTree::Subtree(subtree) => { | ||
205 | let content = subtree | ||
206 | .token_trees | ||
207 | .iter() | ||
208 | .fold((String::new(), true), |(last, last_to_joint), tkn| { | 206 | .fold((String::new(), true), |(last, last_to_joint), tkn| { |
209 | let s = [last, to_text(tkn)].join(if last_to_joint { "" } else { " " }); | 207 | let s = [last, tokentree_to_text(tkn)].join(if last_to_joint { |
208 | "" | ||
209 | } else { | ||
210 | " " | ||
211 | }); | ||
210 | let mut is_joint = false; | 212 | let mut is_joint = false; |
211 | if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { | 213 | if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { |
212 | if punct.spacing == tt::Spacing::Joint { | 214 | if punct.spacing == tt::Spacing::Joint { |
@@ -215,15 +217,25 @@ pub mod token_stream { | |||
215 | } | 217 | } |
216 | (s, is_joint) | 218 | (s, is_joint) |
217 | }) | 219 | }) |
218 | .0; | 220 | .0 |
219 | 221 | } | |
220 | let (open, close) = match subtree.delimiter.map(|it| it.kind) { | 222 | |
221 | None => ("", ""), | 223 | fn tokentree_to_text(tkn: &tt::TokenTree) -> String { |
222 | Some(tt::DelimiterKind::Brace) => ("{", "}"), | 224 | match tkn { |
223 | Some(tt::DelimiterKind::Parenthesis) => ("(", ")"), | 225 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(), |
224 | Some(tt::DelimiterKind::Bracket) => ("[", "]"), | 226 | tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(), |
225 | }; | 227 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char), |
226 | format!("{}{}{}", open, content, close) | 228 | tt::TokenTree::Subtree(subtree) => { |
229 | let content = tokentrees_to_text(&subtree.token_trees); | ||
230 | let (open, close) = match subtree.delimiter.map(|it| it.kind) { | ||
231 | None => ("", ""), | ||
232 | Some(tt::DelimiterKind::Brace) => ("{", "}"), | ||
233 | Some(tt::DelimiterKind::Parenthesis) => ("(", ")"), | ||
234 | Some(tt::DelimiterKind::Bracket) => ("[", "]"), | ||
235 | }; | ||
236 | format!("{}{}{}", open, content, close) | ||
237 | } | ||
238 | } | ||
227 | } | 239 | } |
228 | } | 240 | } |
229 | } | 241 | } |
@@ -433,10 +445,7 @@ fn spacing_to_external(spacing: Spacing) -> bridge::Spacing { | |||
433 | 445 | ||
434 | impl server::Group for Rustc { | 446 | impl server::Group for Rustc { |
435 | fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group { | 447 | fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group { |
436 | Self::Group { | 448 | Self::Group { delimiter: delim_to_internal(delimiter), token_trees: stream.token_trees } |
437 | delimiter: delim_to_internal(delimiter), | ||
438 | token_trees: stream.subtree.token_trees, | ||
439 | } | ||
440 | } | 449 | } |
441 | fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter { | 450 | fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter { |
442 | delim_to_external(group.delimiter) | 451 | delim_to_external(group.delimiter) |
@@ -444,9 +453,7 @@ impl server::Group for Rustc { | |||
444 | 453 | ||
445 | // NOTE: Return value of do not include delimiter | 454 | // NOTE: Return value of do not include delimiter |
446 | fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { | 455 | fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { |
447 | TokenStream { | 456 | TokenStream { token_trees: group.token_trees.clone() } |
448 | subtree: tt::Subtree { delimiter: None, token_trees: group.token_trees.clone() }, | ||
449 | } | ||
450 | } | 457 | } |
451 | 458 | ||
452 | fn span(&mut self, group: &Self::Group) -> Self::Span { | 459 | fn span(&mut self, group: &Self::Group) -> Self::Span { |
@@ -755,28 +762,48 @@ mod tests { | |||
755 | #[test] | 762 | #[test] |
756 | fn test_rustc_server_to_string() { | 763 | fn test_rustc_server_to_string() { |
757 | let s = TokenStream { | 764 | let s = TokenStream { |
758 | subtree: tt::Subtree { | 765 | token_trees: vec![ |
759 | delimiter: None, | 766 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { |
760 | token_trees: vec![ | 767 | text: "struct".into(), |
761 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | 768 | id: tt::TokenId::unspecified(), |
762 | text: "struct".into(), | 769 | })), |
763 | id: tt::TokenId::unspecified(), | 770 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { |
764 | })), | 771 | text: "T".into(), |
765 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | 772 | id: tt::TokenId::unspecified(), |
766 | text: "T".into(), | 773 | })), |
774 | tt::TokenTree::Subtree(tt::Subtree { | ||
775 | delimiter: Some(tt::Delimiter { | ||
767 | id: tt::TokenId::unspecified(), | 776 | id: tt::TokenId::unspecified(), |
768 | })), | 777 | kind: tt::DelimiterKind::Brace, |
769 | tt::TokenTree::Subtree(tt::Subtree { | ||
770 | delimiter: Some(tt::Delimiter { | ||
771 | id: tt::TokenId::unspecified(), | ||
772 | kind: tt::DelimiterKind::Brace, | ||
773 | }), | ||
774 | token_trees: vec![], | ||
775 | }), | 778 | }), |
776 | ], | 779 | token_trees: vec![], |
777 | }, | 780 | }), |
781 | ], | ||
778 | }; | 782 | }; |
779 | 783 | ||
780 | assert_eq!(s.to_string(), "struct T {}"); | 784 | assert_eq!(s.to_string(), "struct T {}"); |
781 | } | 785 | } |
786 | |||
787 | #[test] | ||
788 | fn test_rustc_server_from_str() { | ||
789 | use std::str::FromStr; | ||
790 | let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { | ||
791 | delimiter: Some(tt::Delimiter { | ||
792 | id: tt::TokenId::unspecified(), | ||
793 | kind: tt::DelimiterKind::Parenthesis, | ||
794 | }), | ||
795 | token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | ||
796 | text: "a".into(), | ||
797 | id: tt::TokenId::unspecified(), | ||
798 | }))], | ||
799 | }); | ||
800 | |||
801 | let t1 = TokenStream::from_str("(a)").unwrap(); | ||
802 | assert_eq!(t1.token_trees.len(), 1); | ||
803 | assert_eq!(t1.token_trees[0], subtree_paren_a); | ||
804 | |||
805 | let t2 = TokenStream::from_str("(a);").unwrap(); | ||
806 | assert_eq!(t2.token_trees.len(), 2); | ||
807 | assert_eq!(t2.token_trees[0], subtree_paren_a); | ||
808 | } | ||
782 | } | 809 | } |