Skip to content

Commit 5aff307

Browse files
committed
Auto merge of #55971 - SergioBenitez:skip-non-semantic, r=alexcrichton
Ignore non-semantic tokens for 'probably_eq' streams. Improves the situation in #43081 by skipping typically non-semantic tokens when checking for 'probably_eq'. r? @alexcrichton
2 parents 39852ca + 78eb516 commit 5aff307

File tree

5 files changed

+141
-6
lines changed

5 files changed

+141
-6
lines changed

src/libsyntax/parse/token.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,9 @@ impl Token {
570570
//
571571
// Instead the "probably equal" check here is "does each token
572572
// recursively have the same discriminant?" We basically don't look at
573-
// the token values here and assume that such fine grained modifications
574-
// of token streams doesn't happen.
573+
// the token values here and assume that such fine grained token stream
574+
// modifications, including adding/removing typically non-semantic
575+
// tokens such as extra braces and commas, don't happen.
575576
if let Some(tokens) = tokens {
576577
if tokens.probably_equal_for_proc_macro(&tokens_for_real) {
577578
return tokens

src/libsyntax/tokenstream.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use syntax_pos::{BytePos, Mark, Span, DUMMY_SP};
2626
use ext::base;
2727
use ext::tt::{macro_parser, quoted};
2828
use parse::Directory;
29-
use parse::token::{self, Token};
29+
use parse::token::{self, DelimToken, Token};
3030
use print::pprust;
3131
use serialize::{Decoder, Decodable, Encoder, Encodable};
3232
use util::RcVec;
@@ -38,7 +38,7 @@ use std::{fmt, iter, mem};
3838
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
3939
pub struct Delimited {
4040
/// The type of delimiter
41-
pub delim: token::DelimToken,
41+
pub delim: DelimToken,
4242
/// The delimited sequence of token trees
4343
pub tts: ThinTokenStream,
4444
}
@@ -368,8 +368,30 @@ impl TokenStream {
368368
// This is otherwise the same as `eq_unspanned`, only recursing with a
369369
// different method.
370370
pub fn probably_equal_for_proc_macro(&self, other: &TokenStream) -> bool {
371-
let mut t1 = self.trees();
372-
let mut t2 = other.trees();
371+
// When checking for `probably_eq`, we ignore certain tokens that aren't
372+
// preserved in the AST. Because they are not preserved, the pretty
373+
// printer arbitrarily adds or removes them when printing as token
374+
// streams, making a comparison between a token stream generated from an
375+
// AST and a token stream which was parsed into an AST more reliable.
376+
fn semantic_tree(tree: &TokenTree) -> bool {
377+
match tree {
378+
// The pretty printer tends to add trailing commas to
379+
// everything, and in particular, after struct fields.
380+
| TokenTree::Token(_, Token::Comma)
381+
// The pretty printer emits `NoDelim` as whitespace.
382+
| TokenTree::Token(_, Token::OpenDelim(DelimToken::NoDelim))
383+
| TokenTree::Token(_, Token::CloseDelim(DelimToken::NoDelim))
384+
// The pretty printer collapses many semicolons into one.
385+
| TokenTree::Token(_, Token::Semi)
386+
// The pretty printer collapses whitespace arbitrarily and can
387+
// introduce whitespace from `NoDelim`.
388+
| TokenTree::Token(_, Token::Whitespace) => false,
389+
_ => true
390+
}
391+
}
392+
393+
let mut t1 = self.trees().filter(semantic_tree);
394+
let mut t2 = other.trees().filter(semantic_tree);
373395
for (t1, t2) in t1.by_ref().zip(t2.by_ref()) {
374396
if !t1.probably_equal_for_proc_macro(&t2) {
375397
return false;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// no-prefer-dynamic
2+
3+
#![crate_type = "proc-macro"]
4+
5+
extern crate proc_macro;
6+
7+
use proc_macro::TokenStream;
8+
9+
#[proc_macro_attribute]
10+
pub fn foo(_: TokenStream, input: TokenStream) -> TokenStream {
11+
input.into_iter().collect()
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// aux-build:span-preservation.rs
2+
3+
// For each of these, we should get the appropriate type mismatch error message,
4+
// and the function should be echoed.
5+
6+
extern crate span_preservation as foo;
7+
8+
use foo::foo;
9+
10+
#[foo]
11+
fn a() {
12+
let x: usize = "hello";;;;;
13+
}
14+
15+
#[foo]
16+
fn b(x: Option<isize>) -> usize {
17+
match x {
18+
Some(x) => { return x },
19+
None => 10
20+
}
21+
}
22+
23+
#[foo]
24+
fn c() {
25+
struct Foo {
26+
a: usize
27+
}
28+
29+
struct Bar {
30+
a: usize,
31+
b: usize
32+
}
33+
34+
let x = Foo { a: 10isize };
35+
let y = Foo { a: 10, b: 10isize };
36+
}
37+
38+
// FIXME: This doesn't work at the moment. See the one below. The pretty-printer
39+
// injects a "C" between `extern` and `fn` which causes a "probably_eq"
40+
// `TokenStream` mismatch. The lack of `"C"` should be preserved in the AST.
41+
#[foo]
42+
extern fn bar() {
43+
0
44+
}
45+
46+
#[foo]
47+
extern "C" fn baz() {
48+
0
49+
}
50+
51+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
error[E0308]: mismatched types
2+
|
3+
= note: expected type `()`
4+
found type `{integer}`
5+
6+
error[E0308]: mismatched types
7+
--> $DIR/span-preservation.rs:12:20
8+
|
9+
LL | let x: usize = "hello";;;;;
10+
| ^^^^^^^ expected usize, found reference
11+
|
12+
= note: expected type `usize`
13+
found type `&'static str`
14+
15+
error[E0308]: mismatched types
16+
--> $DIR/span-preservation.rs:18:29
17+
|
18+
LL | Some(x) => { return x },
19+
| ^ expected usize, found isize
20+
21+
error[E0308]: mismatched types
22+
--> $DIR/span-preservation.rs:34:22
23+
|
24+
LL | let x = Foo { a: 10isize };
25+
| ^^^^^^^ expected usize, found isize
26+
27+
error[E0560]: struct `c::Foo` has no field named `b`
28+
--> $DIR/span-preservation.rs:35:26
29+
|
30+
LL | let y = Foo { a: 10, b: 10isize };
31+
| ^ `c::Foo` does not have this field
32+
|
33+
= note: available fields are: `a`
34+
35+
error[E0308]: mismatched types
36+
--> $DIR/span-preservation.rs:48:5
37+
|
38+
LL | extern "C" fn baz() {
39+
| - possibly return type missing here?
40+
LL | 0
41+
| ^ expected (), found integral variable
42+
|
43+
= note: expected type `()`
44+
found type `{integer}`
45+
46+
error: aborting due to 6 previous errors
47+
48+
Some errors occurred: E0308, E0560.
49+
For more information about an error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)