mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Fix TokenStream::from_str for input consisting of a single Group
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. In this case, wrap an extra level of Subtree around it. Fixes #7810 Fixes #7875
This commit is contained in:
parent
750d3cb846
commit
632fa8ef4a
1 changed files with 34 additions and 2 deletions
|
@ -34,8 +34,17 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_subtree(subtree: tt::Subtree) -> Self {
|
pub fn with_subtree(subtree: tt::Subtree) -> Self {
|
||||||
|
if subtree.delimiter.is_some() {
|
||||||
|
TokenStream {
|
||||||
|
subtree: tt::Subtree {
|
||||||
|
token_trees: vec![TokenTree::Subtree(subtree)],
|
||||||
|
delimiter: None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
TokenStream { subtree }
|
TokenStream { subtree }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.subtree.token_trees.is_empty()
|
self.subtree.token_trees.is_empty()
|
||||||
|
@ -185,7 +194,7 @@ pub mod token_stream {
|
||||||
mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
|
mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
|
||||||
|
|
||||||
let subtree = subtree_replace_token_ids_with_unspecified(subtree);
|
let subtree = subtree_replace_token_ids_with_unspecified(subtree);
|
||||||
Ok(TokenStream { subtree })
|
Ok(TokenStream::with_subtree(subtree))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,4 +788,27 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(s.to_string(), "struct T {}");
|
assert_eq!(s.to_string(), "struct T {}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rustc_server_from_str() {
|
||||||
|
use std::str::FromStr;
|
||||||
|
let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
|
||||||
|
delimiter: Some(tt::Delimiter {
|
||||||
|
id: tt::TokenId::unspecified(),
|
||||||
|
kind: tt::DelimiterKind::Parenthesis,
|
||||||
|
}),
|
||||||
|
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
|
text: "a".into(),
|
||||||
|
id: tt::TokenId::unspecified(),
|
||||||
|
}))],
|
||||||
|
});
|
||||||
|
|
||||||
|
let t1 = TokenStream::from_str("(a)").unwrap();
|
||||||
|
assert_eq!(t1.subtree.token_trees.len(), 1);
|
||||||
|
assert_eq!(t1.subtree.token_trees[0], subtree_paren_a);
|
||||||
|
|
||||||
|
let t2 = TokenStream::from_str("(a);").unwrap();
|
||||||
|
assert_eq!(t2.subtree.token_trees.len(), 2);
|
||||||
|
assert_eq!(t2.subtree.token_trees[0], subtree_paren_a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue