blob: d74d96d2066bdb498630eb3747ffa5abb13f29df [file] [log] [blame]
David Tolnayf83b6c92019-03-09 22:58:26 -08001#![cfg(not(syn_disable_nightly_tests))]
David Tolnayecd024d2018-07-21 09:07:56 -07002#![recursion_limit = "1024"]
Nika Layzella2a1a4a2017-11-19 11:33:17 -05003#![feature(rustc_private)]
4
Michael Layzell53fc31a2017-06-07 09:21:53 -04005//! The tests in this module do the following:
6//!
Haibo Huang4fbebf92020-05-26 17:08:50 -07007//! 1. Parse a given expression in both `syn` and `librustc`.
Michael Layzell53fc31a2017-06-07 09:21:53 -04008//! 2. Fold over the expression adding brackets around each subexpression (with
Haibo Huang4fbebf92020-05-26 17:08:50 -07009//! some complications - see the `syn_brackets` and `librustc_brackets`
Michael Layzell53fc31a2017-06-07 09:21:53 -040010//! methods).
11//! 3. Serialize the `syn` expression back into a string, and re-parse it with
Haibo Huang4fbebf92020-05-26 17:08:50 -070012//! `librustc`.
David Tolnay0ccb6d12018-08-14 22:43:00 -070013//! 4. Respan all of the expressions, replacing the spans with the default
14//! spans.
Michael Layzell53fc31a2017-06-07 09:21:53 -040015//! 5. Compare the expressions with one another, if they are not equal fail.
16
Chih-Hung Hsieh725b6ec2020-04-16 17:09:06 -070017extern crate rustc_ast;
David Tolnayc8659922018-08-14 22:40:50 -070018extern crate rustc_data_structures;
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -070019extern crate rustc_span;
Michael Layzell53fc31a2017-06-07 09:21:53 -040020
David Tolnaye9b448f2019-03-10 22:46:38 -070021use quote::quote;
David Tolnay51382052017-12-27 13:46:21 -050022use rayon::iter::{IntoParallelIterator, ParallelIterator};
David Tolnayd1c31cc2018-08-24 14:47:15 -040023use regex::Regex;
Chih-Hung Hsieh725b6ec2020-04-16 17:09:06 -070024use rustc_ast::ast;
25use rustc_ast::ptr::P;
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -070026use rustc_span::edition::Edition;
Igor Gnatenko951a52b2018-03-12 10:33:33 +010027use walkdir::{DirEntry, WalkDir};
David Tolnayee97dbf2017-11-19 14:24:38 -080028
29use std::fs::File;
30use std::io::Read;
David Tolnay3eaf7d82017-12-17 23:14:52 -080031use std::process;
David Tolnayee97dbf2017-11-19 14:24:38 -080032use std::sync::atomic::{AtomicUsize, Ordering};
Michael Layzell53fc31a2017-06-07 09:21:53 -040033
David Tolnayecd024d2018-07-21 09:07:56 -070034use common::eq::SpanlessEq;
35use common::parse;
Michael Layzell53fc31a2017-06-07 09:21:53 -040036
Michael Layzell53fc31a2017-06-07 09:21:53 -040037#[macro_use]
David Tolnaydd125562017-12-31 02:16:22 -050038mod macros;
39
40#[allow(dead_code)]
Michael Layzell53fc31a2017-06-07 09:21:53 -040041mod common;
42
David Tolnay4d156fd2019-06-30 11:54:14 -070043mod repo;
44
Michael Layzell53fc31a2017-06-07 09:21:53 -040045/// Test some pre-set expressions chosen by us.
46#[test]
47fn test_simple_precedence() {
48 const EXPRS: &[&str] = &[
49 "1 + 2 * 3 + 4",
50 "1 + 2 * ( 3 + 4 )",
51 "{ for i in r { } *some_ptr += 1; }",
52 "{ loop { break 5; } }",
53 "{ if true { () }.mthd() }",
Nika Layzell3aa0dc72017-12-04 13:41:28 -050054 "{ for i in unsafe { 20 } { } }",
Michael Layzell53fc31a2017-06-07 09:21:53 -040055 ];
56
57 let mut failed = 0;
58
59 for input in EXPRS {
60 let expr = if let Some(expr) = parse::syn_expr(input) {
61 expr
62 } else {
63 failed += 1;
64 continue;
65 };
66
Haibo Huang4fbebf92020-05-26 17:08:50 -070067 let pf = match test_expressions(Edition::Edition2018, vec![expr]) {
Michael Layzell53fc31a2017-06-07 09:21:53 -040068 (1, 0) => "passed",
69 (0, 1) => {
70 failed += 1;
71 "failed"
72 }
73 _ => unreachable!(),
74 };
75 errorf!("=== {}: {}\n", input, pf);
76 }
77
78 if failed > 0 {
79 panic!("Failed {} tests", failed);
80 }
81}
82
83/// Test expressions from rustc, like in `test_round_trip`.
84#[test]
85fn test_rustc_precedence() {
Haibo Huang548c6a32020-05-15 23:36:50 -070086 common::rayon_init();
David Tolnay4d156fd2019-06-30 11:54:14 -070087 repo::clone_rust();
Michael Layzell53fc31a2017-06-07 09:21:53 -040088 let abort_after = common::abort_after();
89 if abort_after == 0 {
90 panic!("Skipping all precedence tests");
91 }
92
David Tolnayee97dbf2017-11-19 14:24:38 -080093 let passed = AtomicUsize::new(0);
94 let failed = AtomicUsize::new(0);
Michael Layzell53fc31a2017-06-07 09:21:53 -040095
David Tolnayd1c31cc2018-08-24 14:47:15 -040096 // 2018 edition is hard
97 let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();
98
David Tolnayee97dbf2017-11-19 14:24:38 -080099 WalkDir::new("tests/rust")
Igor Gnatenko951a52b2018-03-12 10:33:33 +0100100 .sort_by(|a, b| a.file_name().cmp(b.file_name()))
David Tolnayee97dbf2017-11-19 14:24:38 -0800101 .into_iter()
David Tolnay4d156fd2019-06-30 11:54:14 -0700102 .filter_entry(repo::base_dir_filter)
David Tolnayee97dbf2017-11-19 14:24:38 -0800103 .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
104 .unwrap()
105 .into_par_iter()
David Tolnay51382052017-12-27 13:46:21 -0500106 .for_each(|entry| {
107 let path = entry.path();
108 if path.is_dir() {
109 return;
Michael Layzell53fc31a2017-06-07 09:21:53 -0400110 }
David Tolnay51382052017-12-27 13:46:21 -0500111
David Tolnay51382052017-12-27 13:46:21 -0500112 let mut file = File::open(path).unwrap();
113 let mut content = String::new();
114 file.read_to_string(&mut content).unwrap();
David Tolnayd1c31cc2018-08-24 14:47:15 -0400115 let content = edition_regex.replace_all(&content, "_$0");
Michael Layzell53fc31a2017-06-07 09:21:53 -0400116
David Tolnay51382052017-12-27 13:46:21 -0500117 let (l_passed, l_failed) = match syn::parse_file(&content) {
118 Ok(file) => {
Haibo Huang4fbebf92020-05-26 17:08:50 -0700119 let edition = repo::edition(path).parse().unwrap();
David Tolnay51382052017-12-27 13:46:21 -0500120 let exprs = collect_exprs(file);
Haibo Huang4fbebf92020-05-26 17:08:50 -0700121 test_expressions(edition, exprs)
David Tolnay51382052017-12-27 13:46:21 -0500122 }
123 Err(msg) => {
124 errorf!("syn failed to parse\n{:?}\n", msg);
125 (0, 1)
126 }
127 };
David Tolnayee97dbf2017-11-19 14:24:38 -0800128
David Tolnay51382052017-12-27 13:46:21 -0500129 errorf!(
130 "=== {}: {} passed | {} failed\n",
131 path.display(),
132 l_passed,
133 l_failed
134 );
135
136 passed.fetch_add(l_passed, Ordering::SeqCst);
137 let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);
138
139 if prev_failed + l_failed >= abort_after {
140 process::exit(1);
141 }
142 });
David Tolnayee97dbf2017-11-19 14:24:38 -0800143
144 let passed = passed.load(Ordering::SeqCst);
145 let failed = failed.load(Ordering::SeqCst);
Michael Layzell53fc31a2017-06-07 09:21:53 -0400146
147 errorf!("\n===== Precedence Test Results =====\n");
148 errorf!("{} passed | {} failed\n", passed, failed);
149
Michael Layzell53fc31a2017-06-07 09:21:53 -0400150 if failed > 0 {
151 panic!("{} failures", failed);
152 }
153}
154
Haibo Huang4fbebf92020-05-26 17:08:50 -0700155fn test_expressions(edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) {
Michael Layzell53fc31a2017-06-07 09:21:53 -0400156 let mut passed = 0;
157 let mut failed = 0;
158
Haibo Huangc7557ca2020-07-20 17:20:33 -0700159 rustc_ast::with_session_globals(edition, || {
David Tolnayeb7d79b2018-03-31 22:52:17 +0200160 for expr in exprs {
161 let raw = quote!(#expr).to_string();
Michael Layzell53fc31a2017-06-07 09:21:53 -0400162
Haibo Huang4fbebf92020-05-26 17:08:50 -0700163 let librustc_ast = if let Some(e) = librustc_parse_and_rewrite(&raw) {
David Tolnayeb7d79b2018-03-31 22:52:17 +0200164 e
165 } else {
166 failed += 1;
Haibo Huang4fbebf92020-05-26 17:08:50 -0700167 errorf!("\nFAIL - librustc failed to parse raw\n");
David Tolnayeb7d79b2018-03-31 22:52:17 +0200168 continue;
169 };
Michael Layzell53fc31a2017-06-07 09:21:53 -0400170
David Tolnayeb7d79b2018-03-31 22:52:17 +0200171 let syn_expr = syn_brackets(expr);
Haibo Huang4fbebf92020-05-26 17:08:50 -0700172 let syn_ast = if let Some(e) = parse::librustc_expr(&quote!(#syn_expr).to_string()) {
David Tolnayeb7d79b2018-03-31 22:52:17 +0200173 e
174 } else {
175 failed += 1;
Haibo Huang4fbebf92020-05-26 17:08:50 -0700176 errorf!("\nFAIL - librustc failed to parse bracketed\n");
David Tolnayeb7d79b2018-03-31 22:52:17 +0200177 continue;
178 };
Michael Layzell53fc31a2017-06-07 09:21:53 -0400179
Haibo Huang4fbebf92020-05-26 17:08:50 -0700180 if SpanlessEq::eq(&syn_ast, &librustc_ast) {
David Tolnayeb7d79b2018-03-31 22:52:17 +0200181 passed += 1;
182 } else {
183 failed += 1;
Haibo Huang4fbebf92020-05-26 17:08:50 -0700184 errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, librustc_ast);
David Tolnayeb7d79b2018-03-31 22:52:17 +0200185 }
Michael Layzell53fc31a2017-06-07 09:21:53 -0400186 }
David Tolnay5d1a3ee2018-03-17 19:41:36 -0700187 });
Michael Layzell53fc31a2017-06-07 09:21:53 -0400188
189 (passed, failed)
190}
191
Haibo Huang4fbebf92020-05-26 17:08:50 -0700192fn librustc_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
193 parse::librustc_expr(input).and_then(librustc_brackets)
Michael Layzell53fc31a2017-06-07 09:21:53 -0400194}
195
196/// Wrap every expression which is not already wrapped in parens with parens, to
David Tolnay0ccb6d12018-08-14 22:43:00 -0700197/// reveal the precidence of the parsed expressions, and produce a stringified
198/// form of the resulting expression.
Michael Layzell53fc31a2017-06-07 09:21:53 -0400199///
Haibo Huang4fbebf92020-05-26 17:08:50 -0700200/// This method operates on librustc objects.
201fn librustc_brackets(mut librustc_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
Chih-Hung Hsieh725b6ec2020-04-16 17:09:06 -0700202 use rustc_ast::ast::{
Haibo Huang4fbebf92020-05-26 17:08:50 -0700203 Block, BorrowKind, Expr, ExprKind, Field, GenericArg, MacCall, Pat, Stmt, StmtKind, Ty,
Chih-Hung Hsieh725b6ec2020-04-16 17:09:06 -0700204 };
Haibo Huang4fbebf92020-05-26 17:08:50 -0700205 use rustc_ast::mut_visit::{noop_visit_generic_arg, MutVisitor};
Haibo Huang3588bff2020-04-23 15:44:10 -0700206 use rustc_data_structures::map_in_place::MapInPlace;
David Tolnayc8659922018-08-14 22:40:50 -0700207 use rustc_data_structures::thin_vec::ThinVec;
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -0700208 use rustc_span::DUMMY_SP;
David Tolnay176838f2019-02-07 17:28:37 +0100209 use std::mem;
Michael Layzell53fc31a2017-06-07 09:21:53 -0400210
David Tolnay176838f2019-02-07 17:28:37 +0100211 struct BracketsVisitor {
Michael Layzell53fc31a2017-06-07 09:21:53 -0400212 failed: bool,
213 };
David Tolnaye6b37092019-05-08 18:29:54 -0700214
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -0700215 fn flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> Vec<Field> {
216 if f.is_shorthand {
217 noop_visit_expr(&mut f.expr, vis);
218 } else {
219 vis.visit_expr(&mut f.expr);
220 }
221 vec![f]
222 }
223
224 fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
225 let kind = match stmt.kind {
226 // Don't wrap toplevel expressions in statements.
227 StmtKind::Expr(mut e) => {
228 noop_visit_expr(&mut e, vis);
229 StmtKind::Expr(e)
230 }
231 StmtKind::Semi(mut e) => {
232 noop_visit_expr(&mut e, vis);
233 StmtKind::Semi(e)
234 }
235 s => s,
236 };
237
238 vec![Stmt { kind, ..stmt }]
239 }
240
241 fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
Chih-Hung Hsieh725b6ec2020-04-16 17:09:06 -0700242 use rustc_ast::mut_visit::{noop_visit_expr, visit_opt, visit_thin_attrs};
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -0700243 match &mut e.kind {
244 ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
245 ExprKind::Struct(path, fields, expr) => {
246 vis.visit_path(path);
247 fields.flat_map_in_place(|field| flat_map_field(field, vis));
248 visit_opt(expr, |expr| vis.visit_expr(expr));
249 vis.visit_id(&mut e.id);
250 vis.visit_span(&mut e.span);
251 visit_thin_attrs(&mut e.attrs, vis);
252 }
253 _ => noop_visit_expr(e, vis),
254 }
255 }
256
David Tolnay176838f2019-02-07 17:28:37 +0100257 impl MutVisitor for BracketsVisitor {
258 fn visit_expr(&mut self, e: &mut P<Expr>) {
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -0700259 noop_visit_expr(e, self);
260 match e.kind {
David Tolnayc992d702019-06-23 18:48:23 -0700261 ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
David Tolnay176838f2019-02-07 17:28:37 +0100262 _ => {
263 let inner = mem::replace(
264 e,
265 P(Expr {
266 id: ast::DUMMY_NODE_ID,
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -0700267 kind: ExprKind::Err,
David Tolnay176838f2019-02-07 17:28:37 +0100268 span: DUMMY_SP,
269 attrs: ThinVec::new(),
Haibo Huang4fbebf92020-05-26 17:08:50 -0700270 tokens: None,
David Tolnay176838f2019-02-07 17:28:37 +0100271 }),
272 );
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -0700273 e.kind = ExprKind::Paren(inner);
David Tolnay5d314dc2018-07-21 16:40:01 -0700274 }
David Tolnay176838f2019-02-07 17:28:37 +0100275 }
Michael Layzell53fc31a2017-06-07 09:21:53 -0400276 }
277
Haibo Huang4fbebf92020-05-26 17:08:50 -0700278 fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
279 match arg {
280 // Don't wrap const generic arg as that's invalid syntax.
281 GenericArg::Const(arg) => noop_visit_expr(&mut arg.value, self),
282 _ => noop_visit_generic_arg(arg, self),
283 }
284 }
285
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -0700286 fn visit_block(&mut self, block: &mut P<Block>) {
287 self.visit_id(&mut block.id);
288 block
289 .stmts
290 .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
291 self.visit_span(&mut block.span);
Michael Layzell53fc31a2017-06-07 09:21:53 -0400292 }
293
294 // We don't want to look at expressions that might appear in patterns or
295 // types yet. We'll look into comparing those in the future. For now
296 // focus on expressions appearing in other places.
David Tolnay176838f2019-02-07 17:28:37 +0100297 fn visit_pat(&mut self, pat: &mut P<Pat>) {
298 let _ = pat;
Michael Layzell53fc31a2017-06-07 09:21:53 -0400299 }
300
David Tolnay176838f2019-02-07 17:28:37 +0100301 fn visit_ty(&mut self, ty: &mut P<Ty>) {
302 let _ = ty;
Michael Layzell53fc31a2017-06-07 09:21:53 -0400303 }
304
Chih-Hung Hsieh725b6ec2020-04-16 17:09:06 -0700305 fn visit_mac(&mut self, mac: &mut MacCall) {
Haibo Huang4fbebf92020-05-26 17:08:50 -0700306 // By default when folding over macros, librustc panics. This is
Michael Layzell53fc31a2017-06-07 09:21:53 -0400307 // because it's usually not what you want, you want to run after
308 // macro expansion. We do want to do that (syn doesn't do macro
David Tolnay176838f2019-02-07 17:28:37 +0100309 // expansion), so we implement visit_mac to just return the macro
Michael Layzell53fc31a2017-06-07 09:21:53 -0400310 // unchanged.
David Tolnay176838f2019-02-07 17:28:37 +0100311 let _ = mac;
Michael Layzell53fc31a2017-06-07 09:21:53 -0400312 }
313 }
314
David Tolnay176838f2019-02-07 17:28:37 +0100315 let mut folder = BracketsVisitor { failed: false };
Haibo Huang4fbebf92020-05-26 17:08:50 -0700316 folder.visit_expr(&mut librustc_expr);
Michael Layzell53fc31a2017-06-07 09:21:53 -0400317 if folder.failed {
318 None
319 } else {
Haibo Huang4fbebf92020-05-26 17:08:50 -0700320 Some(librustc_expr)
Michael Layzell53fc31a2017-06-07 09:21:53 -0400321 }
322}
323
324/// Wrap every expression which is not already wrapped in parens with parens, to
David Tolnay0ccb6d12018-08-14 22:43:00 -0700325/// reveal the precedence of the parsed expressions, and produce a stringified
326/// form of the resulting expression.
Michael Layzell53fc31a2017-06-07 09:21:53 -0400327fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
Michael Layzell53fc31a2017-06-07 09:21:53 -0400328 use syn::fold::*;
David Tolnayeb7d79b2018-03-31 22:52:17 +0200329 use syn::*;
Michael Layzell53fc31a2017-06-07 09:21:53 -0400330
David Tolnayeb752062018-01-06 13:51:42 -0800331 struct ParenthesizeEveryExpr;
332 impl Fold for ParenthesizeEveryExpr {
Michael Layzell53fc31a2017-06-07 09:21:53 -0400333 fn fold_expr(&mut self, expr: Expr) -> Expr {
David Tolnay8c91b882017-12-28 23:04:32 -0500334 match expr {
335 Expr::Group(_) => unreachable!(),
David Tolnay9c119122018-09-01 18:47:02 -0700336 Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
David Tolnay3bc597f2017-12-31 02:31:11 -0500337 fold_expr(self, expr)
Michael Layzell53fc31a2017-06-07 09:21:53 -0400338 }
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -0700339 _ => Expr::Paren(ExprParen {
David Tolnay5d314dc2018-07-21 16:40:01 -0700340 attrs: Vec::new(),
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -0700341 expr: Box::new(fold_expr(self, expr)),
David Tolnay5d314dc2018-07-21 16:40:01 -0700342 paren_token: token::Paren::default(),
343 }),
David Tolnay8c91b882017-12-28 23:04:32 -0500344 }
Michael Layzell53fc31a2017-06-07 09:21:53 -0400345 }
346
Haibo Huang4fbebf92020-05-26 17:08:50 -0700347 fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument {
348 match arg {
349 // Don't wrap const generic arg as that's invalid syntax.
350 GenericArgument::Const(a) => GenericArgument::Const(fold_expr(self, a)),
351 _ => fold_generic_argument(self, arg),
352 }
353 }
354
Michael Layzell53fc31a2017-06-07 09:21:53 -0400355 fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
356 match stmt {
357 // Don't wrap toplevel expressions in statements.
David Tolnay1f0b7b82018-01-06 16:07:14 -0800358 Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
359 Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
Michael Layzell53fc31a2017-06-07 09:21:53 -0400360 s => s,
361 }
362 }
363
364 // We don't want to look at expressions that might appear in patterns or
365 // types yet. We'll look into comparing those in the future. For now
366 // focus on expressions appearing in other places.
367 fn fold_pat(&mut self, pat: Pat) -> Pat {
368 pat
369 }
370
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800371 fn fold_type(&mut self, ty: Type) -> Type {
Michael Layzell53fc31a2017-06-07 09:21:53 -0400372 ty
373 }
374 }
375
David Tolnayeb752062018-01-06 13:51:42 -0800376 let mut folder = ParenthesizeEveryExpr;
Michael Layzell53fc31a2017-06-07 09:21:53 -0400377 folder.fold_expr(syn_expr)
378}
379
380/// Walk through a crate collecting all expressions we can find in it.
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700381fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
Michael Layzell53fc31a2017-06-07 09:21:53 -0400382 use syn::fold::*;
David Tolnayf2cfd722017-12-31 18:02:51 -0500383 use syn::punctuated::Punctuated;
David Tolnayeb7d79b2018-03-31 22:52:17 +0200384 use syn::*;
Michael Layzell53fc31a2017-06-07 09:21:53 -0400385
David Tolnayeb752062018-01-06 13:51:42 -0800386 struct CollectExprs(Vec<Expr>);
387 impl Fold for CollectExprs {
Michael Layzell53fc31a2017-06-07 09:21:53 -0400388 fn fold_expr(&mut self, expr: Expr) -> Expr {
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -0700389 match expr {
390 Expr::Verbatim(tokens) if tokens.is_empty() => {}
391 _ => self.0.push(expr),
392 }
Michael Layzell53fc31a2017-06-07 09:21:53 -0400393
David Tolnay8c91b882017-12-28 23:04:32 -0500394 Expr::Tuple(ExprTuple {
Michael Layzell53fc31a2017-06-07 09:21:53 -0400395 attrs: vec![],
David Tolnayf2cfd722017-12-31 18:02:51 -0500396 elems: Punctuated::new(),
David Tolnay8c91b882017-12-28 23:04:32 -0500397 paren_token: token::Paren::default(),
398 })
Michael Layzell53fc31a2017-06-07 09:21:53 -0400399 }
400 }
401
David Tolnayeb752062018-01-06 13:51:42 -0800402 let mut folder = CollectExprs(vec![]);
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700403 folder.fold_file(file);
Michael Layzell53fc31a2017-06-07 09:21:53 -0400404 folder.0
405}