X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclosures.rs;h=fa656cc351eea68c857d6bbe8ce99cdd3acaa384;hb=cbd568083d87a90dfe5ab0e90f404454946c9f20;hp=b9009598f1a527527a32d472ddacbc203c163c7b;hpb=7d63490d8573eca400260f836ae6a75555620b4f;p=rust.git diff --git a/src/closures.rs b/src/closures.rs index b9009598f1a..fa656cc351e 100644 --- a/src/closures.rs +++ b/src/closures.rs @@ -8,17 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::{ast, ptr}; -use syntax::codemap::Span; +use config::lists::*; use syntax::parse::classify; +use syntax::source_map::Span; +use syntax::{ast, ptr}; -use codemap::SpanUtils; -use expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewrite_cond, ToExpr}; +use expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewrite_cond}; use items::{span_hi_for_arg, span_lo_for_arg}; -use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting, - ListTactic, Separator, SeparatorPlace, SeparatorTactic}; +use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator}; +use overflow::OverflowableItem; use rewrite::{Rewrite, RewriteContext}; use shape::Shape; +use source_map::SpanUtils; use utils::{last_line_width, left_most_sub_expr, stmt_expr}; // This module is pretty messy because of the rules around closures and blocks: @@ -33,6 +34,8 @@ pub fn rewrite_closure( capture: ast::CaptureBy, + asyncness: ast::IsAsync, + movability: ast::Movability, fn_decl: &ast::FnDecl, body: &ast::Expr, span: Span, @@ -41,15 +44,18 @@ pub fn rewrite_closure( ) -> Option { debug!("rewrite_closure {:?}", body); - let (prefix, extra_offset) = - rewrite_closure_fn_decl(capture, fn_decl, body, span, context, shape)?; + let (prefix, extra_offset) = rewrite_closure_fn_decl( + capture, asyncness, movability, fn_decl, body, span, context, shape, + )?; // 1 = space between `|...|` and body. let body_shape = shape.offset_left(extra_offset)?; - if let ast::ExprKind::Block(ref block) = body.node { + if let ast::ExprKind::Block(ref block, _) = body.node { // The body of the closure is an empty block. - if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) { - return Some(format!("{} {{}}", prefix)); + if block.stmts.is_empty() && !block_contains_comment(block, context.source_map) { + return body + .rewrite(context, shape) + .map(|s| format!("{} {}", prefix, s)); } let result = match fn_decl.output { @@ -93,7 +99,7 @@ fn get_inner_expr<'a>( prefix: &str, context: &RewriteContext, ) -> &'a ast::Expr { - if let ast::ExprKind::Block(ref block) = expr.node { + if let ast::ExprKind::Block(ref block, _) = expr.node { if !needs_block(block, prefix, context) { // block.stmts.len() == 1 if let Some(expr) = stmt_expr(&block.stmts[0]) { @@ -107,8 +113,26 @@ fn get_inner_expr<'a>( // Figure out if a block is necessary. fn needs_block(block: &ast::Block, prefix: &str, context: &RewriteContext) -> bool { - is_unsafe_block(block) || block.stmts.len() > 1 - || block_contains_comment(block, context.codemap) || prefix.contains('\n') + is_unsafe_block(block) + || block.stmts.len() > 1 + || block_contains_comment(block, context.source_map) + || prefix.contains('\n') +} + +fn veto_block(e: &ast::Expr) -> bool { + match e.node { + ast::ExprKind::Call(..) + | ast::ExprKind::Binary(..) + | ast::ExprKind::Cast(..) + | ast::ExprKind::Type(..) + | ast::ExprKind::Assign(..) + | ast::ExprKind::AssignOp(..) + | ast::ExprKind::Field(..) + | ast::ExprKind::Index(..) + | ast::ExprKind::Range(..) + | ast::ExprKind::Try(..) => true, + _ => false, + } } // Rewrite closure with a single expression wrapping its body with block. @@ -119,25 +143,23 @@ fn rewrite_closure_with_block( shape: Shape, ) -> Option { let left_most = left_most_sub_expr(body); - let veto_block = left_most != body && !classify::expr_requires_semi_to_be_stmt(left_most); + let veto_block = veto_block(body) && !classify::expr_requires_semi_to_be_stmt(left_most); if veto_block { return None; } let block = ast::Block { - stmts: vec![ - ast::Stmt { - id: ast::NodeId::new(0), - node: ast::StmtKind::Expr(ptr::P(body.clone())), - span: body.span, - }, - ], + stmts: vec![ast::Stmt { + id: ast::NodeId::new(0), + node: ast::StmtKind::Expr(ptr::P(body.clone())), + span: body.span, + }], id: ast::NodeId::new(0), rules: ast::BlockCheckMode::Default, span: body.span, recovered: false, }; - let block = ::expr::rewrite_block_with_visitor(context, "", &block, shape, false)?; + let block = ::expr::rewrite_block_with_visitor(context, "", &block, None, None, shape, false)?; Some(format!("{} {}", prefix, block)) } @@ -152,7 +174,7 @@ fn allow_multi_line(expr: &ast::Expr) -> bool { match expr.node { ast::ExprKind::Match(..) | ast::ExprKind::Block(..) - | ast::ExprKind::Catch(..) + | ast::ExprKind::TryBlock(..) | ast::ExprKind::Loop(..) | ast::ExprKind::Struct(..) => true, @@ -168,7 +190,7 @@ fn allow_multi_line(expr: &ast::Expr) -> bool { // When rewriting closure's body without block, we require it to fit in a single line // unless it is a block-like expression or we are inside macro call. - let veto_multiline = (!allow_multi_line(expr) && !context.inside_macro) + let veto_multiline = (!allow_multi_line(expr) && !context.inside_macro()) || context.config.force_multiline_blocks(); expr.rewrite(context, shape) .and_then(|rw| { @@ -194,20 +216,30 @@ fn rewrite_closure_block( // Return type is (prefix, extra_offset) fn rewrite_closure_fn_decl( capture: ast::CaptureBy, + asyncness: ast::IsAsync, + movability: ast::Movability, fn_decl: &ast::FnDecl, body: &ast::Expr, span: Span, context: &RewriteContext, shape: Shape, ) -> Option<(String, usize)> { + let is_async = if asyncness.is_async() { "async " } else { "" }; let mover = if capture == ast::CaptureBy::Value { "move " } else { "" }; + let immovable = if movability == ast::Movability::Static { + "static " + } else { + "" + }; // 4 = "|| {".len(), which is overconservative when the closure consists of // a single expression. - let nested_shape = shape.shrink_left(mover.len())?.sub_width(4)?; + let nested_shape = shape + .shrink_left(is_async.len() + mover.len() + immovable.len())? + .sub_width(4)?; // 1 = | let argument_offset = nested_shape.indent + 1; @@ -215,23 +247,20 @@ fn rewrite_closure_fn_decl( let ret_str = fn_decl.output.rewrite(context, arg_shape)?; let arg_items = itemize_list( - context.codemap, + context.snippet_provider, fn_decl.inputs.iter(), "|", ",", |arg| span_lo_for_arg(arg), |arg| span_hi_for_arg(context, arg), |arg| arg.rewrite(context, arg_shape), - context.codemap.span_after(span, "|"), + context.snippet_provider.span_after(span, "|"), body.span.lo(), false, ); let item_vec = arg_items.collect::>(); // 1 = space between arguments and return type. - let horizontal_budget = nested_shape - .width - .checked_sub(ret_str.len() + 1) - .unwrap_or(0); + let horizontal_budget = nested_shape.width.saturating_sub(ret_str.len() + 1); let tactic = definitive_tactic( &item_vec, ListTactic::HorizontalVertical, @@ -243,18 +272,11 @@ fn rewrite_closure_fn_decl( _ => arg_shape, }; - let fmt = ListFormatting { - tactic: tactic, - separator: ",", - trailing_separator: SeparatorTactic::Never, - separator_place: SeparatorPlace::Back, - shape: arg_shape, - ends_with_newline: false, - preserve_newline: true, - config: context.config, - }; + let fmt = ListFormatting::new(arg_shape, context.config) + .tactic(tactic) + .preserve_newline(true); let list_str = write_list(&item_vec, &fmt)?; - let mut prefix = format!("{}|{}|", mover, list_str); + let mut prefix = format!("{}{}{}|{}|", is_async, immovable, mover, list_str); if !ret_str.is_empty() { if prefix.contains('\n') { @@ -278,17 +300,21 @@ pub fn rewrite_last_closure( expr: &ast::Expr, shape: Shape, ) -> Option { - if let ast::ExprKind::Closure(capture, _, ref fn_decl, ref body, _) = expr.node { + if let ast::ExprKind::Closure(capture, asyncness, movability, ref fn_decl, ref body, _) = + expr.node + { let body = match body.node { - ast::ExprKind::Block(ref block) - if !is_unsafe_block(block) && is_simple_block(block, context.codemap) => + ast::ExprKind::Block(ref block, _) + if !is_unsafe_block(block) + && is_simple_block(block, Some(&body.attrs), context.source_map) => { stmt_expr(&block.stmts[0]).unwrap_or(body) } _ => body, }; - let (prefix, extra_offset) = - rewrite_closure_fn_decl(capture, fn_decl, body, expr.span, context, shape)?; + let (prefix, extra_offset) = rewrite_closure_fn_decl( + capture, asyncness, movability, fn_decl, body, expr.span, context, shape, + )?; // If the closure goes multi line before its body, do not overflow the closure. if prefix.contains('\n') { return None; @@ -319,9 +345,9 @@ pub fn rewrite_last_closure( // When overflowing the closure which consists of a single control flow expression, // force to use block if its condition uses multi line. - let is_multi_lined_cond = rewrite_cond(context, body, body_shape) - .map(|cond| cond.contains('\n') || cond.len() > body_shape.width) - .unwrap_or(false); + let is_multi_lined_cond = rewrite_cond(context, body, body_shape).map_or(false, |cond| { + cond.contains('\n') || cond.len() > body_shape.width + }); if is_multi_lined_cond { return rewrite_closure_with_block(body, &prefix, context, body_shape); } @@ -333,25 +359,20 @@ pub fn rewrite_last_closure( } /// Returns true if the given vector of arguments has more than one `ast::ExprKind::Closure`. -pub fn args_have_many_closure(args: &[&T]) -> bool -where - T: ToExpr, -{ +pub fn args_have_many_closure(args: &[OverflowableItem]) -> bool { args.iter() - .filter(|arg| { - arg.to_expr() - .map(|e| match e.node { - ast::ExprKind::Closure(..) => true, - _ => false, - }) - .unwrap_or(false) + .filter_map(|arg| arg.to_expr()) + .filter(|expr| match expr.node { + ast::ExprKind::Closure(..) => true, + _ => false, }) - .count() > 1 + .count() + > 1 } fn is_block_closure_forced(context: &RewriteContext, expr: &ast::Expr) -> bool { // If we are inside macro, we do not want to add or remove block from closure body. - if context.inside_macro { + if context.inside_macro() { false } else { is_block_closure_forced_inner(expr)