Merge pull request #288 from marcusklaas/closure-return

Format closures' return types
This commit is contained in:
Nick Cameron 2015-09-09 09:14:15 +12:00
commit aa2abc63a0
4 changed files with 85 additions and 32 deletions

View File

@ -163,9 +163,12 @@ fn rewrite_closure(capture: ast::CaptureClause,
// 4 = "|| {".len(), which is overconservative when the closure consists of
// a single expression.
let argument_budget = try_opt!(width.checked_sub(4 + mover.len()));
let budget = try_opt!(width.checked_sub(4 + mover.len()));
// 1 = |
let argument_offset = offset + 1;
let ret_str = try_opt!(fn_decl.output.rewrite(context, budget, argument_offset));
// 1 = space between arguments and return type.
let horizontal_budget = budget.checked_sub(ret_str.len() + 1).unwrap_or(0);
let arg_items = itemize_list(context.codemap,
fn_decl.inputs.iter(),
@ -176,13 +179,37 @@ fn rewrite_closure(capture: ast::CaptureClause,
span_after(span, "|", context.codemap),
body.span.lo);
let fmt = ListFormatting::for_fn(argument_budget, argument_offset);
let fmt = ListFormatting {
tactic: ListTactic::HorizontalVertical,
separator: ",",
trailing_separator: SeparatorTactic::Never,
indent: argument_offset,
h_width: horizontal_budget,
v_width: budget,
ends_with_newline: false,
};
let list_str = try_opt!(write_list(&arg_items.collect::<Vec<_>>(), &fmt));
let prefix = format!("{}|{}|", mover, list_str);
let mut prefix = format!("{}|{}|", mover, list_str);
if !ret_str.is_empty() {
if prefix.contains('\n') {
prefix.push('\n');
prefix.push_str(&make_indent(argument_offset));
} else {
prefix.push(' ');
}
prefix.push_str(&ret_str);
}
let closure_indent = closure_indent(context, offset);
// Try to format closure body as a single line expression without braces.
if body.stmts.is_empty() {
if is_simple_block(body, context.codemap) && !prefix.contains('\n') {
let (spacer, closer) = if ret_str.is_empty() {
(" ", "")
} else {
(" { ", " }")
};
let expr = body.expr.as_ref().unwrap();
// All closure bodies are blocks in the eyes of the AST, but we may not
// want to unwrap them when they only contain a single expression.
@ -192,28 +219,31 @@ fn rewrite_closure(capture: ast::CaptureClause,
}
_ => expr,
};
// 1 = the separating space between arguments and the body.
let extra_offset = extra_offset(&prefix, offset) + 1;
let budget = try_opt!(width.checked_sub(extra_offset));
let extra_offset = extra_offset(&prefix, offset) + spacer.len();
let budget = try_opt!(width.checked_sub(extra_offset + closer.len()));
let rewrite = inner_expr.rewrite(context, budget, offset + extra_offset);
// Checks if rewrite succeeded and fits on a single line.
let accept_rewrite = rewrite.as_ref().map(|result| !result.contains('\n')).unwrap_or(false);
if accept_rewrite {
return Some(format!("{} {}", prefix, rewrite.unwrap()));
return Some(format!("{}{}{}{}", prefix, spacer, rewrite.unwrap(), closer));
}
}
// We couldn't format the closure body as a single line expression; fall
// back to block formatting.
let inner_context = context.overflow_context(closure_indent - context.block_indent);
let body_rewrite = if let ast::Expr_::ExprBlock(ref inner) = body.expr.as_ref().unwrap().node {
inner.rewrite(&inner_context, 0, 0)
} else {
body.rewrite(&inner_context, 0, 0)
};
let body_rewrite = body.expr
.as_ref()
.and_then(|body_expr| {
if let ast::Expr_::ExprBlock(ref inner) = body_expr.node {
Some(inner.rewrite(&inner_context, 2, 0))
} else {
None
}
})
.unwrap_or_else(|| body.rewrite(&inner_context, 2, 0));
Some(format!("{} {}", prefix, try_opt!(body_rewrite)))
}

View File

@ -17,7 +17,7 @@ use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
use expr::rewrite_assign_rhs;
use comment::FindUncommented;
use visitor::FmtVisitor;
use rewrite::Rewrite;
use rewrite::{Rewrite, RewriteContext};
use config::{Config, BlockIndentStyle, Density};
use syntax::{ast, abi};
@ -207,7 +207,8 @@ impl<'a> FmtVisitor<'a> {
generics_span));
result.push_str(&generics_str);
let ret_str = self.rewrite_return(&fd.output, indent);
let context = self.get_context();
let ret_str = fd.output.rewrite(&context, self.config.max_width - indent, indent).unwrap();
// Args.
let (one_line_budget, multi_line_budget, mut arg_indent) =
@ -902,14 +903,22 @@ impl<'a> FmtVisitor<'a> {
Some(format!(" where {}", preds_str))
}
}
}
fn rewrite_return(&self, ret: &ast::FunctionRetTy, indent: usize) -> String {
match *ret {
ast::FunctionRetTy::DefaultReturn(_) => String::new(),
ast::FunctionRetTy::NoReturn(_) => "-> !".to_owned(),
impl Rewrite for ast::FunctionRetTy {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
match *self {
ast::FunctionRetTy::DefaultReturn(_) => Some(String::new()),
ast::FunctionRetTy::NoReturn(_) => {
if width >= 4 {
Some("-> !".to_owned())
} else {
None
}
}
ast::FunctionRetTy::Return(ref ty) => {
let ctxt = &self.get_context();
format!("-> {}", ty.rewrite(ctxt, ctxt.config.max_width, indent).unwrap())
let inner_width = try_opt!(width.checked_sub(3));
ty.rewrite(context, inner_width, offset + 3).map(|r| format!("-> {}", r))
}
}
}

View File

@ -3,9 +3,6 @@
fn main() {
let square = ( |i: i32 | i * i );
let commented = |/* first */ a /*argument*/, /* second*/ b: WithType /* argument*/, /* ignored */ _ |
(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb);
let commented = |/* first */ a /*argument*/, /* second*/ b: WithType /* argument*/, /* ignored */ _ |
(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);
@ -28,12 +25,22 @@ fn main() {
let empty = |arg| {};
let simple = |arg| { /* TODO(#27): comment formatting */ foo(arg) };
let test = | | { do_something(); do_something_else(); };
let arg_test = |big_argument_name, test123| looooooooooooooooooong_function_naaaaaaaaaaaaaaaaame();
let arg_test = |big_argument_name, test123| {looooooooooooooooooong_function_naaaaaaaaaaaaaaaaame()};
let simple_closure = move || -> () {};
let closure = |input: Ty| -> Option<String> {
foo()
};
let closure_with_return_type = |aaaaaaaaaaaaaaaaaaaaaaarg1, aaaaaaaaaaaaaaaaaaaaaaarg2| -> Strong { "sup".to_owned() };
|arg1, arg2, _, _, arg3, arg4| { let temp = arg4 + arg3;
arg2 * arg1 - temp }
}

View File

@ -3,13 +3,6 @@
fn main() {
let square = (|i: i32| i * i);
let commented = |// first
a, // argument
// second
b: WithType, // argument
// ignored
_| (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb);
let commented = |// first
a, // argument
// second
@ -46,6 +39,10 @@ fn main() {
let empty = |arg| {};
let simple = |arg| { /* TODO(#27): comment formatting */
foo(arg)
};
let test = || {
do_something();
do_something_else();
@ -59,6 +56,16 @@ fn main() {
looooooooooooooooooong_function_naaaaaaaaaaaaaaaaame()
};
let simple_closure = move || -> () {};
let closure = |input: Ty| -> Option<String> { foo() };
let closure_with_return_type = |aaaaaaaaaaaaaaaaaaaaaaarg1,
aaaaaaaaaaaaaaaaaaaaaaarg2|
-> Strong {
"sup".to_owned()
};
|arg1, arg2, _, _, arg3, arg4| {
let temp = arg4 + arg3;
arg2 * arg1 - temp