Skip to content

Commit 520f0d6

Browse files
committed
Format multiple patterns in 'if let' and `while let'
Closes #2511.
1 parent d749532 commit 520f0d6

File tree

1 file changed

+97
-105
lines changed

1 file changed

+97
-105
lines changed

src/expr.rs

Lines changed: 97 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ struct ControlFlow<'a> {
730730
block: &'a ast::Block,
731731
else_block: Option<&'a ast::Expr>,
732732
label: Option<ast::Label>,
733-
pat: Option<&'a ast::Pat>,
733+
pats: Option<Vec<&'a ast::Pat>>,
734734
keyword: &'a str,
735735
matcher: &'a str,
736736
connector: &'a str,
@@ -754,7 +754,7 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow>
754754
ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref else_block) => {
755755
Some(ControlFlow::new_if(
756756
cond,
757-
Some(pat),
757+
Some(ptr_vec_to_ref_vec(pat)),
758758
if_block,
759759
else_block.as_ref().map(|e| &**e),
760760
expr_type == ExprType::SubExpression,
@@ -772,7 +772,7 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow>
772772
Some(ControlFlow::new_while(None, cond, block, label, expr.span))
773773
}
774774
ast::ExprKind::WhileLet(ref pat, ref cond, ref block, label) => Some(
775-
ControlFlow::new_while(Some(pat), cond, block, label, expr.span),
775+
ControlFlow::new_while(Some(ptr_vec_to_ref_vec(pat)), cond, block, label, expr.span),
776776
),
777777
_ => None,
778778
}
@@ -781,24 +781,25 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow>
781781
impl<'a> ControlFlow<'a> {
782782
fn new_if(
783783
cond: &'a ast::Expr,
784-
pat: Option<&'a ast::Pat>,
784+
pats: Option<Vec<&'a ast::Pat>>,
785785
block: &'a ast::Block,
786786
else_block: Option<&'a ast::Expr>,
787787
allow_single_line: bool,
788788
nested_if: bool,
789789
span: Span,
790790
) -> ControlFlow<'a> {
791+
let matcher = match pats {
792+
Some(..) => "let",
793+
None => "",
794+
};
791795
ControlFlow {
792796
cond: Some(cond),
793797
block,
794798
else_block,
795799
label: None,
796-
pat,
800+
pats,
797801
keyword: "if",
798-
matcher: match pat {
799-
Some(..) => "let",
800-
None => "",
801-
},
802+
matcher,
802803
connector: " =",
803804
allow_single_line,
804805
nested_if,
@@ -812,7 +813,7 @@ impl<'a> ControlFlow<'a> {
812813
block,
813814
else_block: None,
814815
label,
815-
pat: None,
816+
pats: None,
816817
keyword: "loop",
817818
matcher: "",
818819
connector: "",
@@ -823,23 +824,24 @@ impl<'a> ControlFlow<'a> {
823824
}
824825

825826
fn new_while(
826-
pat: Option<&'a ast::Pat>,
827+
pats: Option<Vec<&'a ast::Pat>>,
827828
cond: &'a ast::Expr,
828829
block: &'a ast::Block,
829830
label: Option<ast::Label>,
830831
span: Span,
831832
) -> ControlFlow<'a> {
833+
let matcher = match pats {
834+
Some(..) => "let",
835+
None => "",
836+
};
832837
ControlFlow {
833838
cond: Some(cond),
834839
block,
835840
else_block: None,
836841
label,
837-
pat,
842+
pats,
838843
keyword: "while",
839-
matcher: match pat {
840-
Some(..) => "let",
841-
None => "",
842-
},
844+
matcher,
843845
connector: " =",
844846
allow_single_line: false,
845847
nested_if: false,
@@ -859,7 +861,7 @@ impl<'a> ControlFlow<'a> {
859861
block,
860862
else_block: None,
861863
label,
862-
pat: Some(pat),
864+
pats: Some(vec![pat]),
863865
keyword: "for",
864866
matcher: "",
865867
connector: " in",
@@ -914,6 +916,46 @@ impl<'a> ControlFlow<'a> {
914916
}
915917

916918
impl<'a> ControlFlow<'a> {
919+
fn rewrite_pat_expr(
920+
&self,
921+
context: &RewriteContext,
922+
expr: &ast::Expr,
923+
shape: Shape,
924+
offset: usize,
925+
) -> Option<String> {
926+
debug!("rewrite_pat_expr {:?} {:?} {:?}", shape, self.pats, expr);
927+
928+
let cond_shape = shape.offset_left(offset)?;
929+
if let Some(ref pat) = self.pats {
930+
let matcher = if self.matcher.is_empty() {
931+
self.matcher.to_owned()
932+
} else {
933+
format!("{} ", self.matcher)
934+
};
935+
let pat_shape = cond_shape
936+
.offset_left(matcher.len())?
937+
.sub_width(self.connector.len())?;
938+
let pat_string = rewrite_multiple_patterns(context, pat, pat_shape)?;
939+
let result = format!("{}{}{}", matcher, pat_string, self.connector);
940+
return rewrite_assign_rhs(context, result, expr, cond_shape);
941+
}
942+
943+
let expr_rw = expr.rewrite(context, cond_shape);
944+
// The expression may (partially) fit on the current line.
945+
// We do not allow splitting between `if` and condition.
946+
if self.keyword == "if" || expr_rw.is_some() {
947+
return expr_rw;
948+
}
949+
950+
// The expression won't fit on the current line, jump to next.
951+
let nested_shape = shape
952+
.block_indent(context.config.tab_spaces())
953+
.with_max_width(context.config);
954+
let nested_indent_str = nested_shape.indent.to_string_with_newline(context.config);
955+
expr.rewrite(context, nested_shape)
956+
.map(|expr_rw| format!("{}{}", nested_indent_str, expr_rw))
957+
}
958+
917959
fn rewrite_cond(
918960
&self,
919961
context: &RewriteContext,
@@ -922,11 +964,7 @@ impl<'a> ControlFlow<'a> {
922964
) -> Option<(String, usize)> {
923965
// Do not take the rhs overhead from the upper expressions into account
924966
// when rewriting pattern.
925-
let new_width = context
926-
.config
927-
.max_width()
928-
.checked_sub(shape.used_width())
929-
.unwrap_or(0);
967+
let new_width = context.budget(shape.used_width());
930968
let fresh_shape = Shape {
931969
width: new_width,
932970
..shape
@@ -944,16 +982,7 @@ impl<'a> ControlFlow<'a> {
944982
let offset = self.keyword.len() + label_string.len() + 1;
945983

946984
let pat_expr_string = match self.cond {
947-
Some(cond) => rewrite_pat_expr(
948-
context,
949-
self.pat,
950-
cond,
951-
self.matcher,
952-
self.connector,
953-
self.keyword,
954-
constr_shape,
955-
offset,
956-
)?,
985+
Some(cond) => self.rewrite_pat_expr(context, cond, constr_shape, offset)?,
957986
None => String::new(),
958987
};
959988

@@ -1007,9 +1036,9 @@ impl<'a> ControlFlow<'a> {
10071036
context
10081037
.snippet_provider
10091038
.span_after(mk_sp(lo, self.span.hi()), self.keyword.trim()),
1010-
self.pat.map_or(cond_span.lo(), |p| {
1039+
self.pats.as_ref().map_or(cond_span.lo(), |p| {
10111040
if self.matcher.is_empty() {
1012-
p.span.lo()
1041+
p[0].span.lo()
10131042
} else {
10141043
context
10151044
.snippet_provider
@@ -1102,7 +1131,7 @@ impl<'a> Rewrite for ControlFlow<'a> {
11021131
ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref next_else_block) => {
11031132
ControlFlow::new_if(
11041133
cond,
1105-
Some(pat),
1134+
Some(ptr_vec_to_ref_vec(pat)),
11061135
if_block,
11071136
next_else_block.as_ref().map(|e| &**e),
11081137
false,
@@ -1455,7 +1484,7 @@ fn rewrite_match_arm(
14551484
};
14561485
let pats_str = rewrite_match_pattern(
14571486
context,
1458-
&arm.pats,
1487+
&ptr_vec_to_ref_vec(&arm.pats),
14591488
&arm.guard,
14601489
beginning_vert.is_some(),
14611490
shape,
@@ -1513,7 +1542,7 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
15131542

15141543
fn rewrite_match_pattern(
15151544
context: &RewriteContext,
1516-
pats: &[ptr::P<ast::Pat>],
1545+
pats: &[&ast::Pat],
15171546
guard: &Option<ptr::P<ast::Expr>>,
15181547
has_beginning_vert: bool,
15191548
shape: Shape,
@@ -1524,36 +1553,7 @@ fn rewrite_match_pattern(
15241553
let pat_shape = shape
15251554
.sub_width(5)?
15261555
.offset_left(if has_beginning_vert { 2 } else { 0 })?;
1527-
1528-
let pat_strs = pats.iter()
1529-
.map(|p| p.rewrite(context, pat_shape))
1530-
.collect::<Option<Vec<_>>>()?;
1531-
1532-
let use_mixed_layout = pats.iter()
1533-
.zip(pat_strs.iter())
1534-
.all(|(pat, pat_str)| is_short_pattern(pat, pat_str));
1535-
let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect();
1536-
let tactic = if use_mixed_layout {
1537-
DefinitiveListTactic::Mixed
1538-
} else {
1539-
definitive_tactic(
1540-
&items,
1541-
ListTactic::HorizontalVertical,
1542-
Separator::VerticalBar,
1543-
pat_shape.width,
1544-
)
1545-
};
1546-
let fmt = ListFormatting {
1547-
tactic,
1548-
separator: " |",
1549-
trailing_separator: SeparatorTactic::Never,
1550-
separator_place: context.config.binop_separator(),
1551-
shape: pat_shape,
1552-
ends_with_newline: false,
1553-
preserve_newline: false,
1554-
config: context.config,
1555-
};
1556-
let pats_str = write_list(&items, &fmt)?;
1556+
let pats_str = rewrite_multiple_patterns(context, pats, pat_shape)?;
15571557
let beginning_vert = if has_beginning_vert { "| " } else { "" };
15581558

15591559
// Guard
@@ -1749,48 +1749,40 @@ fn rewrite_guard(
17491749
}
17501750
}
17511751

1752-
fn rewrite_pat_expr(
1752+
fn rewrite_multiple_patterns(
17531753
context: &RewriteContext,
1754-
pat: Option<&ast::Pat>,
1755-
expr: &ast::Expr,
1756-
matcher: &str,
1757-
// Connecting piece between pattern and expression,
1758-
// *without* trailing space.
1759-
connector: &str,
1760-
keyword: &str,
1754+
pats: &[&ast::Pat],
17611755
shape: Shape,
1762-
offset: usize,
17631756
) -> Option<String> {
1764-
debug!("rewrite_pat_expr {:?} {:?} {:?}", shape, pat, expr);
1765-
let cond_shape = shape.offset_left(offset)?;
1766-
if let Some(pat) = pat {
1767-
let matcher = if matcher.is_empty() {
1768-
matcher.to_owned()
1769-
} else {
1770-
format!("{} ", matcher)
1771-
};
1772-
let pat_shape = cond_shape
1773-
.offset_left(matcher.len())?
1774-
.sub_width(connector.len())?;
1775-
let pat_string = pat.rewrite(context, pat_shape)?;
1776-
let result = format!("{}{}{}", matcher, pat_string, connector);
1777-
return rewrite_assign_rhs(context, result, expr, cond_shape);
1778-
}
1779-
1780-
let expr_rw = expr.rewrite(context, cond_shape);
1781-
// The expression may (partially) fit on the current line.
1782-
// We do not allow splitting between `if` and condition.
1783-
if keyword == "if" || expr_rw.is_some() {
1784-
return expr_rw;
1785-
}
1757+
let pat_strs = pats.iter()
1758+
.map(|p| p.rewrite(context, shape))
1759+
.collect::<Option<Vec<_>>>()?;
17861760

1787-
// The expression won't fit on the current line, jump to next.
1788-
let nested_shape = shape
1789-
.block_indent(context.config.tab_spaces())
1790-
.with_max_width(context.config);
1791-
let nested_indent_str = nested_shape.indent.to_string_with_newline(context.config);
1792-
expr.rewrite(context, nested_shape)
1793-
.map(|expr_rw| format!("{}{}", nested_indent_str, expr_rw))
1761+
let use_mixed_layout = pats.iter()
1762+
.zip(pat_strs.iter())
1763+
.all(|(pat, pat_str)| is_short_pattern(pat, pat_str));
1764+
let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect();
1765+
let tactic = if use_mixed_layout {
1766+
DefinitiveListTactic::Mixed
1767+
} else {
1768+
definitive_tactic(
1769+
&items,
1770+
ListTactic::HorizontalVertical,
1771+
Separator::VerticalBar,
1772+
shape.width,
1773+
)
1774+
};
1775+
let fmt = ListFormatting {
1776+
tactic,
1777+
separator: " |",
1778+
trailing_separator: SeparatorTactic::Never,
1779+
separator_place: context.config.binop_separator(),
1780+
shape: shape,
1781+
ends_with_newline: false,
1782+
preserve_newline: false,
1783+
config: context.config,
1784+
};
1785+
write_list(&items, &fmt)
17941786
}
17951787

17961788
fn can_extend_match_arm_body(body: &ast::Expr) -> bool {

0 commit comments

Comments
 (0)