diff --git a/src/closures.rs b/src/closures.rs index 5bf29441b54..6adfb20db8b 100644 --- a/src/closures.rs +++ b/src/closures.rs @@ -9,7 +9,7 @@ use crate::expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewr use crate::items::{span_hi_for_param, span_lo_for_param}; use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator}; use crate::overflow::OverflowableItem; -use crate::rewrite::{Rewrite, RewriteContext}; +use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult}; use crate::shape::Shape; use crate::source_map::SpanUtils; use crate::types::rewrite_bound_params; @@ -36,7 +36,7 @@ pub(crate) fn rewrite_closure( span: Span, context: &RewriteContext<'_>, shape: Shape, -) -> Option { +) -> RewriteResult { debug!("rewrite_closure {:?}", body); let (prefix, extra_offset) = rewrite_closure_fn_decl( @@ -52,13 +52,15 @@ pub(crate) fn rewrite_closure( shape, )?; // 1 = space between `|...|` and body. - let body_shape = shape.offset_left(extra_offset)?; + let body_shape = shape + .offset_left(extra_offset) + .max_width_error(shape.width, span)?; if let ast::ExprKind::Block(ref block, _) = body.kind { // The body of the closure is an empty block. if block.stmts.is_empty() && !block_contains_comment(context, block) { return body - .rewrite(context, shape) + .rewrite_result(context, shape) .map(|s| format!("{} {}", prefix, s)); } @@ -66,15 +68,15 @@ pub(crate) fn rewrite_closure( ast::FnRetTy::Default(_) if !context.inside_macro() => { try_rewrite_without_block(body, &prefix, context, shape, body_shape) } - _ => None, + _ => Err(RewriteError::Unknown), }; - result.or_else(|| { + result.or_else(|_| { // Either we require a block, or tried without and failed. rewrite_closure_block(block, &prefix, context, body_shape) }) } else { - rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|| { + rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|_| { // The closure originally had a non-block expression, but we can't fit on // one line, so we'll insert a block. rewrite_closure_with_block(body, &prefix, context, body_shape) @@ -88,7 +90,7 @@ fn try_rewrite_without_block( context: &RewriteContext<'_>, shape: Shape, body_shape: Shape, -) -> Option { +) -> RewriteResult { let expr = get_inner_expr(expr, prefix, context); if is_block_closure_forced(context, expr) { @@ -152,11 +154,11 @@ fn rewrite_closure_with_block( prefix: &str, context: &RewriteContext<'_>, shape: Shape, -) -> Option { +) -> RewriteResult { let left_most = left_most_sub_expr(body); let veto_block = veto_block(body) && !expr_requires_semi_to_be_stmt(left_most); if veto_block { - return None; + return Err(RewriteError::Unknown); } let block = ast::Block { @@ -184,7 +186,7 @@ fn rewrite_closure_with_block( shape, false, )?; - Some(format!("{prefix} {block}")) + Ok(format!("{prefix} {block}")) } // Rewrite closure with a single expression without wrapping its body with block. @@ -193,7 +195,7 @@ fn rewrite_closure_expr( prefix: &str, context: &RewriteContext<'_>, shape: Shape, -) -> Option { +) -> RewriteResult { fn allow_multi_line(expr: &ast::Expr) -> bool { match expr.kind { ast::ExprKind::Match(..) @@ -216,12 +218,12 @@ fn rewrite_closure_expr( // unless it is a block-like expression or we are inside macro call. let veto_multiline = (!allow_multi_line(expr) && !context.inside_macro()) || context.config.force_multiline_blocks(); - expr.rewrite(context, shape) + expr.rewrite_result(context, shape) .and_then(|rw| { if veto_multiline && rw.contains('\n') { - None + Err(RewriteError::Unknown) } else { - Some(rw) + Ok(rw) } }) .map(|rw| format!("{} {}", prefix, rw)) @@ -233,8 +235,12 @@ fn rewrite_closure_block( prefix: &str, context: &RewriteContext<'_>, shape: Shape, -) -> Option { - Some(format!("{} {}", prefix, block.rewrite(context, shape)?)) +) -> RewriteResult { + Ok(format!( + "{} {}", + prefix, + block.rewrite_result(context, shape)? + )) } // Return type is (prefix, extra_offset) @@ -249,13 +255,14 @@ fn rewrite_closure_fn_decl( span: Span, context: &RewriteContext<'_>, shape: Shape, -) -> Option<(String, usize)> { +) -> Result<(String, usize), RewriteError> { let binder = match binder { ast::ClosureBinder::For { generic_params, .. } if generic_params.is_empty() => { "for<> ".to_owned() } ast::ClosureBinder::For { generic_params, .. } => { - let lifetime_str = rewrite_bound_params(context, shape, generic_params)?; + let lifetime_str = + rewrite_bound_params(context, shape, generic_params).unknown_error()?; format!("for<{lifetime_str}> ") } ast::ClosureBinder::NotPresent => "".to_owned(), @@ -286,13 +293,17 @@ fn rewrite_closure_fn_decl( // 4 = "|| {".len(), which is overconservative when the closure consists of // a single expression. let nested_shape = shape - .shrink_left(binder.len() + const_.len() + immovable.len() + coro.len() + mover.len())? - .sub_width(4)?; + .shrink_left(binder.len() + const_.len() + immovable.len() + coro.len() + mover.len()) + .and_then(|shape| shape.sub_width(4)) + .max_width_error(shape.width, span)?; // 1 = | let param_offset = nested_shape.indent + 1; - let param_shape = nested_shape.offset_left(1)?.visual_indent(0); - let ret_str = fn_decl.output.rewrite(context, param_shape)?; + let param_shape = nested_shape + .offset_left(1) + .max_width_error(nested_shape.width, span)? + .visual_indent(0); + let ret_str = fn_decl.output.rewrite_result(context, param_shape)?; let param_items = itemize_list( context.snippet_provider, @@ -316,14 +327,16 @@ fn rewrite_closure_fn_decl( horizontal_budget, ); let param_shape = match tactic { - DefinitiveListTactic::Horizontal => param_shape.sub_width(ret_str.len() + 1)?, + DefinitiveListTactic::Horizontal => param_shape + .sub_width(ret_str.len() + 1) + .max_width_error(param_shape.width, span)?, _ => param_shape, }; let fmt = ListFormatting::new(param_shape, context.config) .tactic(tactic) .preserve_newline(true); - let list_str = write_list(&item_vec, &fmt)?; + let list_str = write_list(&item_vec, &fmt).unknown_error()?; let mut prefix = format!("{binder}{const_}{immovable}{coro}{mover}|{list_str}|"); if !ret_str.is_empty() { @@ -338,7 +351,7 @@ fn rewrite_closure_fn_decl( // 1 = space between `|...|` and body. let extra_offset = last_line_width(&prefix) + 1; - Some((prefix, extra_offset)) + Ok((prefix, extra_offset)) } // Rewriting closure which is placed at the end of the function call's arg. @@ -347,7 +360,7 @@ pub(crate) fn rewrite_last_closure( context: &RewriteContext<'_>, expr: &ast::Expr, shape: Shape, -) -> Option { +) -> RewriteResult { if let ast::ExprKind::Closure(ref closure) = expr.kind { let ast::Closure { ref binder, @@ -384,10 +397,12 @@ pub(crate) fn rewrite_last_closure( )?; // If the closure goes multi line before its body, do not overflow the closure. if prefix.contains('\n') { - return None; + return Err(RewriteError::Unknown); } - let body_shape = shape.offset_left(extra_offset)?; + let body_shape = shape + .offset_left(extra_offset) + .max_width_error(shape.width, expr.span)?; // We force to use block for the body of the closure for certain kinds of expressions. if is_block_closure_forced(context, body) { @@ -399,7 +414,7 @@ pub(crate) fn rewrite_last_closure( // closure. However, if the closure has a return type, then we must // keep the blocks. match rewrite_closure_expr(body, &prefix, context, shape) { - Some(single_line_body_str) + Ok(single_line_body_str) if !single_line_body_str.contains('\n') => { single_line_body_str @@ -423,9 +438,9 @@ pub(crate) fn rewrite_last_closure( } // Seems fine, just format the closure in usual manner. - return expr.rewrite(context, shape); + return expr.rewrite_result(context, shape); } - None + Err(RewriteError::Unknown) } /// Returns `true` if the given vector of arguments has more than one `ast::ExprKind::Closure`. diff --git a/src/expr.rs b/src/expr.rs index 8266f95fd70..629d3c4f0eb 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -22,7 +22,7 @@ use crate::macros::{rewrite_macro, MacroPosition}; use crate::matches::rewrite_match; use crate::overflow::{self, IntoOverflowableItem, OverflowableItem}; use crate::pairs::{rewrite_all_pairs, rewrite_pair, PairParts}; -use crate::rewrite::{Rewrite, RewriteContext}; +use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult}; use crate::shape::{Indent, Shape}; use crate::source_map::{LineRangeUtils, SpanUtils}; use crate::spanned::Spanned; @@ -145,7 +145,7 @@ pub(crate) fn format_expr( // not the `ast::Block` node we're about to rewrite. To prevent dropping inner // attributes call `rewrite_block` directly. // See https://github.com/rust-lang/rustfmt/issues/6158 - rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)? + rewrite_block(block, Some(&expr.attrs), opt_label, context, shape).ok()? } _ => anon_const.rewrite(context, shape)?, }; @@ -155,7 +155,7 @@ pub(crate) fn format_expr( match expr_type { ExprType::Statement => { if is_unsafe_block(block) { - rewrite_block(block, Some(&expr.attrs), opt_label, context, shape) + rewrite_block(block, Some(&expr.attrs), opt_label, context, shape).ok() } else if let rw @ Some(_) = rewrite_empty_block(context, block, Some(&expr.attrs), opt_label, "", shape) { @@ -173,10 +173,11 @@ pub(crate) fn format_expr( shape, true, ) + .ok() } } ExprType::SubExpression => { - rewrite_block(block, Some(&expr.attrs), opt_label, context, shape) + rewrite_block(block, Some(&expr.attrs), opt_label, context, shape).ok() } } } @@ -229,7 +230,8 @@ pub(crate) fn format_expr( expr.span, context, shape, - ), + ) + .ok(), ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) @@ -352,10 +354,10 @@ pub(crate) fn format_expr( // https://github.com/rust-dev-tools/fmt-rfcs/issues/152 ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()), ast::ExprKind::TryBlock(ref block) => { - if let rw @ Some(_) = + if let rw @ Ok(_) = rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape) { - rw + rw.ok() } else { // 9 = `try ` let budget = shape.width.saturating_sub(9); @@ -368,7 +370,8 @@ pub(crate) fn format_expr( None, context, Shape::legacy(budget, shape.indent) - )? + ) + .ok()? )) } } @@ -378,7 +381,7 @@ pub(crate) fn format_expr( } else { "" }; - if let rw @ Some(_) = rewrite_single_line_block( + if let rw @ Ok(_) = rewrite_single_line_block( context, format!("{kind} {mover}").as_str(), block, @@ -386,7 +389,7 @@ pub(crate) fn format_expr( None, shape, ) { - rw + rw.ok() } else { // 6 = `async ` let budget = shape.width.saturating_sub(6); @@ -398,7 +401,8 @@ pub(crate) fn format_expr( None, context, Shape::legacy(budget, shape.indent) - )? + ) + .ok()? )) } } @@ -522,17 +526,19 @@ fn rewrite_single_line_block( attrs: Option<&[ast::Attribute]>, label: Option, shape: Shape, -) -> Option { +) -> RewriteResult { if let Some(block_expr) = stmt::Stmt::from_simple_block(context, block, attrs) { - let expr_shape = shape.offset_left(last_line_width(prefix))?; - let expr_str = block_expr.rewrite(context, expr_shape)?; + let expr_shape = shape + .offset_left(last_line_width(prefix)) + .max_width_error(shape.width, block_expr.span())?; + let expr_str = block_expr.rewrite_result(context, expr_shape)?; let label_str = rewrite_label(label); let result = format!("{prefix}{label_str}{{ {expr_str} }}"); if result.len() <= shape.width && !result.contains('\n') { - return Some(result); + return Ok(result); } } - None + Err(RewriteError::Unknown) } pub(crate) fn rewrite_block_with_visitor( @@ -543,9 +549,9 @@ pub(crate) fn rewrite_block_with_visitor( label: Option, shape: Shape, has_braces: bool, -) -> Option { - if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, prefix, shape) { - return rw; +) -> RewriteResult { + if let Some(rw_str) = rewrite_empty_block(context, block, attrs, label, prefix, shape) { + return Ok(rw_str); } let mut visitor = FmtVisitor::from_context(context); @@ -554,7 +560,7 @@ pub(crate) fn rewrite_block_with_visitor( match (block.rules, label) { (ast::BlockCheckMode::Unsafe(..), _) | (ast::BlockCheckMode::Default, Some(_)) => { let snippet = context.snippet(block.span); - let open_pos = snippet.find_uncommented("{")?; + let open_pos = snippet.find_uncommented("{").unknown_error()?; visitor.last_pos = block.span.lo() + BytePos(open_pos as u32) } (ast::BlockCheckMode::Default, None) => visitor.last_pos = block.span.lo(), @@ -568,11 +574,15 @@ pub(crate) fn rewrite_block_with_visitor( .skipped_range .borrow_mut() .append(&mut visitor_context.skipped_range.borrow_mut()); - Some(format!("{}{}{}", prefix, label_str, visitor.buffer)) + Ok(format!("{}{}{}", prefix, label_str, visitor.buffer)) } impl Rewrite for ast::Block { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { + self.rewrite_result(context, shape).ok() + } + + fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { rewrite_block(self, None, None, context, shape) } } @@ -583,7 +593,7 @@ fn rewrite_block( label: Option, context: &RewriteContext<'_>, shape: Shape, -) -> Option { +) -> RewriteResult { rewrite_block_inner(block, attrs, label, true, context, shape) } @@ -594,27 +604,24 @@ fn rewrite_block_inner( allow_single_line: bool, context: &RewriteContext<'_>, shape: Shape, -) -> Option { - let prefix = block_prefix(context, block, shape)?; +) -> RewriteResult { + let prefix = block_prefix(context, block, shape).unknown_error()?; // shape.width is used only for the single line case: either the empty block `{}`, // or an unsafe expression `unsafe { e }`. - if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, &prefix, shape) { - return rw; + if let Some(rw_str) = rewrite_empty_block(context, block, attrs, label, &prefix, shape) { + return Ok(rw_str); } - let result = rewrite_block_with_visitor(context, &prefix, block, attrs, label, shape, true); - if let Some(ref result_str) = result { - if allow_single_line && result_str.lines().count() <= 3 { - if let rw @ Some(_) = - rewrite_single_line_block(context, &prefix, block, attrs, label, shape) - { - return rw; - } + let result_str = + rewrite_block_with_visitor(context, &prefix, block, attrs, label, shape, true)?; + if allow_single_line && result_str.lines().count() <= 3 { + if let rw @ Ok(_) = rewrite_single_line_block(context, &prefix, block, attrs, label, shape) + { + return rw; } } - - result + Ok(result_str) } /// Rewrite the divergent block of a `let-else` statement. @@ -623,7 +630,7 @@ pub(crate) fn rewrite_let_else_block( allow_single_line: bool, context: &RewriteContext<'_>, shape: Shape, -) -> Option { +) -> RewriteResult { rewrite_block_inner(block, None, None, allow_single_line, context, shape) } @@ -1112,7 +1119,8 @@ impl<'a> Rewrite for ControlFlow<'a> { let block_str = { let old_val = context.is_if_else_block.replace(self.else_block.is_some()); let result = - rewrite_block_with_visitor(context, "", self.block, None, None, block_shape, true); + rewrite_block_with_visitor(context, "", self.block, None, None, block_shape, true) + .ok(); context.is_if_else_block.replace(old_val); result? }; diff --git a/src/items.rs b/src/items.rs index 48f5c36ac07..0848ec624ca 100644 --- a/src/items.rs +++ b/src/items.rs @@ -181,8 +181,7 @@ impl Rewrite for ast::Local { && allow_single_line_let_else_block(assign_str_with_else_kw, block); let mut rw_else_block = - rewrite_let_else_block(block, allow_single_line, context, shape) - .unknown_error()?; + rewrite_let_else_block(block, allow_single_line, context, shape)?; let single_line_else = !rw_else_block.contains('\n'); // +1 for the trailing `;` @@ -191,8 +190,7 @@ impl Rewrite for ast::Local { if allow_single_line && single_line_else && else_block_exceeds_width { // writing this on one line would exceed the available width // so rewrite the else block over multiple lines. - rw_else_block = - rewrite_let_else_block(block, false, context, shape).unknown_error()?; + rw_else_block = rewrite_let_else_block(block, false, context, shape)?; } result.push_str(&rw_else_block); diff --git a/src/overflow.rs b/src/overflow.rs index a1de71a35be..43d05e56807 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -427,7 +427,7 @@ impl<'a> Context<'a> { if closures::args_have_many_closure(&self.items) { None } else { - closures::rewrite_last_closure(self.context, expr, shape) + closures::rewrite_last_closure(self.context, expr, shape).ok() } }