Skip to content

Format some patterns #484

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 19, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 16 additions & 25 deletions src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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, _, _) => {
Expand All @@ -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),
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down
65 changes: 35 additions & 30 deletions src/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
25 changes: 24 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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
Expand Down
95 changes: 95 additions & 0 deletions src/patterns.rs
Original file line number Diff line number Diff line change
@@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need &** here and elsewhere? Do we not get auto-defered?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just curious, no action required

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not. This is because rewrite_pair takes &Rewrite, I think. If it took for example &ast::Expr, then it would auto-deref.

}
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)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these all intended to remain like this or left for future implementation? Or do they also require #29120?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment would be good here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left for future implementation; I'll add a comment.

}
}
}
28 changes: 4 additions & 24 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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) => {
Expand Down
1 change: 1 addition & 0 deletions tests/source/match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ fn main() {

fn matches() {
match 1 {
-1 => 10,
1 => 1, // foo
2 => 2,
// bar
Expand Down
14 changes: 14 additions & 0 deletions tests/source/pattern.rs
Original file line number Diff line number Diff line change
@@ -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"); }
}
Loading