Auto merge of #16061 - Veykril:vec-completion, r=Veykril

fix: Fix fragment parser replacing matches with dummies on incomplete parses

Notably, this caused some completions in the `vec!` macro to no longer work. Fixes https://github.com/rust-lang/rust-analyzer/issues/15016
This commit is contained in:
bors 2023-12-13 09:59:13 +00:00
commit 94af6c63b7
2 changed files with 82 additions and 25 deletions

View file

@ -13,37 +13,97 @@ fn test_vec() {
check( check(
r#" r#"
macro_rules! vec { macro_rules! vec {
($($item:expr),*) => {{ () => (
let mut v = Vec::new(); $crate::__rust_force_expr!($crate::vec::Vec::new())
$( v.push($item); )* );
v ($elem:expr; $n:expr) => (
}}; $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
);
($($x:expr),+ $(,)?) => (
$crate::__rust_force_expr!(<[_]>::into_vec(
// This rustc_box is not required, but it produces a dramatic improvement in compile
// time when constructing arrays with many elements.
#[rustc_box]
$crate::boxed::Box::new([$($x),+])
))
);
} }
macro_rules! __rust_force_expr {
($e:expr) => {
$e
};
}
fn main() { fn main() {
vec!(); vec!();
vec![1u32,2]; vec![1u32,2];
vec![a.];
} }
"#, "#,
expect![[r#" expect![[r#"
macro_rules! vec { macro_rules! vec {
($($item:expr),*) => {{ () => (
let mut v = Vec::new(); $crate::__rust_force_expr!($crate::vec::Vec::new())
$( v.push($item); )* );
v ($elem:expr; $n:expr) => (
}}; $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
);
($($x:expr),+ $(,)?) => (
$crate::__rust_force_expr!(<[_]>::into_vec(
// This rustc_box is not required, but it produces a dramatic improvement in compile
// time when constructing arrays with many elements.
#[rustc_box]
$crate::boxed::Box::new([$($x),+])
))
);
} }
macro_rules! __rust_force_expr {
($e:expr) => {
$e
};
}
fn main() { fn main() {
{ $crate::__rust_force_expr!($crate:: vec:: Vec:: new());
let mut v = Vec::new(); $crate::__rust_force_expr!(<[_]>:: into_vec(#[rustc_box]$crate:: boxed:: Box:: new([1u32, 2])));
v /* error: expected Expr */$crate::__rust_force_expr!($crate:: vec:: from_elem((a.), $n));
}
"#]],
);
// FIXME we should ahev testing infra for multi level expansion tests
check(
r#"
macro_rules! __rust_force_expr {
($e:expr) => {
$e
}; };
{ }
let mut v = Vec::new();
v.push(1u32); fn main() {
v.push(2); __rust_force_expr!(crate:: vec:: Vec:: new());
v __rust_force_expr!(<[_]>:: into_vec(#[rustc_box] crate:: boxed:: Box:: new([1u32, 2])));
__rust_force_expr/*+errors*/!(crate:: vec:: from_elem((a.), $n));
}
"#,
expect![[r#"
macro_rules! __rust_force_expr {
($e:expr) => {
$e
}; };
} }
fn main() {
(crate ::vec::Vec::new());
(<[_]>::into_vec(#[rustc_box] crate ::boxed::Box::new([1u32, 2])));
/* error: expected Expr *//* parse error: expected field name or number */
/* parse error: expected expression */
/* parse error: expected R_PAREN */
/* parse error: expected COMMA */
/* parse error: expected expression, item or let statement */
(crate ::vec::from_elem((a.), $n));
}
"#]], "#]],
); );
} }

View file

@ -131,7 +131,6 @@ impl<'a, S: Span> TtIter<'a, S> {
let buffer = tt::buffer::TokenBuffer::from_tokens(self.inner.as_slice()); let buffer = tt::buffer::TokenBuffer::from_tokens(self.inner.as_slice());
let parser_input = to_parser_input(&buffer); let parser_input = to_parser_input(&buffer);
let tree_traversal = entry_point.parse(&parser_input); let tree_traversal = entry_point.parse(&parser_input);
let mut cursor = buffer.begin(); let mut cursor = buffer.begin();
let mut error = false; let mut error = false;
for step in tree_traversal.iter() { for step in tree_traversal.iter() {
@ -163,13 +162,11 @@ impl<'a, S: Span> TtIter<'a, S> {
let mut curr = buffer.begin(); let mut curr = buffer.begin();
let mut res = vec![]; let mut res = vec![];
if cursor.is_root() {
while curr != cursor { while curr != cursor {
let Some(token) = curr.token_tree() else { break }; let Some(token) = curr.token_tree() else { break };
res.push(token.cloned()); res.push(token.cloned());
curr = curr.bump(); curr = curr.bump();
} }
}
self.inner = self.inner.as_slice()[res.len()..].iter(); self.inner = self.inner.as_slice()[res.len()..].iter();
let res = match res.len() { let res = match res.len() {