about summary refs log tree commit diff
diff options
context:
space:
mode:
authording-young <lsyhime@snu.ac.kr>2024-07-18 18:02:34 +0900
committerYacin Tmimi <yacintmimi@gmail.com>2024-07-26 03:53:21 -0600
commite21c1e220bdc6748e33b67e00394dd23c46a1a3d (patch)
tree26dd9dc346c8d13a537b86844013ad87542ab9da
parent1313d61842321e5feeed9bc653739ec75fe1034c (diff)
downloadrust-e21c1e220bdc6748e33b67e00394dd23c46a1a3d.tar.gz
rust-e21c1e220bdc6748e33b67e00394dd23c46a1a3d.zip
refactor rewrite_array, pair, tuple, call
-rw-r--r--src/attr.rs26
-rw-r--r--src/chains.rs11
-rw-r--r--src/expr.rs60
-rw-r--r--src/items.rs5
-rw-r--r--src/macros.rs4
-rw-r--r--src/overflow.rs14
-rw-r--r--src/pairs.rs97
-rw-r--r--src/patterns.rs41
-rw-r--r--src/spanned.rs7
-rw-r--r--src/types.rs9
10 files changed, 171 insertions, 103 deletions
diff --git a/src/attr.rs b/src/attr.rs
index c47d7a2a2f1..2679b1b6e7a 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -11,7 +11,7 @@ use crate::config::IndentStyle;
 use crate::expr::rewrite_literal;
 use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
 use crate::overflow;
-use crate::rewrite::{Rewrite, RewriteContext};
+use crate::rewrite::{Rewrite, RewriteContext, RewriteErrorExt};
 use crate::shape::Shape;
 use crate::source_map::SpanUtils;
 use crate::types::{rewrite_path, PathContext};
@@ -274,20 +274,27 @@ fn has_newlines_before_after_comment(comment: &str) -> (&str, &str) {
 
 impl Rewrite for ast::MetaItem {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
-        Some(match self.kind {
+        self.rewrite_result(context, shape).ok()
+    }
+
+    fn rewrite_result(
+        &self,
+        context: &RewriteContext<'_>,
+        shape: Shape,
+    ) -> crate::rewrite::RewriteResult {
+        Ok(match self.kind {
             ast::MetaItemKind::Word => {
-                rewrite_path(context, PathContext::Type, &None, &self.path, shape).ok()?
+                rewrite_path(context, PathContext::Type, &None, &self.path, shape)?
             }
             ast::MetaItemKind::List(ref list) => {
-                let path =
-                    rewrite_path(context, PathContext::Type, &None, &self.path, shape).ok()?;
+                let path = rewrite_path(context, PathContext::Type, &None, &self.path, shape)?;
                 let has_trailing_comma = crate::expr::span_ends_with_comma(context, self.span);
                 overflow::rewrite_with_parens(
                     context,
                     &path,
                     list.iter(),
                     // 1 = "]"
-                    shape.sub_width(1)?,
+                    shape.sub_width(1).max_width_error(shape.width, self.span)?,
                     self.span,
                     context.config.attr_fn_like_width(),
                     Some(if has_trailing_comma {
@@ -298,10 +305,11 @@ impl Rewrite for ast::MetaItem {
                 )?
             }
             ast::MetaItemKind::NameValue(ref lit) => {
-                let path =
-                    rewrite_path(context, PathContext::Type, &None, &self.path, shape).ok()?;
+                let path = rewrite_path(context, PathContext::Type, &None, &self.path, shape)?;
                 // 3 = ` = `
-                let lit_shape = shape.shrink_left(path.len() + 3)?;
+                let lit_shape = shape
+                    .shrink_left(path.len() + 3)
+                    .max_width_error(shape.width, self.span)?;
                 // `rewrite_literal` returns `None` when `lit` exceeds max
                 // width. Since a literal is basically unformattable unless it
                 // is a string literal (and only if `format_strings` is set),
diff --git a/src/chains.rs b/src/chains.rs
index ea23690caed..2458e2b6b58 100644
--- a/src/chains.rs
+++ b/src/chains.rs
@@ -66,7 +66,7 @@ use crate::config::{IndentStyle, Version};
 use crate::expr::rewrite_call;
 use crate::lists::extract_pre_comment;
 use crate::macros::convert_try_mac;
-use crate::rewrite::{Rewrite, RewriteContext};
+use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteResult};
 use crate::shape::Shape;
 use crate::source_map::SpanUtils;
 use crate::utils::{
@@ -279,7 +279,8 @@ impl Rewrite for ChainItem {
                 parens: false,
             } => expr.rewrite(context, shape)?,
             ChainItemKind::MethodCall(ref segment, ref types, ref exprs) => {
-                Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)?
+                Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)
+                    .ok()?
             }
             ChainItemKind::StructField(ident) => format!(".{}", rewrite_ident(context, ident)),
             ChainItemKind::TupleField(ident, nested) => format!(
@@ -326,14 +327,14 @@ impl ChainItem {
         span: Span,
         context: &RewriteContext<'_>,
         shape: Shape,
-    ) -> Option<String> {
+    ) -> RewriteResult {
         let type_str = if types.is_empty() {
             String::new()
         } else {
             let type_list = types
                 .iter()
-                .map(|ty| ty.rewrite(context, shape))
-                .collect::<Option<Vec<_>>>()?;
+                .map(|ty| ty.rewrite_result(context, shape))
+                .collect::<Result<Vec<_>, RewriteError>>()?;
 
             format!("::<{}>", type_list.join(", "))
         };
diff --git a/src/expr.rs b/src/expr.rs
index b73b3348b3e..ebbeeee4ae1 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -79,7 +79,8 @@ pub(crate) fn format_expr(
             shape,
             choose_separator_tactic(context, expr.span),
             None,
-        ),
+        )
+        .ok(),
         ast::ExprKind::Lit(token_lit) => {
             if let Some(expr_rw) = rewrite_literal(context, token_lit, expr.span, shape) {
                 Some(expr_rw)
@@ -94,21 +95,23 @@ pub(crate) fn format_expr(
         ast::ExprKind::Call(ref callee, ref args) => {
             let inner_span = mk_sp(callee.span.hi(), expr.span.hi());
             let callee_str = callee.rewrite(context, shape)?;
-            rewrite_call(context, &callee_str, args, inner_span, shape)
+            rewrite_call(context, &callee_str, args, inner_span, shape).ok()
         }
         ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape, expr.span),
         ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
             // FIXME: format comments between operands and operator
-            rewrite_all_pairs(expr, shape, context).or_else(|| {
-                rewrite_pair(
-                    &**lhs,
-                    &**rhs,
-                    PairParts::infix(&format!(" {} ", context.snippet(op.span))),
-                    context,
-                    shape,
-                    context.config.binop_separator(),
-                )
-            })
+            rewrite_all_pairs(expr, shape, context)
+                .or_else(|_| {
+                    rewrite_pair(
+                        &**lhs,
+                        &**rhs,
+                        PairParts::infix(&format!(" {} ", context.snippet(op.span))),
+                        context,
+                        shape,
+                        context.config.binop_separator(),
+                    )
+                })
+                .ok()
         }
         ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
         ast::ExprKind::Struct(ref struct_expr) => {
@@ -131,7 +134,7 @@ pub(crate) fn format_expr(
             .ok()
         }
         ast::ExprKind::Tup(ref items) => {
-            rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1)
+            rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1).ok()
         }
         ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr),
         ast::ExprKind::If(..)
@@ -265,7 +268,8 @@ pub(crate) fn format_expr(
             context,
             shape,
             SeparatorPlace::Front,
-        ),
+        )
+        .ok(),
         ast::ExprKind::Index(ref expr, ref index, _) => {
             rewrite_index(&**expr, &**index, context, shape)
         }
@@ -276,7 +280,8 @@ pub(crate) fn format_expr(
             context,
             shape,
             SeparatorPlace::Back,
-        ),
+        )
+        .ok(),
         ast::ExprKind::Range(ref lhs, ref rhs, limits) => {
             let delim = match limits {
                 ast::RangeLimits::HalfOpen => "..",
@@ -329,6 +334,7 @@ pub(crate) fn format_expr(
                         shape,
                         context.config.binop_separator(),
                     )
+                    .ok()
                 }
                 (None, Some(rhs)) => {
                     let sp_delim = if context.config.spaces_around_ranges() {
@@ -442,7 +448,7 @@ pub(crate) fn rewrite_array<'a, T: 'a + IntoOverflowableItem<'a>>(
     shape: Shape,
     force_separator_tactic: Option<SeparatorTactic>,
     delim_token: Option<Delimiter>,
-) -> Option<String> {
+) -> RewriteResult {
     overflow::rewrite_with_square_brackets(
         context,
         name,
@@ -1346,7 +1352,7 @@ pub(crate) fn rewrite_call(
     args: &[ptr::P<ast::Expr>],
     span: Span,
     shape: Shape,
-) -> Option<String> {
+) -> RewriteResult {
     overflow::rewrite_with_parens(
         context,
         callee,
@@ -1830,21 +1836,27 @@ fn rewrite_tuple_in_visual_indent_style<'a, T: 'a + IntoOverflowableItem<'a>>(
     span: Span,
     shape: Shape,
     is_singleton_tuple: bool,
-) -> Option<String> {
+) -> RewriteResult {
     // In case of length 1, need a trailing comma
     debug!("rewrite_tuple_in_visual_indent_style {:?}", shape);
     if is_singleton_tuple {
         // 3 = "(" + ",)"
-        let nested_shape = shape.sub_width(3)?.visual_indent(1);
+        let nested_shape = shape
+            .sub_width(3)
+            .max_width_error(shape.width, span)?
+            .visual_indent(1);
         return items
             .next()
             .unwrap()
-            .rewrite(context, nested_shape)
+            .rewrite_result(context, nested_shape)
             .map(|s| format!("({},)", s));
     }
 
     let list_lo = context.snippet_provider.span_after(span, "(");
-    let nested_shape = shape.sub_width(2)?.visual_indent(1);
+    let nested_shape = shape
+        .sub_width(2)
+        .max_width_error(shape.width, span)?
+        .visual_indent(1);
     let items = itemize_list(
         context.snippet_provider,
         items,
@@ -1867,9 +1879,9 @@ 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).ok()?;
+    let list_str = write_list(&item_vec, &fmt)?;
 
-    Some(format!("({list_str})"))
+    Ok(format!("({list_str})"))
 }
 
 fn rewrite_let(
@@ -1912,7 +1924,7 @@ pub(crate) fn rewrite_tuple<'a, T: 'a + IntoOverflowableItem<'a>>(
     span: Span,
     shape: Shape,
     is_singleton_tuple: bool,
-) -> Option<String> {
+) -> RewriteResult {
     debug!("rewrite_tuple {:?}", shape);
     if context.use_block_indent() {
         // We use the same rule as function calls for rewriting tuples.
diff --git a/src/items.rs b/src/items.rs
index 0bb27839ed3..a9f86c6b7d6 100644
--- a/src/items.rs
+++ b/src/items.rs
@@ -1646,7 +1646,8 @@ fn format_tuple_struct(
             mk_sp(lo, span.hi()),
             context.config.fn_call_width(),
             None,
-        )?;
+        )
+        .ok()?;
     }
 
     if !where_clause_str.is_empty()
@@ -2912,7 +2913,7 @@ fn rewrite_generics(
     }
 
     let params = generics.params.iter();
-    overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span)
+    overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span).ok()
 }
 
 fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
diff --git a/src/macros.rs b/src/macros.rs
index a948aaba083..e08146a1f33 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -283,6 +283,7 @@ fn rewrite_macro_inner(
                         Some(SeparatorTactic::Never)
                     },
                 )
+                .ok()
                 .map(|rw| match position {
                     MacroPosition::Item => format!("{};", rw),
                     _ => rw,
@@ -316,7 +317,8 @@ fn rewrite_macro_inner(
                     shape,
                     force_trailing_comma,
                     Some(original_style),
-                )?;
+                )
+                .ok()?;
                 let comma = match position {
                     MacroPosition::Item => ";",
                     _ => "",
diff --git a/src/overflow.rs b/src/overflow.rs
index 1a0d8bf15f6..add86799132 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, RewriteErrorExt};
+use crate::rewrite::{Rewrite, RewriteContext, RewriteErrorExt, RewriteResult};
 use crate::shape::Shape;
 use crate::source_map::SpanUtils;
 use crate::spanned::Spanned;
@@ -277,7 +277,7 @@ pub(crate) fn rewrite_with_parens<'a, T: 'a + IntoOverflowableItem<'a>>(
     span: Span,
     item_max_width: usize,
     force_separator_tactic: Option<SeparatorTactic>,
-) -> Option<String> {
+) -> RewriteResult {
     Context::new(
         context,
         items,
@@ -299,7 +299,7 @@ pub(crate) fn rewrite_with_angle_brackets<'a, T: 'a + IntoOverflowableItem<'a>>(
     items: impl Iterator<Item = &'a T>,
     shape: Shape,
     span: Span,
-) -> Option<String> {
+) -> RewriteResult {
     Context::new(
         context,
         items,
@@ -323,7 +323,7 @@ pub(crate) fn rewrite_with_square_brackets<'a, T: 'a + IntoOverflowableItem<'a>>
     span: Span,
     force_separator_tactic: Option<SeparatorTactic>,
     delim_token: Option<Delimiter>,
-) -> Option<String> {
+) -> RewriteResult {
     let (lhs, rhs) = match delim_token {
         Some(Delimiter::Parenthesis) => ("(", ")"),
         Some(Delimiter::Brace) => ("{", "}"),
@@ -712,8 +712,8 @@ impl<'a> Context<'a> {
         result
     }
 
-    fn rewrite(&self, shape: Shape) -> Option<String> {
-        let (extendable, items_str) = self.rewrite_items()?;
+    fn rewrite(&self, shape: Shape) -> RewriteResult {
+        let (extendable, items_str) = self.rewrite_items().unknown_error()?;
 
         // If we are using visual indent style and failed to format, retry with block indent.
         if !self.context.use_block_indent()
@@ -726,7 +726,7 @@ impl<'a> Context<'a> {
             return result;
         }
 
-        Some(self.wrap_items(&items_str, shape, extendable))
+        Ok(self.wrap_items(&items_str, shape, extendable))
     }
 }
 
diff --git a/src/pairs.rs b/src/pairs.rs
index bfc2ffed383..5a7d9c8aaa4 100644
--- a/src/pairs.rs
+++ b/src/pairs.rs
@@ -1,9 +1,11 @@
 use rustc_ast::ast;
+use rustc_span::Span;
 
 use crate::config::lists::*;
 use crate::config::IndentStyle;
-use crate::rewrite::{Rewrite, RewriteContext};
+use crate::rewrite::{Rewrite, RewriteContext, RewriteErrorExt, RewriteResult};
 use crate::shape::Shape;
+use crate::spanned::Spanned;
 use crate::utils::{
     first_line_width, is_single_line, last_line_width, trimmed_last_line_width, wrap_str,
 };
@@ -40,16 +42,19 @@ pub(crate) fn rewrite_all_pairs(
     expr: &ast::Expr,
     shape: Shape,
     context: &RewriteContext<'_>,
-) -> Option<String> {
-    expr.flatten(context, shape).and_then(|list| {
-        if list.let_chain_count() > 0 && !list.can_rewrite_let_chain_single_line() {
-            rewrite_pairs_multiline(&list, shape, context)
-        } else {
-            // First we try formatting on one line.
-            rewrite_pairs_one_line(&list, shape, context)
-                .or_else(|| rewrite_pairs_multiline(&list, shape, context))
-        }
-    })
+) -> RewriteResult {
+    expr.flatten(context, shape)
+        .unknown_error()
+        .and_then(|list| {
+            if list.let_chain_count() > 0 && !list.can_rewrite_let_chain_single_line() {
+                rewrite_pairs_multiline(&list, shape, context)
+            } else {
+                // First we try formatting on one line.
+                rewrite_pairs_one_line(&list, shape, context)
+                    .unknown_error()
+                    .or_else(|_| rewrite_pairs_multiline(&list, shape, context))
+            }
+        })
 }
 
 // This may return a multi-line result since we allow the last expression to go
@@ -65,7 +70,7 @@ fn rewrite_pairs_one_line<T: Rewrite>(
     let base_shape = shape.block();
 
     for ((_, rewrite), s) in list.list.iter().zip(list.separators.iter()) {
-        if let Some(rewrite) = rewrite {
+        if let Ok(rewrite) = rewrite {
             if !is_single_line(rewrite) || result.len() > shape.width {
                 return None;
             }
@@ -104,19 +109,20 @@ fn rewrite_pairs_multiline<T: Rewrite>(
     list: &PairList<'_, '_, T>,
     shape: Shape,
     context: &RewriteContext<'_>,
-) -> Option<String> {
+) -> RewriteResult {
     let rhs_offset = shape.rhs_overhead(context.config);
     let nested_shape = (match context.config.indent_style() {
         IndentStyle::Visual => shape.visual_indent(0),
         IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
     })
     .with_max_width(context.config)
-    .sub_width(rhs_offset)?;
+    .sub_width(rhs_offset)
+    .max_width_error(shape.width, list.span)?;
 
     let indent_str = nested_shape.indent.to_string_with_newline(context.config);
     let mut result = String::new();
 
-    result.push_str(list.list[0].1.as_ref()?);
+    result.push_str(list.list[0].1.as_ref().map_err(|err| err.clone())?);
 
     for ((e, default_rw), s) in list.list[1..].iter().zip(list.separators.iter()) {
         // The following test checks if we should keep two subexprs on the same
@@ -132,7 +138,7 @@ fn rewrite_pairs_multiline<T: Rewrite>(
             if let Some(line_shape) =
                 shape.offset_left(s.len() + 2 + trimmed_last_line_width(&result))
             {
-                if let Some(rewrite) = e.rewrite(context, line_shape) {
+                if let Ok(rewrite) = e.rewrite_result(context, line_shape) {
                     result.push(' ');
                     result.push_str(s);
                     result.push(' ');
@@ -155,9 +161,9 @@ fn rewrite_pairs_multiline<T: Rewrite>(
             }
         }
 
-        result.push_str(default_rw.as_ref()?);
+        result.push_str(default_rw.as_ref().map_err(|err| err.clone())?);
     }
-    Some(result)
+    Ok(result)
 }
 
 // Rewrites a single pair.
@@ -168,10 +174,10 @@ pub(crate) fn rewrite_pair<LHS, RHS>(
     context: &RewriteContext<'_>,
     shape: Shape,
     separator_place: SeparatorPlace,
-) -> Option<String>
+) -> RewriteResult
 where
-    LHS: Rewrite,
-    RHS: Rewrite,
+    LHS: Rewrite + Spanned,
+    RHS: Rewrite + Spanned,
 {
     let tab_spaces = context.config.tab_spaces();
     let lhs_overhead = match separator_place {
@@ -183,15 +189,17 @@ where
         ..shape
     };
     let lhs_result = lhs
-        .rewrite(context, lhs_shape)
+        .rewrite_result(context, lhs_shape)
         .map(|lhs_str| format!("{}{}", pp.prefix, lhs_str))?;
 
     // Try to put both lhs and rhs on the same line.
     let rhs_orig_result = shape
         .offset_left(last_line_width(&lhs_result) + pp.infix.len())
         .and_then(|s| s.sub_width(pp.suffix.len()))
-        .and_then(|rhs_shape| rhs.rewrite(context, rhs_shape));
-    if let Some(ref rhs_result) = rhs_orig_result {
+        .max_width_error(shape.width, rhs.span())
+        .and_then(|rhs_shape| rhs.rewrite_result(context, rhs_shape));
+
+    if let Ok(ref rhs_result) = rhs_orig_result {
         // If the length of the lhs is equal to or shorter than the tab width or
         // the rhs looks like block expression, we put the rhs on the same
         // line with the lhs even if the rhs is multi-lined.
@@ -207,7 +215,7 @@ where
                 + first_line_width(rhs_result)
                 + pp.suffix.len();
             if one_line_width <= shape.width {
-                return Some(format!(
+                return Ok(format!(
                     "{}{}{}{}",
                     lhs_result, pp.infix, rhs_result, pp.suffix
                 ));
@@ -219,13 +227,15 @@ where
     // Re-evaluate the rhs because we have more space now:
     let mut rhs_shape = match context.config.indent_style() {
         IndentStyle::Visual => shape
-            .sub_width(pp.suffix.len() + pp.prefix.len())?
+            .sub_width(pp.suffix.len() + pp.prefix.len())
+            .max_width_error(shape.width, rhs.span())?
             .visual_indent(pp.prefix.len()),
         IndentStyle::Block => {
             // Try to calculate the initial constraint on the right hand side.
             let rhs_overhead = shape.rhs_overhead(context.config);
             Shape::indented(shape.indent.block_indent(context.config), context.config)
-                .sub_width(rhs_overhead)?
+                .sub_width(rhs_overhead)
+                .max_width_error(shape.width, rhs.span())?
         }
     };
     let infix = match separator_place {
@@ -233,15 +243,17 @@ where
         SeparatorPlace::Front => pp.infix.trim_start(),
     };
     if separator_place == SeparatorPlace::Front {
-        rhs_shape = rhs_shape.offset_left(infix.len())?;
+        rhs_shape = rhs_shape
+            .offset_left(infix.len())
+            .max_width_error(rhs_shape.width, rhs.span())?;
     }
-    let rhs_result = rhs.rewrite(context, rhs_shape)?;
+    let rhs_result = rhs.rewrite_result(context, rhs_shape)?;
     let indent_str = rhs_shape.indent.to_string_with_newline(context.config);
     let infix_with_sep = match separator_place {
         SeparatorPlace::Back => format!("{infix}{indent_str}"),
         SeparatorPlace::Front => format!("{indent_str}{infix}"),
     };
-    Some(format!(
+    Ok(format!(
         "{}{}{}{}",
         lhs_result, infix_with_sep, rhs_result, pp.suffix
     ))
@@ -255,8 +267,9 @@ trait FlattenPair: Rewrite + Sized {
 }
 
 struct PairList<'a, 'b, T: Rewrite> {
-    list: Vec<(&'b T, Option<String>)>,
+    list: Vec<(&'b T, RewriteResult)>,
     separators: Vec<&'a str>,
+    span: Span,
 }
 
 fn is_ident(expr: &ast::Expr) -> bool {
@@ -303,7 +316,7 @@ impl FlattenPair for ast::Expr {
 
         let default_rewrite = |node: &ast::Expr, sep: usize, is_first: bool| {
             if is_first {
-                return node.rewrite(context, shape);
+                return node.rewrite_result(context, shape);
             }
             let nested_overhead = sep + 1;
             let rhs_offset = shape.rhs_overhead(context.config);
@@ -312,12 +325,17 @@ impl FlattenPair for ast::Expr {
                 IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
             })
             .with_max_width(context.config)
-            .sub_width(rhs_offset)?;
+            .sub_width(rhs_offset)
+            .max_width_error(shape.width, node.span)?;
             let default_shape = match context.config.binop_separator() {
-                SeparatorPlace::Back => nested_shape.sub_width(nested_overhead)?,
-                SeparatorPlace::Front => nested_shape.offset_left(nested_overhead)?,
+                SeparatorPlace::Back => nested_shape
+                    .sub_width(nested_overhead)
+                    .max_width_error(nested_shape.width, node.span)?,
+                SeparatorPlace::Front => nested_shape
+                    .offset_left(nested_overhead)
+                    .max_width_error(nested_shape.width, node.span)?,
             };
-            node.rewrite(context, default_shape)
+            node.rewrite_result(context, default_shape)
         };
 
         // Turn a tree of binop expressions into a list using a depth-first,
@@ -326,6 +344,7 @@ impl FlattenPair for ast::Expr {
         let mut list = vec![];
         let mut separators = vec![];
         let mut node = self;
+        let span = self.span();
         loop {
             match node.kind {
                 ast::ExprKind::Binary(op, ref lhs, _) if op.node == top_op => {
@@ -352,7 +371,11 @@ impl FlattenPair for ast::Expr {
         }
 
         assert_eq!(list.len() - 1, separators.len());
-        Some(PairList { list, separators })
+        Some(PairList {
+            list,
+            separators,
+            span,
+        })
     }
 }
 
diff --git a/src/patterns.rs b/src/patterns.rs
index df435a3069d..ba97c1d2123 100644
--- a/src/patterns.rs
+++ b/src/patterns.rs
@@ -61,13 +61,20 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
     }
 }
 
-struct RangeOperand<'a>(&'a Option<ptr::P<ast::Expr>>);
+pub(crate) struct RangeOperand<'a> {
+    operand: &'a Option<ptr::P<ast::Expr>>,
+    pub(crate) span: Span,
+}
 
 impl<'a> Rewrite for RangeOperand<'a> {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
-        match &self.0 {
-            None => Some("".to_owned()),
-            Some(ref exp) => exp.rewrite(context, shape),
+        self.rewrite_result(context, shape).ok()
+    }
+
+    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
+        match &self.operand {
+            None => Ok("".to_owned()),
+            Some(ref exp) => exp.rewrite_result(context, shape),
         }
     }
 }
@@ -239,27 +246,38 @@ impl Rewrite for Pat {
                 } else {
                     infix.to_owned()
                 };
+                let lspan = self.span.with_hi(end_kind.span.lo());
+                let rspan = self.span.with_lo(end_kind.span.hi());
                 rewrite_pair(
-                    &RangeOperand(lhs),
-                    &RangeOperand(rhs),
+                    &RangeOperand {
+                        operand: lhs,
+                        span: lspan,
+                    },
+                    &RangeOperand {
+                        operand: rhs,
+                        span: rspan,
+                    },
                     PairParts::infix(&infix),
                     context,
                     shape,
                     SeparatorPlace::Front,
                 )
+                .ok()
             }
             PatKind::Ref(ref pat, mutability) => {
                 let prefix = format!("&{}", format_mutability(mutability));
                 rewrite_unary_prefix(context, &prefix, &**pat, shape)
             }
-            PatKind::Tuple(ref items) => rewrite_tuple_pat(items, None, self.span, context, shape),
+            PatKind::Tuple(ref items) => {
+                rewrite_tuple_pat(items, None, self.span, context, shape).ok()
+            }
             PatKind::Path(ref q_self, ref path) => {
                 rewrite_path(context, PathContext::Expr, q_self, path, shape).ok()
             }
             PatKind::TupleStruct(ref q_self, ref path, ref pat_vec) => {
                 let path_str =
                     rewrite_path(context, PathContext::Expr, q_self, path, shape).ok()?;
-                rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
+                rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape).ok()
             }
             PatKind::Lit(ref expr) => expr.rewrite(context, shape),
             PatKind::Slice(ref slice_pat) if context.config.version() == Version::One => {
@@ -283,7 +301,8 @@ impl Rewrite for Pat {
                 self.span,
                 None,
                 None,
-            ),
+            )
+            .ok(),
             PatKind::Struct(ref qself, ref path, ref fields, rest) => rewrite_struct_pat(
                 qself,
                 path,
@@ -495,9 +514,9 @@ fn rewrite_tuple_pat(
     span: Span,
     context: &RewriteContext<'_>,
     shape: Shape,
-) -> Option<String> {
+) -> RewriteResult {
     if pats.is_empty() {
-        return Some(format!("{}()", path_str.unwrap_or_default()));
+        return Ok(format!("{}()", path_str.unwrap_or_default()));
     }
     let mut pat_vec: Vec<_> = pats.iter().map(TuplePatField::Pat).collect();
 
diff --git a/src/spanned.rs b/src/spanned.rs
index 1ee691b4ade..030495e3ff8 100644
--- a/src/spanned.rs
+++ b/src/spanned.rs
@@ -4,6 +4,7 @@ use rustc_ast::{ast, ptr};
 use rustc_span::{source_map, Span};
 
 use crate::macros::MacroArg;
+use crate::patterns::RangeOperand;
 use crate::utils::{mk_sp, outer_attributes};
 
 /// Spanned returns a span including attributes, if available.
@@ -212,3 +213,9 @@ impl Spanned for ast::PreciseCapturingArg {
         }
     }
 }
+
+impl<'a> Spanned for RangeOperand<'a> {
+    fn span(&self) -> Span {
+        self.span
+    }
+}
diff --git a/src/types.rs b/src/types.rs
index f43c60db02a..eda607c8c9f 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -532,7 +532,6 @@ fn rewrite_generic_args(
                 .collect::<Vec<_>>();
 
             overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
-                .unknown_error()
         }
         ast::GenericArgs::Parenthesized(ref data) => format_function_type(
             data.inputs.iter().map(|x| &**x),
@@ -617,7 +616,6 @@ impl Rewrite for ast::GenericBound {
             }
             ast::GenericBound::Use(ref args, span) => {
                 overflow::rewrite_with_angle_brackets(context, "use", args.iter(), shape, span)
-                    .unknown_error()
             }
             ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite_result(context, shape),
         }
@@ -933,7 +931,6 @@ impl Rewrite for ast::Ty {
             }
             ast::TyKind::Tup(ref items) => {
                 rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
-                    .unknown_error()
             }
             ast::TyKind::AnonStruct(..) => Ok(context.snippet(self.span).to_owned()),
             ast::TyKind::AnonUnion(..) => Ok(context.snippet(self.span).to_owned()),
@@ -947,8 +944,7 @@ impl Rewrite for ast::Ty {
                 context,
                 shape,
                 SeparatorPlace::Back,
-            )
-            .unknown_error(),
+            ),
             ast::TyKind::Infer => {
                 if shape.width >= 1 {
                     Ok("_".to_owned())
@@ -988,8 +984,7 @@ impl Rewrite for ast::Ty {
                 &[anon_const.value.clone()],
                 self.span,
                 shape,
-            )
-            .unknown_error(),
+            ),
             ast::TyKind::Pat(ref ty, ref pat) => {
                 let ty = ty.rewrite_result(context, shape)?;
                 let pat = pat.rewrite_result(context, shape)?;