Skip to content

Commit d92c89e

Browse files
authored
fix(fmt): keep if stmts inline in assembly blocks (#12306)
fix(fmt): asm inline if stmt
1 parent b32f4ee commit d92c89e

File tree

6 files changed

+83
-31
lines changed

6 files changed

+83
-31
lines changed

crates/fmt/src/state/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ impl<'ast> State<'_, 'ast> {
588588
self.s.offset(offset);
589589
}
590590
} else if style.is_isolated() {
591-
self.print_sep_unhandled(Separator::Space);
591+
self.print_sep_unhandled(Separator::Hardbreak);
592592
self.s.offset(offset);
593593
}
594594
}

crates/fmt/src/state/mod.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,17 @@ impl<'sess> State<'sess, '_> {
250250
self.has_crlf && self.char_at(self.cursor.pos) == Some('\r')
251251
}
252252

253+
/// Computes the space left, bounded by the max space left.
253254
fn space_left(&self) -> usize {
254-
std::cmp::min(
255-
self.s.space_left(),
256-
self.config.line_length.saturating_sub(self.block_depth * self.config.tab_width),
257-
)
255+
std::cmp::min(self.s.space_left(), self.max_space_left(0))
256+
}
257+
258+
/// Computes the maximum space left given the context information available:
259+
/// `block_depth`, `tab_width`, and a user-defined unavailable size `prefix_len`.
260+
fn max_space_left(&self, prefix_len: usize) -> usize {
261+
self.config
262+
.line_length
263+
.saturating_sub(self.block_depth * self.config.tab_width + prefix_len)
258264
}
259265

260266
fn break_offset_if_not_bol(&mut self, n: usize, off: isize, search: bool) {

crates/fmt/src/state/sol.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,7 +1871,7 @@ impl<'ast> State<'_, 'ast> {
18711871
_ = self.handle_span(self.cursor.span(span.lo()), false);
18721872
if !self.handle_span(span.until(block.span), false) {
18731873
self.cursor.advance_to(span.lo(), true);
1874-
self.print_word("assembly ");
1874+
self.print_word("assembly "); // 9 chars
18751875
if let Some(dialect) = dialect {
18761876
self.print_ast_str_lit(dialect);
18771877
self.print_sep(Separator::Nbsp);
@@ -1888,7 +1888,7 @@ impl<'ast> State<'_, 'ast> {
18881888
self.print_sep(Separator::Nbsp);
18891889
}
18901890
}
1891-
self.print_yul_block(block, block.span, false);
1891+
self.print_yul_block(block, block.span, false, 9);
18921892
}
18931893

18941894
/// Prints a multiple-variable declaration with a single initializer expression,

crates/fmt/src/state/yul.rs

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ impl<'ast> State<'_, 'ast> {
2626
}
2727

2828
match kind {
29-
yul::StmtKind::Block(stmts) => self.print_yul_block(stmts, span, false),
29+
yul::StmtKind::Block(stmts) => self.print_yul_block(stmts, span, false, 0),
3030
yul::StmtKind::AssignSingle(path, expr) => {
3131
self.print_path(path, false);
3232
self.word(" := ");
3333
self.neverbreak();
34+
self.cursor.advance_to(expr.span.lo(), self.cursor.enabled);
3435
self.print_yul_expr(expr);
3536
}
3637
yul::StmtKind::AssignMulti(paths, expr_call) => {
@@ -53,30 +54,30 @@ impl<'ast> State<'_, 'ast> {
5354
}
5455
yul::StmtKind::Expr(expr_call) => self.print_yul_expr(expr_call),
5556
yul::StmtKind::If(expr, stmts) => {
56-
self.word("if ");
57+
self.print_word("if "); // 3 chars
5758
self.print_yul_expr(expr);
58-
self.nbsp();
59-
self.print_yul_block(stmts, span, false);
59+
self.nbsp(); // 1 char
60+
self.print_yul_block(stmts, span, false, 4 + self.estimate_size(expr.span));
6061
}
6162
yul::StmtKind::For(yul::StmtFor { init, cond, step, body }) => {
6263
self.ibox(0);
6364

64-
self.word("for ");
65-
self.print_yul_block(init, init.span, false);
65+
self.print_word("for "); // 4 chars
66+
self.print_yul_block(init, init.span, false, 4);
6667

6768
self.space();
6869
self.print_yul_expr(cond);
6970

7071
self.space();
71-
self.print_yul_block(step, step.span, false);
72+
self.print_yul_block(step, step.span, false, 0);
7273

7374
self.space();
74-
self.print_yul_block(body, body.span, false);
75+
self.print_yul_block(body, body.span, false, 0);
7576

7677
self.end();
7778
}
7879
yul::StmtKind::Switch(yul::StmtSwitch { selector, cases }) => {
79-
self.word("switch ");
80+
self.print_word("switch ");
8081
self.print_yul_expr(selector);
8182

8283
self.print_trailing_comment(selector.span.hi(), None);
@@ -88,24 +89,24 @@ impl<'ast> State<'_, 'ast> {
8889
constant.span.lo(),
8990
CommentConfig::default().mixed_prev_space(),
9091
);
91-
self.word("case ");
92+
self.print_word("case ");
9293
self.print_lit_yul(constant);
9394
self.nbsp();
9495
} else {
9596
self.print_comments(
9697
body.span.lo(),
9798
CommentConfig::default().mixed_prev_space(),
9899
);
99-
self.word("default ");
100+
self.print_word("default ");
100101
}
101-
self.print_yul_block(body, *span, false);
102+
self.print_yul_block(body, *span, false, 0);
102103

103104
self.print_trailing_comment(selector.span.hi(), None);
104105
}
105106
}
106-
yul::StmtKind::Leave => self.word("leave"),
107-
yul::StmtKind::Break => self.word("break"),
108-
yul::StmtKind::Continue => self.word("continue"),
107+
yul::StmtKind::Leave => self.print_word("leave"),
108+
yul::StmtKind::Break => self.print_word("break"),
109+
yul::StmtKind::Continue => self.print_word("continue"),
109110
yul::StmtKind::FunctionDef(func) => {
110111
let yul::Function { name, parameters, returns, body } = func;
111112
let params_hi = parameters
@@ -116,7 +117,7 @@ impl<'ast> State<'_, 'ast> {
116117

117118
self.cbox(0);
118119
self.s.ibox(0);
119-
self.word("function ");
120+
self.print_word("function ");
120121
self.print_ident(name);
121122
self.print_tuple(
122123
parameters,
@@ -143,12 +144,12 @@ impl<'ast> State<'_, 'ast> {
143144
);
144145
}
145146
self.end();
146-
self.print_yul_block(body, span, skip_opening_brace);
147+
self.print_yul_block(body, span, skip_opening_brace, 0);
147148
self.end();
148149
}
149150
yul::StmtKind::VarDecl(idents, expr) => {
150151
self.s.ibox(self.ind);
151-
self.word("let ");
152+
self.print_word("let ");
152153
self.commasep(
153154
idents,
154155
stmt.span.lo(),
@@ -158,7 +159,7 @@ impl<'ast> State<'_, 'ast> {
158159
ListFormat::consistent(),
159160
);
160161
if let Some(expr) = expr {
161-
self.word(" :=");
162+
self.print_word(" :=");
162163
self.space();
163164
self.print_yul_expr(expr);
164165
}
@@ -201,6 +202,7 @@ impl<'ast> State<'_, 'ast> {
201202
block: &'ast yul::Block<'ast>,
202203
span: Span,
203204
skip_opening_brace: bool,
205+
prefix_len: usize,
204206
) {
205207
if self.handle_span(span, false) {
206208
return;
@@ -210,9 +212,15 @@ impl<'ast> State<'_, 'ast> {
210212
self.print_word("{");
211213
}
212214

213-
let can_inline_block = block.len() <= 1
214-
&& !self.is_multiline_yul_block(block)
215-
&& self.estimate_size(block.span) <= self.space_left();
215+
let can_inline_block = if block.len() <= 1 && !self.is_multiline_yul_block(block) {
216+
if self.max_space_left(prefix_len) == 0 {
217+
self.estimate_size(block.span) + self.config.tab_width < self.space_left()
218+
} else {
219+
self.estimate_size(block.span) + prefix_len < self.space_left()
220+
}
221+
} else {
222+
false
223+
};
216224
if can_inline_block {
217225
self.neverbreak();
218226
self.print_block_inner(

crates/fmt/testdata/Yul/fmt.sol

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,28 @@ contract Yul {
228228
result, p := parseValue(input, 0, p, e)
229229
mstore8(e, c) // Restore the original char at the end.
230230
}
231-
if or(lt(p, e), iszero(result)) { fail() }
231+
}
232+
}
233+
234+
assembly {
235+
function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {
236+
_pOut := pIn_
237+
if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.
238+
if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.
239+
let c_ := chr(_pOut)
240+
_pOut := add(_pOut, 1)
241+
if iszero(eq(c_, 48)) {
242+
_pOut := skip0To9s(_pOut, end_, 0)
243+
} // Not '0'.
244+
if eq(chr(_pOut), 46) {
245+
_pOut := skip0To9s(add(_pOut, 1), end_, 1)
246+
} // '.'.
247+
let t_ := mload(_pOut)
248+
if eq(or(0x20, byte(0, t_)), 101) {
249+
// forgefmt: disable-next-item
250+
_pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.
251+
add(_pOut, 1)), end_, 1)
252+
}
232253
}
233254
}
234255
}

crates/fmt/testdata/Yul/original.sol

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,24 @@ contract Yul {
171171
result, p := parseValue(input, 0, p, e)
172172
mstore8(e, c) // Restore the original char at the end.
173173
}
174-
if or(lt(p, e), iszero(result)) { fail() }
174+
}
175+
}
176+
177+
assembly {
178+
function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {
179+
_pOut := pIn_
180+
if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.
181+
if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.
182+
let c_ := chr(_pOut)
183+
_pOut := add(_pOut, 1)
184+
if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'.
185+
if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'.
186+
let t_ := mload(_pOut)
187+
if eq(or(0x20, byte(0, t_)), 101) {
188+
// forgefmt: disable-next-item
189+
_pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.
190+
add(_pOut, 1)), end_, 1)
191+
}
175192
}
176193
}
177194
}

0 commit comments

Comments
 (0)