diff --git a/src/attr.rs b/src/attr.rs index a263e253dd9..c47d7a2a2f1 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -99,7 +99,7 @@ fn format_derive( ",", |span| span.lo(), |span| span.hi(), - |span| Some(context.snippet(*span).to_owned()), + |span| Ok(context.snippet(*span).to_owned()), // We update derive attribute spans to start after the opening '(' // This helps us focus parsing to just what's inside #[derive(...)] context.snippet_provider.span_after(attr.span, "("), @@ -147,7 +147,7 @@ fn format_derive( .tactic(tactic) .trailing_separator(trailing_separator) .ends_with_newline(false); - let item_str = write_list(&all_items, &fmt)?; + let item_str = write_list(&all_items, &fmt).ok()?; debug!("item_str: '{}'", item_str); diff --git a/src/closures.rs b/src/closures.rs index 6adfb20db8b..20dc4eb6ec4 100644 --- a/src/closures.rs +++ b/src/closures.rs @@ -312,7 +312,7 @@ fn rewrite_closure_fn_decl( ",", |param| span_lo_for_param(param), |param| span_hi_for_param(context, param), - |param| param.rewrite(context, param_shape), + |param| param.rewrite_result(context, param_shape), context.snippet_provider.span_after(span, "|"), body.span.lo(), false, @@ -336,7 +336,7 @@ fn rewrite_closure_fn_decl( let fmt = ListFormatting::new(param_shape, context.config) .tactic(tactic) .preserve_newline(true); - let list_str = write_list(&item_vec, &fmt).unknown_error()?; + let list_str = write_list(&item_vec, &fmt)?; let mut prefix = format!("{binder}{const_}{immovable}{coro}{mover}|{list_str}|"); if !ret_str.is_empty() { diff --git a/src/expr.rs b/src/expr.rs index 7eaaadb1850..b73b3348b3e 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1671,15 +1671,24 @@ fn rewrite_struct_lit<'a>( let rewrite = |item: &StructLitField<'_>| match *item { StructLitField::Regular(field) => { // The 1 taken from the v_budget is for the comma. - let v_shape = v_shape.sub_width(1)?; - rewrite_field(context, field, v_shape, 0).ok() + rewrite_field( + context, + field, + v_shape.sub_width(1).max_width_error(v_shape.width, span)?, + 0, + ) } StructLitField::Base(expr) => { // 2 = .. - let v_shape = v_shape.sub_width(2)?; - expr.rewrite(context, v_shape).map(|s| format!("..{}", s)) + expr.rewrite_result( + context, + v_shape + .offset_left(2) + .max_width_error(v_shape.width, span)?, + ) + .map(|s| format!("..{}", s)) } - StructLitField::Rest(_) => Some("..".to_owned()), + StructLitField::Rest(_) => Ok("..".to_owned()), }; let items = itemize_list( @@ -1709,7 +1718,7 @@ fn rewrite_struct_lit<'a>( force_no_trailing_comma || has_base_or_rest || !context.use_block_indent(), ); - write_list(&item_vec, &fmt).unknown_error()? + write_list(&item_vec, &fmt)? }; let fields_str = @@ -1843,7 +1852,7 @@ fn rewrite_tuple_in_visual_indent_style<'a, T: 'a + IntoOverflowableItem<'a>>( ",", |item| item.span().lo(), |item| item.span().hi(), - |item| item.rewrite(context, nested_shape), + |item| item.rewrite_result(context, nested_shape), list_lo, span.hi() - BytePos(1), false, @@ -1858,7 +1867,7 @@ fn rewrite_tuple_in_visual_indent_style<'a, T: 'a + IntoOverflowableItem<'a>>( let fmt = ListFormatting::new(nested_shape, context.config) .tactic(tactic) .ends_with_newline(false); - let list_str = write_list(&item_vec, &fmt)?; + let list_str = write_list(&item_vec, &fmt).ok()?; Some(format!("({list_str})")) } diff --git a/src/imports.rs b/src/imports.rs index 12c178e136f..4cea59ddc58 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -470,7 +470,7 @@ impl UseTree { ",", |tree| tree.span.lo(), |tree| tree.span.hi(), - |_| Some("".to_owned()), // We only need comments for now. + |_| Ok("".to_owned()), // We only need comments for now. context.snippet_provider.span_after(a.span, "{"), a.span.hi(), false, @@ -993,7 +993,7 @@ fn rewrite_nested_use_tree( }; for use_tree in use_tree_list { if let Some(mut list_item) = use_tree.list_item.clone() { - list_item.item = use_tree.rewrite(context, nested_shape); + list_item.item = use_tree.rewrite_result(context, nested_shape); list_items.push(list_item); } else { list_items.push(ListItem::from_str(use_tree.rewrite(context, nested_shape)?)); @@ -1032,7 +1032,7 @@ fn rewrite_nested_use_tree( .preserve_newline(true) .nested(has_nested_list); - let list_str = write_list(&list_items, &fmt)?; + let list_str = write_list(&list_items, &fmt).ok()?; let result = if (list_str.contains('\n') || list_str.len() > remaining_width diff --git a/src/items.rs b/src/items.rs index 0848ec624ca..0bb27839ed3 100644 --- a/src/items.rs +++ b/src/items.rs @@ -629,7 +629,10 @@ impl<'a> FmtVisitor<'a> { } }, |f| f.span.hi(), - |f| self.format_variant(f, one_line_width, pad_discrim_ident_to), + |f| { + self.format_variant(f, one_line_width, pad_discrim_ident_to) + .unknown_error() + }, body_lo, body_hi, false, @@ -650,7 +653,7 @@ impl<'a> FmtVisitor<'a> { .trailing_separator(self.config.trailing_comma()) .preserve_newline(true); - let list = write_list(&items, &fmt)?; + let list = write_list(&items, &fmt).ok()?; result.push_str(&list); result.push_str(&original_offset.to_string_with_newline(self.config)); result.push('}'); @@ -2777,8 +2780,8 @@ fn rewrite_params( |param| param.ty.span.hi(), |param| { param - .rewrite(context, Shape::legacy(multi_line_budget, param_indent)) - .or_else(|| Some(context.snippet(param.span()).to_owned())) + .rewrite_result(context, Shape::legacy(multi_line_budget, param_indent)) + .or_else(|_| Ok(context.snippet(param.span()).to_owned())) }, span.lo(), span.hi(), @@ -2816,7 +2819,7 @@ fn rewrite_params( .trailing_separator(trailing_separator) .ends_with_newline(tactic.ends_with_newline(context.config.indent_style())) .preserve_newline(true); - write_list(¶m_items, &fmt) + write_list(¶m_items, &fmt).ok() } fn compute_budgets_for_params( @@ -3048,7 +3051,7 @@ fn rewrite_bounds_on_where_clause( ",", |pred| pred.span().lo(), |pred| pred.span().hi(), - |pred| pred.rewrite(context, shape), + |pred| pred.rewrite_result(context, shape), span_start, span_end, false, @@ -3073,7 +3076,7 @@ fn rewrite_bounds_on_where_clause( .tactic(shape_tactic) .trailing_separator(comma_tactic) .preserve_newline(preserve_newline); - write_list(&items.collect::>(), &fmt) + write_list(&items.collect::>(), &fmt).ok() } fn rewrite_where_clause( @@ -3129,7 +3132,7 @@ fn rewrite_where_clause( ",", |pred| pred.span().lo(), |pred| pred.span().hi(), - |pred| pred.rewrite(context, Shape::legacy(budget, offset)), + |pred| pred.rewrite_result(context, Shape::legacy(budget, offset)), span_start, span_end, false, @@ -3149,7 +3152,7 @@ fn rewrite_where_clause( .trailing_separator(comma_tactic) .ends_with_newline(tactic.ends_with_newline(context.config.indent_style())) .preserve_newline(true); - let preds_str = write_list(&item_vec, &fmt)?; + let preds_str = write_list(&item_vec, &fmt).ok()?; let end_length = if terminator == "{" { // If the brace is on the next line we don't need to count it otherwise it needs two diff --git a/src/lists.rs b/src/lists.rs index 41afef279e9..46d40fa750e 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -8,7 +8,7 @@ use rustc_span::BytePos; use crate::comment::{find_comment_end, rewrite_comment, FindUncommented}; use crate::config::lists::*; use crate::config::{Config, IndentStyle}; -use crate::rewrite::RewriteContext; +use crate::rewrite::{RewriteContext, RewriteError, RewriteErrorExt, RewriteResult}; use crate::shape::{Indent, Shape}; use crate::utils::{ count_newlines, first_line_width, last_line_width, mk_sp, starts_with_newline, @@ -125,18 +125,18 @@ pub(crate) struct ListItem { pub(crate) pre_comment_style: ListItemCommentStyle, // Item should include attributes and doc comments. None indicates a failed // rewrite. - pub(crate) item: Option, + pub(crate) item: RewriteResult, pub(crate) post_comment: Option, // Whether there is extra whitespace before this item. pub(crate) new_lines: bool, } impl ListItem { - pub(crate) fn empty() -> ListItem { + pub(crate) fn from_item(item: RewriteResult) -> ListItem { ListItem { pre_comment: None, pre_comment_style: ListItemCommentStyle::None, - item: None, + item: item, post_comment: None, new_lines: false, } @@ -185,7 +185,7 @@ impl ListItem { ListItem { pre_comment: None, pre_comment_style: ListItemCommentStyle::None, - item: Some(s.into()), + item: Ok(s.into()), post_comment: None, new_lines: false, } @@ -197,7 +197,11 @@ impl ListItem { !matches!(*s, Some(ref s) if !s.is_empty()) } - !(empty(&self.pre_comment) && empty(&self.item) && empty(&self.post_comment)) + fn empty_result(s: &RewriteResult) -> bool { + !matches!(*s, Ok(ref s) if !s.is_empty()) + } + + !(empty(&self.pre_comment) && empty_result(&self.item) && empty(&self.post_comment)) } } @@ -257,7 +261,7 @@ where } // Format a list of commented items into a string. -pub(crate) fn write_list(items: I, formatting: &ListFormatting<'_>) -> Option +pub(crate) fn write_list(items: I, formatting: &ListFormatting<'_>) -> RewriteResult where I: IntoIterator + Clone, T: AsRef, @@ -281,7 +285,7 @@ where let indent_str = &formatting.shape.indent.to_string(formatting.config); while let Some((i, item)) = iter.next() { let item = item.as_ref(); - let inner_item = item.item.as_ref()?; + let inner_item = item.item.as_ref().or_else(|err| Err(err.clone()))?; let first = i == 0; let last = iter.peek().is_none(); let mut separate = match sep_place { @@ -362,8 +366,8 @@ where // Block style in non-vertical mode. let block_mode = tactic == DefinitiveListTactic::Horizontal; // Width restriction is only relevant in vertical mode. - let comment = - rewrite_comment(comment, block_mode, formatting.shape, formatting.config)?; + let comment = rewrite_comment(comment, block_mode, formatting.shape, formatting.config) + .unknown_error()?; result.push_str(&comment); if !inner_item.is_empty() { @@ -409,7 +413,8 @@ where true, Shape::legacy(formatting.shape.width, Indent::empty()), formatting.config, - )?; + ) + .unknown_error()?; result.push(' '); result.push_str(&formatted_comment); @@ -460,7 +465,8 @@ where ) }; - let mut formatted_comment = rewrite_post_comment(&mut item_max_width)?; + let mut formatted_comment = + rewrite_post_comment(&mut item_max_width).unknown_error()?; if !starts_with_newline(comment) { if formatting.align_comments { @@ -473,7 +479,8 @@ where > formatting.config.max_width() { item_max_width = None; - formatted_comment = rewrite_post_comment(&mut item_max_width)?; + formatted_comment = + rewrite_post_comment(&mut item_max_width).unknown_error()?; comment_alignment = post_comment_alignment(item_max_width, unicode_str_width(inner_item)); } @@ -516,7 +523,7 @@ where prev_item_is_nested_import = inner_item.contains("::"); } - Some(result) + Ok(result) } fn max_width_of_item_with_post_comment( @@ -741,7 +748,7 @@ where I: Iterator, F1: Fn(&T) -> BytePos, F2: Fn(&T) -> BytePos, - F3: Fn(&T) -> Option, + F3: Fn(&T) -> RewriteResult, { type Item = ListItem; @@ -775,8 +782,9 @@ where ListItem { pre_comment, pre_comment_style, + // leave_last is set to true only for rewrite_items item: if self.inner.peek().is_none() && self.leave_last { - None + Err(RewriteError::SkipFormatting) } else { (self.get_item_string)(&item) }, @@ -805,7 +813,7 @@ where I: Iterator, F1: Fn(&T) -> BytePos, F2: Fn(&T) -> BytePos, - F3: Fn(&T) -> Option, + F3: Fn(&T) -> RewriteResult, { ListItems { snippet_provider, diff --git a/src/macros.rs b/src/macros.rs index a0582b061c0..a948aaba083 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -31,7 +31,7 @@ use crate::lists::{itemize_list, write_list, ListFormatting}; use crate::overflow; use crate::parse::macros::lazy_static::parse_lazy_static; use crate::parse::macros::{parse_expr, parse_macro_args, ParsedMacroArgs}; -use crate::rewrite::{Rewrite, RewriteContext}; +use crate::rewrite::{Rewrite, RewriteContext, RewriteError}; use crate::shape::{Indent, Shape}; use crate::source_map::SpanUtils; use crate::spanned::Spanned; @@ -452,13 +452,13 @@ pub(crate) fn rewrite_macro_def( |branch| branch.span.lo(), |branch| branch.span.hi(), |branch| match branch.rewrite(context, arm_shape, multi_branch_style) { - Some(v) => Some(v), + Some(v) => Ok(v), // if the rewrite returned None because a macro could not be rewritten, then return the // original body None if context.macro_rewrite_failure.get() => { - Some(context.snippet(branch.body).trim().to_string()) + Ok(context.snippet(branch.body).trim().to_string()) } - None => None, + None => Err(RewriteError::Unknown), }, context.snippet_provider.span_after(span, "{"), span.hi(), @@ -477,8 +477,8 @@ pub(crate) fn rewrite_macro_def( } match write_list(&branch_items, &fmt) { - Some(ref s) => result += s, - None => return snippet, + Ok(ref s) => result += s, + Err(_) => return snippet, } if multi_branch_style { diff --git a/src/matches.rs b/src/matches.rs index 0dbbb6f1cac..5884d02af15 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -225,7 +225,7 @@ fn rewrite_match_arms( "|", |arm| arm.span().lo(), |arm| arm.span().hi(), - |arm| arm.rewrite(context, arm_shape), + |arm| arm.rewrite_result(context, arm_shape), open_brace_pos, span.hi(), false, @@ -236,7 +236,7 @@ fn rewrite_match_arms( .separator("") .preserve_newline(true); - write_list(&arms_vec, &fmt).unknown_error() + write_list(&arms_vec, &fmt) } fn rewrite_match_arm( diff --git a/src/overflow.rs b/src/overflow.rs index 43d05e56807..1a0d8bf15f6 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -19,7 +19,7 @@ use crate::lists::{ }; use crate::macros::MacroArg; use crate::patterns::{can_be_overflowed_pat, TuplePatField}; -use crate::rewrite::{Rewrite, RewriteContext}; +use crate::rewrite::{Rewrite, RewriteContext, RewriteErrorExt}; use crate::shape::Shape; use crate::source_map::SpanUtils; use crate::spanned::Spanned; @@ -456,7 +456,7 @@ impl<'a> Context<'a> { if let Some(rewrite) = rewrite { // splitn(2, *).next().unwrap() is always safe. - let rewrite_first_line = Some(rewrite.splitn(2, '\n').next().unwrap().to_owned()); + let rewrite_first_line = Ok(rewrite.splitn(2, '\n').next().unwrap().to_owned()); last_list_item.item = rewrite_first_line; Some(rewrite) } else { @@ -544,22 +544,23 @@ impl<'a> Context<'a> { .and_then(|last_item| last_item.rewrite(self.context, self.nested_shape)); let no_newline = rw.as_ref().map_or(false, |s| !s.contains('\n')); if no_newline { - list_items[self.items.len() - 1].item = rw; + list_items[self.items.len() - 1].item = rw.unknown_error(); } else { - list_items[self.items.len() - 1].item = Some(overflowed.to_owned()); + list_items[self.items.len() - 1].item = Ok(overflowed.to_owned()); } } else { - list_items[self.items.len() - 1].item = Some(overflowed.to_owned()); + list_items[self.items.len() - 1].item = Ok(overflowed.to_owned()); } } (true, DefinitiveListTactic::Horizontal, placeholder @ Some(..)) => { - list_items[self.items.len() - 1].item = placeholder; + list_items[self.items.len() - 1].item = placeholder.unknown_error(); } _ if !self.items.is_empty() => { list_items[self.items.len() - 1].item = self .items .last() - .and_then(|last_item| last_item.rewrite(self.context, self.nested_shape)); + .and_then(|last_item| last_item.rewrite(self.context, self.nested_shape)) + .unknown_error(); // Use horizontal layout for a function with a single argument as long as // everything fits in a single line. @@ -623,7 +624,7 @@ impl<'a> Context<'a> { ",", |item| item.span().lo(), |item| item.span().hi(), - |item| item.rewrite(self.context, self.nested_shape), + |item| item.rewrite_result(self.context, self.nested_shape), span.lo(), span.hi(), true, @@ -656,6 +657,7 @@ impl<'a> Context<'a> { .ends_with_newline(ends_with_newline); write_list(&list_items, &fmt) + .ok() .map(|items_str| (tactic == DefinitiveListTactic::Horizontal, items_str)) } diff --git a/src/patterns.rs b/src/patterns.rs index da5a0c49aa2..df435a3069d 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -101,7 +101,7 @@ impl Rewrite for Pat { .separator(" |") .separator_place(context.config.binop_separator()) .ends_with_newline(false); - write_list(&items, &fmt) + write_list(&items, &fmt).ok() } PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape), PatKind::Ident(BindingMode(by_ref, mutability), ident, ref sub_pat) => { @@ -343,7 +343,7 @@ fn rewrite_struct_pat( } }, |f| f.span.hi(), - |f| f.rewrite(context, v_shape), + |f| f.rewrite_result(context, v_shape), context.snippet_provider.span_after(span, "{"), span.hi(), false, @@ -354,7 +354,7 @@ fn rewrite_struct_pat( let nested_shape = shape_for_tactic(tactic, h_shape, v_shape); let fmt = struct_lit_formatting(nested_shape, tactic, context, false); - let mut fields_str = write_list(&item_vec, &fmt).unknown_error()?; + let mut fields_str = write_list(&item_vec, &fmt)?; let one_line_width = h_shape.map_or(0, |shape| shape.width); let has_trailing_comma = fmt.needs_trailing_separator(); @@ -551,7 +551,7 @@ fn count_wildcard_suffix_len( ",", |item| item.span().lo(), |item| item.span().hi(), - |item| item.rewrite(context, shape), + |item| item.rewrite_result(context, shape), context.snippet_provider.span_after(span, "("), span.hi() - BytePos(1), false, @@ -561,7 +561,7 @@ fn count_wildcard_suffix_len( for item in items .iter() .rev() - .take_while(|i| matches!(i.item, Some(ref internal_string) if internal_string == "_")) + .take_while(|i| matches!(i.item, Ok(ref internal_string) if internal_string == "_")) { suffix_len += 1; diff --git a/src/reorder.rs b/src/reorder.rs index fdbed939af5..8a546a78297 100644 --- a/src/reorder.rs +++ b/src/reorder.rs @@ -15,7 +15,7 @@ use crate::config::{Config, GroupImportsTactic}; use crate::imports::{normalize_use_trees_with_granularity, UseSegmentKind, UseTree}; use crate::items::{is_mod_decl, rewrite_extern_crate, rewrite_mod}; use crate::lists::{itemize_list, write_list, ListFormatting, ListItem}; -use crate::rewrite::RewriteContext; +use crate::rewrite::{RewriteContext, RewriteErrorExt}; use crate::shape::Shape; use crate::source_map::LineRangeUtils; use crate::spanned::Spanned; @@ -59,7 +59,7 @@ fn wrap_reorderable_items( let fmt = ListFormatting::new(shape, context.config) .separator("") .align_comments(false); - write_list(list_items, &fmt) + write_list(list_items, &fmt).ok() } fn rewrite_reorderable_item( @@ -99,7 +99,7 @@ fn rewrite_reorderable_or_regroupable_items( ";", |item| item.span().lo(), |item| item.span().hi(), - |_item| Some("".to_owned()), + |_item| Ok("".to_owned()), span.lo(), span.hi(), false, @@ -131,9 +131,18 @@ fn rewrite_reorderable_or_regroupable_items( .map(|use_group| { let item_vec: Vec<_> = use_group .into_iter() - .map(|use_tree| ListItem { - item: use_tree.rewrite_top_level(context, nested_shape), - ..use_tree.list_item.unwrap_or_else(ListItem::empty) + .map(|use_tree| { + let item = use_tree + .rewrite_top_level(context, nested_shape) + .unknown_error(); + if let Some(list_item) = use_tree.list_item { + ListItem { + item: item, + ..list_item + } + } else { + ListItem::from_item(item) + } }) .collect(); wrap_reorderable_items(context, &item_vec, nested_shape) @@ -151,7 +160,7 @@ fn rewrite_reorderable_or_regroupable_items( ";", |item| item.span().lo(), |item| item.span().hi(), - |item| rewrite_reorderable_item(context, item, shape), + |item| rewrite_reorderable_item(context, item, shape).unknown_error(), span.lo(), span.hi(), false, diff --git a/src/rewrite.rs b/src/rewrite.rs index acf4cc1d60b..6644e4b27a8 100644 --- a/src/rewrite.rs +++ b/src/rewrite.rs @@ -30,7 +30,7 @@ impl Rewrite for ptr::P { } } -#[derive(Error, Debug)] +#[derive(Clone, Error, Debug)] pub(crate) enum RewriteError { #[error("Formatting was skipped due to skip attribute or out of file range.")] SkipFormatting, diff --git a/src/types.rs b/src/types.rs index c15ee2f3c5b..f43c60db02a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -388,7 +388,7 @@ where ",", |arg| arg.span().lo(), |arg| arg.span().hi(), - |arg| arg.rewrite(context, list_shape), + |arg| arg.rewrite_result(context, list_shape), list_lo, span.hi(), false, @@ -407,7 +407,7 @@ where .trailing_separator(trailing_separator) .ends_with_newline(tactic.ends_with_newline(context.config.indent_style())) .preserve_newline(true); - (write_list(&item_vec, &fmt).unknown_error()?, tactic) + (write_list(&item_vec, &fmt)?, tactic) }; let args = if tactic == DefinitiveListTactic::Horizontal diff --git a/src/vertical.rs b/src/vertical.rs index 691759803e5..670fa5a21e4 100644 --- a/src/vertical.rs +++ b/src/vertical.rs @@ -228,11 +228,7 @@ fn rewrite_aligned_items_inner( ",", |field| field.get_span().lo(), |field| field.get_span().hi(), - |field| { - field - .rewrite_aligned_item(context, item_shape, field_prefix_max_width) - .ok() - }, + |field| field.rewrite_aligned_item(context, item_shape, field_prefix_max_width), span.lo(), span.hi(), false, @@ -248,14 +244,13 @@ fn rewrite_aligned_items_inner( if tactic == DefinitiveListTactic::Horizontal { // since the items fits on a line, there is no need to align them - let do_rewrite = |field: &T| -> Option { - field.rewrite_aligned_item(context, item_shape, 0).ok() - }; + let do_rewrite = + |field: &T| -> RewriteResult { field.rewrite_aligned_item(context, item_shape, 0) }; fields .iter() .zip(items.iter_mut()) .for_each(|(field, list_item): (&T, &mut ListItem)| { - if list_item.item.is_some() { + if list_item.item.is_ok() { list_item.item = do_rewrite(field); } }); @@ -271,7 +266,7 @@ fn rewrite_aligned_items_inner( .tactic(tactic) .trailing_separator(separator_tactic) .preserve_newline(true); - write_list(&items, &fmt) + write_list(&items, &fmt).ok() } /// Returns the index in `fields` up to which a field belongs to the current group.