Use a fixed-point iteration when breaking tokens
Some tokens need to be broken in a loop until we reach 'unbreakable' tokens.
This commit is contained in:
parent
9b2b8a5afa
commit
4a8ccdcc0b
@ -21,6 +21,8 @@
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use log::debug;
|
||||
|
||||
use std::{iter, mem};
|
||||
|
||||
/// When the main rust parser encounters a syntax-extension invocation, it
|
||||
@ -358,14 +360,47 @@ fn semantic_tree(tree: &TokenTree) -> bool {
|
||||
// leading to some tokens being 'glued' together in one stream but not
|
||||
// the other. See #68489 for more details.
|
||||
fn break_tokens(tree: TokenTree) -> impl Iterator<Item = TokenTree> {
|
||||
// In almost all cases, we should have either zero or one levels
|
||||
// of 'unglueing'. However, in some unusual cases, we may need
|
||||
// to iterate breaking tokens mutliple times. For example:
|
||||
// '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]'
|
||||
let mut token_trees: SmallVec<[_; 2]>;
|
||||
if let TokenTree::Token(token) = &tree {
|
||||
if let Some((first, second)) = token.kind.break_two_token_op() {
|
||||
return SmallVec::from_buf([TokenTree::Token(Token::new(first, DUMMY_SP)), TokenTree::Token(Token::new(second, DUMMY_SP))]).into_iter()
|
||||
let mut out = SmallVec::<[_; 2]>::new();
|
||||
out.push(token.clone());
|
||||
// Iterate to fixpoint:
|
||||
// * We start off with 'out' containing our initial token, and `temp` empty
|
||||
// * If we are able to break any tokens in `out`, then `out` will have
|
||||
// at least one more element than 'temp', so we will try to break tokens
|
||||
// again.
|
||||
// * If we cannot break any tokens in 'out', we are done
|
||||
loop {
|
||||
let mut temp = SmallVec::<[_; 2]>::new();
|
||||
let mut changed = false;
|
||||
|
||||
for token in out.into_iter() {
|
||||
if let Some((first, second)) = token.kind.break_two_token_op() {
|
||||
temp.push(Token::new(first, DUMMY_SP));
|
||||
temp.push(Token::new(second, DUMMY_SP));
|
||||
changed = true;
|
||||
} else {
|
||||
temp.push(token);
|
||||
}
|
||||
}
|
||||
out = temp;
|
||||
if !changed {
|
||||
break;
|
||||
}
|
||||
}
|
||||
token_trees = out.into_iter().map(|t| TokenTree::Token(t)).collect();
|
||||
if token_trees.len() != 1 {
|
||||
debug!("break_tokens: broke {:?} to {:?}", tree, token_trees);
|
||||
}
|
||||
} else {
|
||||
token_trees = SmallVec::new();
|
||||
token_trees.push(tree);
|
||||
}
|
||||
let mut vec = SmallVec::<[_; 2]>::new();
|
||||
vec.push(tree);
|
||||
vec.into_iter()
|
||||
token_trees.into_iter()
|
||||
}
|
||||
|
||||
let mut t1 = self.trees().filter(semantic_tree).flat_map(break_tokens);
|
||||
|
16
src/test/ui/proc-macro/break-token-spans.rs
Normal file
16
src/test/ui/proc-macro/break-token-spans.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// aux-build:test-macros.rs
|
||||
// Regression test for issues #68489 and #70987
|
||||
// Tests that we properly break tokens in `probably_equal_for_proc_macro`
|
||||
// See #72306
|
||||
//
|
||||
// Note that the weird spacing in this example is critical
|
||||
// for testing the issue.
|
||||
|
||||
extern crate test_macros;
|
||||
|
||||
#[test_macros::recollect_attr]
|
||||
fn repro() {
|
||||
f :: < Vec < _ > > ( ) ; //~ ERROR cannot find
|
||||
let a: Option<Option<u8>>= true; //~ ERROR mismatched
|
||||
}
|
||||
fn main() {}
|
21
src/test/ui/proc-macro/break-token-spans.stderr
Normal file
21
src/test/ui/proc-macro/break-token-spans.stderr
Normal file
@ -0,0 +1,21 @@
|
||||
error[E0425]: cannot find function `f` in this scope
|
||||
--> $DIR/break-token-spans.rs:13:5
|
||||
|
|
||||
LL | f :: < Vec < _ > > ( ) ;
|
||||
| ^ not found in this scope
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/break-token-spans.rs:14:32
|
||||
|
|
||||
LL | let a: Option<Option<u8>>= true;
|
||||
| ------------------ ^^^^ expected enum `std::option::Option`, found `bool`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected enum `std::option::Option<std::option::Option<u8>>`
|
||||
found type `bool`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0425.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
@ -1,9 +0,0 @@
|
||||
// aux-build:test-macros.rs
|
||||
|
||||
extern crate test_macros;
|
||||
|
||||
#[test_macros::recollect_attr]
|
||||
fn repro() {
|
||||
f :: < Vec < _ > > ( ) ; //~ ERROR cannot find
|
||||
}
|
||||
fn main() {}
|
@ -1,9 +0,0 @@
|
||||
error[E0425]: cannot find function `f` in this scope
|
||||
--> $DIR/turbo-proc-macro.rs:7:5
|
||||
|
|
||||
LL | f :: < Vec < _ > > ( ) ;
|
||||
| ^ not found in this scope
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
Loading…
Reference in New Issue
Block a user