Skip to content

Commit f0b7c02

Browse files
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]>
2 parents 07a54f7 + aea9749 commit f0b7c02

File tree

4 files changed

+89
-62
lines changed

4 files changed

+89
-62
lines changed

crates/proc_macro_srv/src/dylib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl Expander {
138138
parsed_body,
139139
false,
140140
);
141-
return res.map(|it| it.subtree);
141+
return res.map(|it| it.into_subtree());
142142
}
143143
bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
144144
let res = client.run(
@@ -147,7 +147,7 @@ impl Expander {
147147
parsed_body,
148148
false,
149149
);
150-
return res.map(|it| it.subtree);
150+
return res.map(|it| it.into_subtree());
151151
}
152152
bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
153153
let res = client.run(
@@ -157,7 +157,7 @@ impl Expander {
157157
parsed_body,
158158
false,
159159
);
160-
return res.map(|it| it.subtree);
160+
return res.map(|it| it.into_subtree());
161161
}
162162
_ => continue,
163163
}

crates/proc_macro_srv/src/proc_macro/bridge/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ macro_rules! define_client_side {
238238
$(impl $name {
239239
#[allow(unused)]
240240
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
241-
panic!("hello");
241+
panic!("crates should be linked against the sysroot version of proc_macro, not this one from rust-analyzer");
242242
// Bridge::with(|bridge| {
243243
// let mut b = bridge.cached_buffer.take();
244244

crates/proc_macro_srv/src/rustc_server.rs

Lines changed: 84 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,35 @@ type Span = tt::TokenId;
2525

2626
#[derive(Debug, Clone)]
2727
pub struct TokenStream {
28-
pub subtree: tt::Subtree,
28+
pub token_trees: Vec<TokenTree>,
2929
}
3030

3131
impl TokenStream {
3232
pub fn new() -> Self {
33-
TokenStream { subtree: Default::default() }
33+
TokenStream { token_trees: Default::default() }
3434
}
3535

3636
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 }
3846
}
3947

4048
pub fn is_empty(&self) -> bool {
41-
self.subtree.token_trees.is_empty()
49+
self.token_trees.is_empty()
4250
}
4351
}
4452

4553
/// Creates a token stream containing a single token tree.
4654
impl From<TokenTree> for TokenStream {
4755
fn from(tree: TokenTree) -> TokenStream {
48-
TokenStream { subtree: tt::Subtree { delimiter: None, token_trees: vec![tree] } }
56+
TokenStream { token_trees: vec![tree] }
4957
}
5058
}
5159

@@ -78,10 +86,10 @@ impl Extend<TokenStream> for TokenStream {
7886
for tkn in item {
7987
match tkn {
8088
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);
8290
}
8391
_ => {
84-
self.subtree.token_trees.push(tkn);
92+
self.token_trees.push(tkn);
8593
}
8694
}
8795
}
@@ -164,7 +172,7 @@ pub mod token_stream {
164172
type IntoIter = super::IntoIter<TokenTree>;
165173

166174
fn into_iter(self) -> Self::IntoIter {
167-
self.subtree.token_trees.into_iter()
175+
self.token_trees.into_iter()
168176
}
169177
}
170178

@@ -185,28 +193,22 @@ pub mod token_stream {
185193
mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
186194

187195
let subtree = subtree_replace_token_ids_with_unspecified(subtree);
188-
Ok(TokenStream { subtree })
196+
Ok(TokenStream::with_subtree(subtree))
189197
}
190198
}
191199

192200
impl ToString for TokenStream {
193201
fn to_string(&self) -> String {
194-
let tt = self.subtree.clone().into();
195-
to_text(&tt)
196-
}
197-
}
202+
return tokentrees_to_text(&self.token_trees[..]);
198203

199-
fn to_text(tkn: &tt::TokenTree) -> String {
200-
match tkn {
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()
204+
fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
205+
tkns.iter()
208206
.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+
});
210212
let mut is_joint = false;
211213
if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
212214
if punct.spacing == tt::Spacing::Joint {
@@ -215,15 +217,25 @@ pub mod token_stream {
215217
}
216218
(s, is_joint)
217219
})
218-
.0;
219-
220-
let (open, close) = match subtree.delimiter.map(|it| it.kind) {
221-
None => ("", ""),
222-
Some(tt::DelimiterKind::Brace) => ("{", "}"),
223-
Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
224-
Some(tt::DelimiterKind::Bracket) => ("[", "]"),
225-
};
226-
format!("{}{}{}", open, content, close)
220+
.0
221+
}
222+
223+
fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
224+
match tkn {
225+
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
226+
tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
227+
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
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+
}
227239
}
228240
}
229241
}
@@ -433,20 +445,15 @@ fn spacing_to_external(spacing: Spacing) -> bridge::Spacing {
433445

434446
impl server::Group for Rustc {
435447
fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group {
436-
Self::Group {
437-
delimiter: delim_to_internal(delimiter),
438-
token_trees: stream.subtree.token_trees,
439-
}
448+
Self::Group { delimiter: delim_to_internal(delimiter), token_trees: stream.token_trees }
440449
}
441450
fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter {
442451
delim_to_external(group.delimiter)
443452
}
444453

445454
// NOTE: Return value of do not include delimiter
446455
fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
447-
TokenStream {
448-
subtree: tt::Subtree { delimiter: None, token_trees: group.token_trees.clone() },
449-
}
456+
TokenStream { token_trees: group.token_trees.clone() }
450457
}
451458

452459
fn span(&mut self, group: &Self::Group) -> Self::Span {
@@ -755,28 +762,48 @@ mod tests {
755762
#[test]
756763
fn test_rustc_server_to_string() {
757764
let s = TokenStream {
758-
subtree: tt::Subtree {
759-
delimiter: None,
760-
token_trees: vec![
761-
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
762-
text: "struct".into(),
763-
id: tt::TokenId::unspecified(),
764-
})),
765-
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
766-
text: "T".into(),
765+
token_trees: vec![
766+
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
767+
text: "struct".into(),
768+
id: tt::TokenId::unspecified(),
769+
})),
770+
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
771+
text: "T".into(),
772+
id: tt::TokenId::unspecified(),
773+
})),
774+
tt::TokenTree::Subtree(tt::Subtree {
775+
delimiter: Some(tt::Delimiter {
767776
id: tt::TokenId::unspecified(),
768-
})),
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![],
777+
kind: tt::DelimiterKind::Brace,
775778
}),
776-
],
777-
},
779+
token_trees: vec![],
780+
}),
781+
],
778782
};
779783

780784
assert_eq!(s.to_string(), "struct T {}");
781785
}
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+
}
782809
}

crates/proc_macro_srv/src/tests/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub fn assert_expand(
5252
let expander = dylib::Expander::new(&path).unwrap();
5353
let fixture = parse_string(ra_fixture).unwrap();
5454

55-
let res = expander.expand(macro_name, &fixture.subtree, None).unwrap();
55+
let res = expander.expand(macro_name, &fixture.into_subtree(), None).unwrap();
5656
assert_eq_text!(&expect.trim(), &format!("{:?}", res));
5757
}
5858

0 commit comments

Comments
 (0)