With an input file like
#![feature(underscore_imports)]
use std::iter::Iterator as _;
fn main() {}
running rustfmt on it produces
#![feature(underscore_imports)]
use std::iter::Iterator as ;
fn main() {}
Version:
rustfmt 0.9.0-nightly (69ad879d 2018-07-27)
Tracking issue for the unstable feature: https://github.com/rust-lang/rust/issues/48216
cc @max-sixty the universe provides! This would be a great issue to start on. Look in imports.rs and look for the code dealing with aliasing. You'll want to look at libsyntax/ast.rs in the rust repo to find out how the underscore is represented, and then take that into account in the rustfmt code.
(FYI I had a look at this over the weekend. It was a steeper learning curve than I had thought, but I'll give it another try)
What's the easiest way for me to discover how ast parses the _? I'm struggling to even view the output of a string of code. I've read the docs but let me know if I'm missing something obvious. Thanks
@max-sixty I would run rustfmt on a very simple program using _ and then dump the entire AST (println). For the code, I would look at token.rs in the compiler - iirc, _ vs other identifiers is handled during lexing, not parsing (it's been a while though, I might be wrong).
For the sake of progress - and feedback if I'm doing something bad, I ran this file:
// #![allow(unused_variables)]
// #![allow(unused_imports)]
extern crate syntax;
use std::path::PathBuf;
use syntax::with_globals;
use syntax::codemap::FilePathMapping;
use syntax::parse::{filemap_to_stream, ParseSess};
fn main() {
let parse_session = ParseSess::new(FilePathMapping::empty());
// let p = Path::new(file!());
// let string = "use std::iter::Iterator as _;".to_string();
with_globals(|| {
let stream = filemap_to_stream(
&parse_session,
parse_session
.codemap()
.new_filemap(PathBuf::from("").into(), "use a::b as _".to_string()),
None,
);
println!("{:?}", stream)
});
}
...which generated this output:
TokenStream { kind: Stream([TokenStream { kind: Tree(Token(Span { lo: BytePos(0), hi: BytePos(3), ctxt: #0 }, Ident(use#0, false))) }, TokenStream { kind: JointTree(Token(Span { lo: BytePos(4), hi: BytePos(5), ctxt: #0 }, Ident(a#0, false))) }, TokenStream { kind: Tree(Token(Span { lo: BytePos(5), hi: BytePos(7), ctxt: #0 }, ModSep)) }, TokenStream { kind: Tree(Token(Span { lo: BytePos(7), hi: BytePos(8), ctxt: #0 }, Ident(b#0, false))) }, TokenStream { kind: Tree(Token(Span { lo: BytePos(9), hi: BytePos(11), ctxt: #0 }, Ident(as#0, false))) }, TokenStream { kind: Tree(Token(Span { lo: BytePos(12), hi: BytePos(13), ctxt: #0 }, Ident(_#0, false))) }]) }
...suggesting that _ is parsed as Ident(_#0, false)
Reading through the code, my hypothesis is this section is passing an empty ident as an alias.
https://github.com/rust-lang-nursery/rustfmt/blob/master/src/imports.rs#L352-L357
I'm not sure how to debug this though. Let me know if you have any guidance from here!
I would look at rewrite_ident - I think it might be formatting _ as ``. Probably insert some printlns to confirm.
Most helpful comment
(FYI I had a look at this over the weekend. It was a steeper learning curve than I had thought, but I'll give it another try)