Format some patterns

This commit is contained in:
Marcus Klaas 2015-10-17 15:56:53 +02:00
parent 8a9bbd9d7c
commit ca023ba9b7
14 changed files with 236 additions and 88 deletions

View File

@ -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<String> {
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::<Option<Vec<_>>>());
let mut total_width = pat_strs.iter().fold(0, |a, p| a + p.len());
@ -1187,7 +1176,9 @@ fn rewrite_call_inner<R>(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<R>(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<ast::Expr>],
span: Span,
width: usize,
offset: Indent)
-> Option<String> {
pub fn rewrite_tuple<'a, R>(context: &RewriteContext,
items: &'a [ptr::P<R>],
span: Span,
width: usize,
offset: Indent)
-> Option<String>
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)

View File

@ -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 {

View File

@ -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

95
src/patterns.rs Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<String> {
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)
}
}
}
}

View File

@ -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<String> {
@ -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) => {

View File

@ -88,6 +88,7 @@ fn main() {
fn matches() {
match 1 {
-1 => 10,
1 => 1, // foo
2 => 2,
// bar

14
tests/source/pattern.rs Normal file
View File

@ -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"); }
}

View File

@ -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();
}

View File

@ -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 {

View File

@ -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() {

View File

@ -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

View File

@ -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) {
}

16
tests/target/pattern.rs Normal file
View File

@ -0,0 +1,16 @@
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");
}
}

View File

@ -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();
}