From d122ad5adc2164e34e59a7e9e7e8da2dfba7ffb5 Mon Sep 17 00:00:00 2001 From: Marcus Klaas Date: Sat, 24 Oct 2015 12:19:58 +0200 Subject: [PATCH] Address some issues with multiline patterns in let statements --- src/expr.rs | 16 ++++-- src/items.rs | 116 +++++++++++++++----------------------- src/lib.rs | 8 +++ src/visitor.rs | 8 ++- tests/source/issue-510.rs | 39 +++++++++++++ tests/target/issue-510.rs | 43 ++++++++++++++ 6 files changed, 154 insertions(+), 76 deletions(-) create mode 100644 tests/source/issue-510.rs create mode 100644 tests/target/issue-510.rs diff --git a/src/expr.rs b/src/expr.rs index 20a637bffca..16c46f6bef1 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1398,7 +1398,10 @@ pub fn rewrite_tuple<'a, R>(context: &RewriteContext, |item| item.span().lo, |item| item.span().hi, |item| { - let inner_width = context.config.max_width - indent.width() - 1; + let inner_width = try_opt!(context.config + .max_width + .checked_sub(indent.width() + + 1)); item.rewrite(context, inner_width, indent) }, span.lo + BytePos(1), // Remove parens @@ -1522,10 +1525,15 @@ pub fn rewrite_assign_rhs>(context: &RewriteContext, offset: Indent) -> Option { let mut result = lhs.into(); - + let last_line_width = last_line_width(&result) - + if result.contains('\n') { + offset.width() + } else { + 0 + }; // 1 = space between operator and rhs. - let max_width = try_opt!(width.checked_sub(result.len() + 1)); - let rhs = ex.rewrite(&context, max_width, offset + result.len() + 1); + let max_width = try_opt!(width.checked_sub(last_line_width + 1)); + let rhs = ex.rewrite(&context, max_width, offset + last_line_width + 1); match rhs { Some(new_str) => { diff --git a/src/items.rs b/src/items.rs index c8054b8d01f..e6b401d2ff3 100644 --- a/src/items.rs +++ b/src/items.rs @@ -26,85 +26,59 @@ use syntax::codemap::{Span, BytePos, mk_sp}; use syntax::print::pprust; use syntax::parse::token; -impl<'a> FmtVisitor<'a> { - pub fn visit_let(&mut self, local: &ast::Local, span: Span) { - self.format_missing_with_indent(span.lo); +// Statements of the form +// let pat: ty = init; +impl Rewrite for ast::Local { + fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + let mut result = "let ".to_owned(); + let pattern_offset = offset + result.len(); + // 1 = ; + let pattern_width = try_opt!(width.checked_sub(pattern_offset.width() + 1)); - // New scope so we drop the borrow of self (context) in time to mutably - // borrow self to mutate its buffer. - let result = { - let context = self.get_context(); - let mut result = "let ".to_owned(); - let pattern_offset = self.block_indent + result.len(); - // 1 = ; - let pattern_width = match self.config - .max_width - .checked_sub(pattern_offset.width() + 1) { - Some(width) => width, - None => return, - }; + let pat_str = try_opt!(self.pat.rewrite(&context, pattern_width, pattern_offset)); + result.push_str(&pat_str); - match local.pat.rewrite(&context, pattern_width, pattern_offset) { - Some(ref pat_string) => result.push_str(pat_string), - None => return, + // String that is placed within the assignment pattern and expression. + let infix = { + let mut infix = String::new(); + + if let Some(ref ty) = self.ty { + // 2 = ": ".len() + // 1 = ; + let indent = offset + last_line_width(&result) + 2; + let budget = try_opt!(width.checked_sub(indent.width() + 1)); + let rewrite = try_opt!(ty.rewrite(context, budget, indent)); + + infix.push_str(": "); + infix.push_str(&rewrite); } - // String that is placed within the assignment pattern and expression. - let infix = { - let mut infix = String::new(); - - if let Some(ref ty) = local.ty { - // 2 = ": ".len() - // 1 = ; - let offset = self.block_indent + result.len() + 2; - let width = match self.config.max_width.checked_sub(offset.width() + 1) { - Some(w) => w, - None => return, - }; - let rewrite = ty.rewrite(&self.get_context(), width, offset); - - match rewrite { - Some(result) => { - infix.push_str(": "); - infix.push_str(&result); - } - None => return, - } - } - - if local.init.is_some() { - infix.push_str(" ="); - } - - infix - }; - - result.push_str(&infix); - - if let Some(ref ex) = local.init { - let max_width = self.config.max_width.checked_sub(context.block_indent.width() + 1); - let max_width = match max_width { - Some(width) => width, - None => return, - }; - - // 1 = trailing semicolon; - let rhs = rewrite_assign_rhs(&context, result, ex, max_width, context.block_indent); - - match rhs { - Some(s) => s, - None => return, - } - } else { - result + if self.init.is_some() { + infix.push_str(" ="); } + + infix }; - self.buffer.push_str(&result); - self.buffer.push_str(";"); - self.last_pos = span.hi; - } + result.push_str(&infix); + if let Some(ref ex) = self.init { + let budget = try_opt!(width.checked_sub(context.block_indent.width() + 1)); + + // 1 = trailing semicolon; + result = try_opt!(rewrite_assign_rhs(&context, + result, + ex, + budget, + context.block_indent)); + } + + result.push(';'); + Some(result) + } +} + +impl<'a> FmtVisitor<'a> { pub fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) { self.buffer.push_str("extern "); diff --git a/src/lib.rs b/src/lib.rs index 33753524348..a22e797fb68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -168,6 +168,14 @@ impl Add for Indent { } } +impl Sub for Indent { + type Output = Indent; + + fn sub(self, rhs: usize) -> Indent { + Indent::new(self.block_indent, self.alignment - rhs) + } +} + #[derive(Copy, Clone)] pub enum WriteMode { // Backups the original file and overwrites the orignal. diff --git a/src/visitor.rs b/src/visitor.rs index 9a33fdae024..bd30e80e5a9 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -37,7 +37,13 @@ impl<'a> FmtVisitor<'a> { match stmt.node { ast::Stmt_::StmtDecl(ref decl, _) => { match decl.node { - ast::Decl_::DeclLocal(ref local) => self.visit_let(local, stmt.span), + ast::Decl_::DeclLocal(ref local) => { + let rewrite = { + let context = self.get_context(); + local.rewrite(&context, self.config.max_width, self.block_indent) + }; + self.push_rewrite(stmt.span, rewrite); + } ast::Decl_::DeclItem(ref item) => self.visit_item(item), } } diff --git a/tests/source/issue-510.rs b/tests/source/issue-510.rs new file mode 100644 index 00000000000..faf3d657ada --- /dev/null +++ b/tests/source/issue-510.rs @@ -0,0 +1,39 @@ +impl ISizeAndMarginsComputer for AbsoluteNonReplaced { +fn solve_inline_size_constraints(&self, +block: &mut BlockFlow, +input: &ISizeConstraintInput) +-> ISizeConstraintSolution { + +let (inline_start,inline_size,margin_inline_start,margin_inline_end) = +match (inline_startssssssxxxxxxsssssxxxxxxxxxssssssxxx,inline_startssssssxxxxxxsssssxxxxxxxxxssssssxxx) { +(MaybeAuto::Auto, MaybeAuto::Auto, MaybeAuto::Auto) => { +let margin_start = inline_start_margin.specified_or_zero(); +let margin_end = inline_end_margin.specified_or_zero(); +// Now it is the same situation as inline-start Specified and inline-end +// and inline-size Auto. +// +// Set inline-end to zero to calculate inline-size. +let inline_size = block.get_shrink_to_fit_inline_size(available_inline_size - +(margin_start + margin_end)); +(Au(0), inline_size, margin_start, margin_end) +} +}; + +// FIXME(#501): tuple width heuristic may not be optimal for patterns. + let (inline_start, inline_size, margin_inline_start, margin_inline_end) = + match (inline_start, inline_end, computed_inline_size) { + (MaybeAuto::Auto, MaybeAuto::Auto, MaybeAuto::Auto) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + // Now it is the same situation as inline-start Specified and inline-end + // and inline-size Auto. + // + // Set inline-end to zero to calculate inline-size. + let inline_size = + block.get_shrink_to_fit_inline_size(available_inline_size - + (margin_start + margin_end)); + (Au(0), inline_size, margin_start, margin_end) + } + }; +} +} diff --git a/tests/target/issue-510.rs b/tests/target/issue-510.rs new file mode 100644 index 00000000000..5b427ef1402 --- /dev/null +++ b/tests/target/issue-510.rs @@ -0,0 +1,43 @@ +impl ISizeAndMarginsComputer for AbsoluteNonReplaced { + fn solve_inline_size_constraints(&self, + block: &mut BlockFlow, + input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + + let (inline_start, + inline_size, + margin_inline_start, + margin_inline_end) = match (inline_startssssssxxxxxxsssssxxxxxxxxxssssssxxx, + inline_startssssssxxxxxxsssssxxxxxxxxxssssssxxx) { + (MaybeAuto::Auto, MaybeAuto::Auto, MaybeAuto::Auto) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + // Now it is the same situation as inline-start Specified and inline-end + // and inline-size Auto. + // + // Set inline-end to zero to calculate inline-size. + let inline_size = block.get_shrink_to_fit_inline_size(available_inline_size - + (margin_start + margin_end)); + (Au(0), inline_size, margin_start, margin_end) + } + }; + + // FIXME(#501): tuple width heuristic may not be optimal for patterns. + let (inline_start, + inline_size, + margin_inline_start, + margin_inline_end) = match (inline_start, inline_end, computed_inline_size) { + (MaybeAuto::Auto, MaybeAuto::Auto, MaybeAuto::Auto) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + // Now it is the same situation as inline-start Specified and inline-end + // and inline-size Auto. + // + // Set inline-end to zero to calculate inline-size. + let inline_size = block.get_shrink_to_fit_inline_size(available_inline_size - + (margin_start + margin_end)); + (Au(0), inline_size, margin_start, margin_end) + } + }; + } +}