From ca023ba9b702ec9d453e917ffac54263ab4ef965 Mon Sep 17 00:00:00 2001 From: Marcus Klaas Date: Sat, 17 Oct 2015 15:56:53 +0200 Subject: [PATCH] Format some patterns --- src/expr.rs | 41 +++++++---------- src/items.rs | 65 ++++++++++++++------------- src/lib.rs | 25 ++++++++++- src/patterns.rs | 95 +++++++++++++++++++++++++++++++++++++++ src/types.rs | 28 ++---------- tests/source/match.rs | 1 + tests/source/pattern.rs | 14 ++++++ tests/source/type.rs | 1 + tests/target/expr.rs | 4 +- tests/target/hard-tabs.rs | 4 +- tests/target/match.rs | 12 ++++- tests/target/multiple.rs | 12 ++++- tests/target/pattern.rs | 16 +++++++ tests/target/type.rs | 6 ++- 14 files changed, 236 insertions(+), 88 deletions(-) create mode 100644 src/patterns.rs create mode 100644 tests/source/pattern.rs create mode 100644 tests/target/pattern.rs diff --git a/src/expr.rs b/src/expr.rs index 2deaed9609a..b69989aa761 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering; use std::borrow::Borrow; use std::mem::swap; -use Indent; +use {Indent, Spanned}; use rewrite::{Rewrite, RewriteContext}; use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic, DefinitiveListTactic, definitive_tactic, ListItem, format_fn_args}; @@ -76,7 +76,7 @@ impl Rewrite for ast::Expr { offset) } ast::Expr_::ExprTup(ref items) => { - rewrite_tuple_lit(context, items, self.span, width, offset) + rewrite_tuple(context, items, self.span, width, offset) } ast::Expr_::ExprWhile(ref cond, ref block, label) => { Loop::new_while(None, cond, block, label).rewrite(context, width, offset) @@ -479,13 +479,6 @@ impl Rewrite for ast::Block { } } -// FIXME(#18): implement pattern formatting -impl Rewrite for ast::Pat { - fn rewrite(&self, context: &RewriteContext, _: usize, _: Indent) -> Option { - Some(context.snippet(self.span)) - } -} - // Abstraction over for, while and loop expressions struct Loop<'a> { cond: Option<&'a ast::Expr>, @@ -849,11 +842,7 @@ impl Rewrite for ast::Arm { // 5 = ` => {` let pat_budget = try_opt!(width.checked_sub(5)); let pat_strs = try_opt!(pats.iter() - .map(|p| { - p.rewrite(context, - pat_budget, - offset.block_indent(context.config)) - }) + .map(|p| p.rewrite(context, pat_budget, offset)) .collect::>>()); let mut total_width = pat_strs.iter().fold(0, |a, p| a + p.len()); @@ -1187,7 +1176,9 @@ fn rewrite_call_inner(context: &RewriteContext, // Replace the stub with the full overflowing last argument if the rewrite // succeeded and its first line fits with the other arguments. match (overflow_last, tactic, placeholder) { - (true, DefinitiveListTactic::Horizontal, placeholder @ Some(..)) => { + (true, + DefinitiveListTactic::Horizontal, + placeholder @ Some(..)) => { item_vec[arg_count - 1].item = placeholder; } (true, _, _) => { @@ -1206,8 +1197,6 @@ fn rewrite_call_inner(context: &RewriteContext, config: context.config, }; - // format_fn_args(items, remaining_width, offset, context.config) - let list_str = match write_list(&item_vec, &fmt) { Some(str) => str, None => return Err(Ordering::Less), @@ -1382,12 +1371,14 @@ fn rewrite_field(context: &RewriteContext, expr.map(|s| format!("{}: {}", name, s)) } -fn rewrite_tuple_lit(context: &RewriteContext, - items: &[ptr::P], - span: Span, - width: usize, - offset: Indent) - -> Option { +pub fn rewrite_tuple<'a, R>(context: &RewriteContext, + items: &'a [ptr::P], + span: Span, + width: usize, + offset: Indent) + -> Option + where R: Rewrite + Spanned + 'a +{ debug!("rewrite_tuple_lit: width: {}, offset: {:?}", width, offset); let indent = offset + 1; // In case of length 1, need a trailing comma @@ -1400,8 +1391,8 @@ fn rewrite_tuple_lit(context: &RewriteContext, let items = itemize_list(context.codemap, items.iter(), ")", - |item| item.span.lo, - |item| item.span.hi, + |item| item.span().lo, + |item| item.span().hi, |item| { let inner_width = context.config.max_width - indent.width() - 1; item.rewrite(context, inner_width, indent) diff --git a/src/items.rs b/src/items.rs index 68715252ce9..6d486bbbe51 100644 --- a/src/items.rs +++ b/src/items.rs @@ -29,41 +29,16 @@ impl<'a> FmtVisitor<'a> { pub fn visit_let(&mut self, local: &ast::Local, span: Span) { self.format_missing_with_indent(span.lo); - // String that is placed within the assignment pattern and expression. - let infix = { - let mut infix = String::new(); - - if let Some(ref ty) = local.ty { - // 2 = ": ".len() - let offset = self.block_indent + 2; - let width = self.config.max_width - offset.width(); - let rewrite = ty.rewrite(&self.get_context(), width, offset); - - match rewrite { - Some(result) => { - infix.push_str(": "); - infix.push_str(&result); - } - None => return, - } - } - - if local.init.is_some() { - infix.push_str(" ="); - } - - infix - }; - // New scope so we drop the borrow of self (context) in time to mutably // borrow self to mutate its buffer. let result = { let context = self.get_context(); let mut result = "let ".to_owned(); - let pattern_offset = self.block_indent + result.len() + infix.len(); + let pattern_offset = self.block_indent + result.len(); // 1 = ; - let pattern_width = self.config.max_width.checked_sub(pattern_offset.width() + 1); - let pattern_width = match pattern_width { + let pattern_width = match self.config + .max_width + .checked_sub(pattern_offset.width() + 1) { Some(width) => width, None => return, }; @@ -73,6 +48,36 @@ impl<'a> FmtVisitor<'a> { None => return, } + // String that is placed within the assignment pattern and expression. + let infix = { + let mut infix = String::new(); + + if let Some(ref ty) = local.ty { + // 2 = ": ".len() + // 1 = ; + let offset = self.block_indent + result.len() + 2; + let width = match self.config.max_width.checked_sub(offset.width() + 1) { + Some(w) => w, + None => return, + }; + let rewrite = ty.rewrite(&self.get_context(), width, offset); + + match rewrite { + Some(result) => { + infix.push_str(": "); + infix.push_str(&result); + } + None => return, + } + } + + if local.init.is_some() { + infix.push_str(" ="); + } + + infix + }; + result.push_str(&infix); if let Some(ref ex) = local.init { @@ -86,7 +91,7 @@ impl<'a> FmtVisitor<'a> { let rhs = rewrite_assign_rhs(&context, result, ex, max_width, context.block_indent); match rhs { - Some(result) => result, + Some(s) => s, None => return, } } else { diff --git a/src/lib.rs b/src/lib.rs index 1dfb05c88b6..03422a20c36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,7 @@ use rustc::session::config::Input; use rustc_driver::{driver, CompilerCalls, Compilation}; use syntax::ast; -use syntax::codemap::CodeMap; +use syntax::codemap::{CodeMap, Span}; use syntax::diagnostics; use std::ops::{Add, Sub}; @@ -76,11 +76,34 @@ mod modules; pub mod rustfmt_diff; mod chains; mod macros; +mod patterns; const MIN_STRING: usize = 10; // When we get scoped annotations, we should have rustfmt::skip. const SKIP_ANNOTATION: &'static str = "rustfmt_skip"; +pub trait Spanned { + fn span(&self) -> Span; +} + +impl Spanned for ast::Expr { + fn span(&self) -> Span { + self.span + } +} + +impl Spanned for ast::Pat { + fn span(&self) -> Span { + self.span + } +} + +impl Spanned for ast::Ty { + fn span(&self) -> Span { + self.span + } +} + #[derive(Copy, Clone, Debug)] pub struct Indent { // Width of the block indent, in characters. Must be a multiple of diff --git a/src/patterns.rs b/src/patterns.rs new file mode 100644 index 00000000000..2e90f719853 --- /dev/null +++ b/src/patterns.rs @@ -0,0 +1,95 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use Indent; +use rewrite::{Rewrite, RewriteContext}; +use utils::{wrap_str, format_mutability, span_after}; +use lists::{format_item_list, itemize_list}; +use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple}; +use types::rewrite_path; + +use syntax::ast::{PatWildKind, BindingMode, Pat, Pat_}; + +// FIXME(#18): implement pattern formatting. +impl Rewrite for Pat { + fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + match self.node { + Pat_::PatBox(ref pat) => { + rewrite_unary_prefix(context, "box ", &**pat, width, offset) + } + Pat_::PatIdent(binding_mode, ident, None) => { + let (prefix, mutability) = match binding_mode { + BindingMode::BindByRef(mutability) => ("ref ", mutability), + BindingMode::BindByValue(mutability) => ("", mutability), + }; + let mut_infix = format_mutability(mutability); + let result = format!("{}{}{}", prefix, mut_infix, ident.node); + wrap_str(result, context.config.max_width, width, offset) + } + Pat_::PatWild(kind) => { + let result = match kind { + PatWildKind::PatWildSingle => "_", + PatWildKind::PatWildMulti => "..", + }; + if result.len() <= width { + Some(result.to_owned()) + } else { + None + } + } + Pat_::PatQPath(ref q_self, ref path) => { + rewrite_path(context, Some(q_self), path, width, offset) + } + Pat_::PatRange(ref lhs, ref rhs) => { + rewrite_pair(&**lhs, &**rhs, "", "...", "", context, width, offset) + } + Pat_::PatRegion(ref pat, mutability) => { + let prefix = format!("&{}", format_mutability(mutability)); + rewrite_unary_prefix(context, &prefix, &**pat, width, offset) + } + Pat_::PatTup(ref items) => { + rewrite_tuple(context, items, self.span, width, offset) + } + Pat_::PatEnum(ref path, Some(ref pat_vec)) => { + let path_str = try_opt!(::types::rewrite_path(context, None, path, width, offset)); + + if pat_vec.is_empty() { + Some(path_str) + } else { + let width = try_opt!(width.checked_sub(path_str.len())); + let offset = offset + path_str.len(); + let items = itemize_list(context.codemap, + pat_vec.iter(), + ")", + |item| item.span.lo, + |item| item.span.hi, + |item| item.rewrite(context, width, offset), + span_after(self.span, "(", context.codemap), + self.span.hi); + Some(format!("{}({})", + path_str, + try_opt!(format_item_list(items, width, offset, context.config)))) + } + } + Pat_::PatLit(ref expr) => expr.rewrite(context, width, offset), + // FIXME(#8): format remaining pattern variants. + Pat_::PatIdent(_, _, Some(..)) | + Pat_::PatEnum(_, None) | + Pat_::PatStruct(..) | + Pat_::PatVec(..) | + Pat_::PatMac(..) => { + wrap_str(context.snippet(self.span), + context.config.max_width, + width, + offset) + } + } + } +} diff --git a/src/types.rs b/src/types.rs index 14c0c2669a9..d8170e2f917 100644 --- a/src/types.rs +++ b/src/types.rs @@ -13,10 +13,10 @@ use syntax::print::pprust; use syntax::codemap::{self, Span, BytePos, CodeMap}; use Indent; -use lists::{format_item_list, itemize_list, format_fn_args, list_helper, ListTactic}; +use lists::{format_item_list, itemize_list, format_fn_args}; use rewrite::{Rewrite, RewriteContext}; use utils::{extra_offset, span_after, format_mutability, wrap_str}; -use expr::{rewrite_unary_prefix, rewrite_pair}; +use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple}; impl Rewrite for ast::Path { fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { @@ -491,28 +491,8 @@ impl Rewrite for ast::Ty { let budget = try_opt!(width.checked_sub(2)); ty.rewrite(context, budget, offset + 1).map(|ty_str| format!("[{}]", ty_str)) } - ast::TyTup(ref tup_ret) => { - if tup_ret.is_empty() { - Some("()".to_owned()) - } else if let [ref item] = &**tup_ret { - let budget = try_opt!(width.checked_sub(3)); - let inner = try_opt!(item.rewrite(context, budget, offset + 1)); - let ret = format!("({},)", inner); - wrap_str(ret, context.config.max_width, budget, offset + 1) - } else { - let budget = try_opt!(width.checked_sub(2)); - let items = itemize_list(context.codemap, - tup_ret.iter(), - ")", - |item| item.span.lo, - |item| item.span.hi, - |item| item.rewrite(context, budget, offset + 1), - span_after(self.span, "(", context.codemap), - self.span.hi); - - list_helper(items, budget, offset + 1, context.config, ListTactic::Mixed) - .map(|s| format!("({})", s)) - } + ast::TyTup(ref items) => { + rewrite_tuple(context, items, self.span, width, offset) } ast::TyPolyTraitRef(ref trait_ref) => trait_ref.rewrite(context, width, offset), ast::TyPath(ref q_self, ref path) => { diff --git a/tests/source/match.rs b/tests/source/match.rs index b1c6449226f..992d0d98bf8 100644 --- a/tests/source/match.rs +++ b/tests/source/match.rs @@ -88,6 +88,7 @@ fn main() { fn matches() { match 1 { + -1 => 10, 1 => 1, // foo 2 => 2, // bar diff --git a/tests/source/pattern.rs b/tests/source/pattern.rs new file mode 100644 index 00000000000..4192d521085 --- /dev/null +++ b/tests/source/pattern.rs @@ -0,0 +1,14 @@ +fn main() { + let z = match x { + "pat1" => 1, + ( ref x, ref mut y /*comment*/) => 2, + }; + + if let < T as Trait > :: CONST = ident { + do_smth(); + } + + let Some ( ref xyz /* comment! */) = opt; + + if let None = opt2 { panic!("oh noes"); } +} diff --git a/tests/source/type.rs b/tests/source/type.rs index 6059bc7a246..71822bd668d 100644 --- a/tests/source/type.rs +++ b/tests/source/type.rs @@ -2,4 +2,5 @@ fn types() { let x: [ Vec < _ > ] = []; let y: * mut [ SomeType ; konst_funk() ] = expr(); let z: (/*#digits*/ usize, /*exp*/ i16) = funk(); + let z: ( usize /*#digits*/ , i16 /*exp*/ ) = funk(); } diff --git a/tests/target/expr.rs b/tests/target/expr.rs index 555d8f37e01..479a279e43b 100644 --- a/tests/target/expr.rs +++ b/tests/target/expr.rs @@ -57,8 +57,8 @@ fn foo() -> bool { tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1111 + 2222 {} - if let (some_very_large, tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = - 1 + 2 + 3 { + if let (some_very_large, + tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1 + 2 + 3 { } let test = if true { diff --git a/tests/target/hard-tabs.rs b/tests/target/hard-tabs.rs index c101f0bbf3c..21155218111 100644 --- a/tests/target/hard-tabs.rs +++ b/tests/target/hard-tabs.rs @@ -28,8 +28,8 @@ fn main() { let str = "AAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAA\ AAAAAAAAAAAAaAa"; - if let (some_very_large, tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = - 1 + 2 + 3 { + if let (some_very_large, + tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1 + 2 + 3 { } if cond() { diff --git a/tests/target/match.rs b/tests/target/match.rs index fe833dffb62..6c498014aa1 100644 --- a/tests/target/match.rs +++ b/tests/target/match.rs @@ -32,7 +32,16 @@ fn foo() { meh, // Test that earlier patterns can take the guard space - (aaaa, bbbbb, ccccccc, aaaaa, bbbbbbbb, cccccc, aaaa, bbbbbbbb, cccccc, dddddd) | + (aaaa, + bbbbb, + ccccccc, + aaaaa, + bbbbbbbb, + cccccc, + aaaa, + bbbbbbbb, + cccccc, + dddddd) | Patternnnnnnnnnnnnnnnnnnnnnnnnn if loooooooooooooooooooooooooooooooooooooooooong_guard => {} _ => {} @@ -83,6 +92,7 @@ fn main() { fn matches() { match 1 { + -1 => 10, 1 => 1, // foo 2 => 2, // bar diff --git a/tests/target/multiple.rs b/tests/target/multiple.rs index d7f7a79f580..3c17eb77924 100644 --- a/tests/target/multiple.rs +++ b/tests/target/multiple.rs @@ -143,12 +143,20 @@ fn main() { } fn deconstruct() - -> (SocketAddr, Method, Headers, RequestUri, HttpVersion, + -> (SocketAddr, + Method, + Headers, + RequestUri, + HttpVersion, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) { } fn deconstruct(foo: Bar) - -> (SocketAddr, Method, Headers, RequestUri, HttpVersion, + -> (SocketAddr, + Method, + Headers, + RequestUri, + HttpVersion, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) { } diff --git a/tests/target/pattern.rs b/tests/target/pattern.rs new file mode 100644 index 00000000000..38ebe675a40 --- /dev/null +++ b/tests/target/pattern.rs @@ -0,0 +1,16 @@ +fn main() { + let z = match x { + "pat1" => 1, + (ref x, ref mut y /* comment */) => 2, + }; + + if let ::CONST = ident { + do_smth(); + } + + let Some(ref xyz /* comment! */) = opt; + + if let None = opt2 { + panic!("oh noes"); + } +} diff --git a/tests/target/type.rs b/tests/target/type.rs index afcf86123ae..a8a5e028aa5 100644 --- a/tests/target/type.rs +++ b/tests/target/type.rs @@ -1,5 +1,9 @@ fn types() { let x: [Vec<_>] = []; let y: *mut [SomeType; konst_funk()] = expr(); - let z: (/* #digits */ usize, /* exp */ i16) = funk(); + let z: (// #digits + usize, + // exp + i16) = funk(); + let z: (usize /* #digits */, i16 /* exp */) = funk(); }