Skip to content

Commit d33edb4

Browse files
committed
ssr: Allow replacing expressions with statements
Now that statements can be matched and replaced (rust-lang#6587) some usecases require expressions to be replaced with statements as well. This happens when something that can ambiguously be an expression or statement like `if` and loop blocks appear in the last position of a block, as trailing expression. In this case a replacement pattern of the form `if foo(){$a();}==>>$a();` will only substitute `if` blocks in the list of statements but not if they (implicitly) end up in the trailing expression, where they are not wrapped by an EXPR_STMT (but the pattern and template are, as parsing only succeeds for the `stmt ==>> stmt` case). Instead of adding two rules that match an expression - and emit duplicate matching errors - allow the template for expressions to be a statement if it fails to parse as an expression.
1 parent b87699d commit d33edb4

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

crates/ssr/src/parsing.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,18 @@ impl ParsedRule {
7373
placeholders_by_stand_in: pattern.placeholders_by_stand_in(),
7474
rules: Vec::new(),
7575
};
76-
builder.try_add(ast::Expr::parse(&raw_pattern), raw_template.map(ast::Expr::parse));
76+
77+
let raw_template_stmt = raw_template.map(ast::Stmt::parse);
78+
if let raw_template_expr @ Some(Ok(_)) = raw_template.map(ast::Expr::parse) {
79+
builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_expr);
80+
} else {
81+
builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone());
82+
}
7783
builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse));
7884
builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse));
7985
builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse));
8086
builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse));
81-
builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template.map(ast::Stmt::parse));
87+
builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template_stmt);
8288
builder.build()
8389
}
8490
}
@@ -89,7 +95,11 @@ struct RuleBuilder {
8995
}
9096

9197
impl RuleBuilder {
92-
fn try_add<T: AstNode>(&mut self, pattern: Result<T, ()>, template: Option<Result<T, ()>>) {
98+
fn try_add<T: AstNode, T2: AstNode>(
99+
&mut self,
100+
pattern: Result<T, ()>,
101+
template: Option<Result<T2, ()>>,
102+
) {
93103
match (pattern, template) {
94104
(Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule {
95105
placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),

crates/ssr/src/tests.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,53 @@ fn ssr_let_stmt_replace_expr() {
203203
);
204204
}
205205

206+
#[test]
207+
fn ssr_blockexpr_replace_stmt_with_stmt() {
208+
assert_ssr_transform(
209+
"if $a() {$b;} ==>> $b;",
210+
"{
211+
if foo() {
212+
bar();
213+
}
214+
Ok(())
215+
}",
216+
expect![[r#"{
217+
bar();
218+
Ok(())
219+
}"#]],
220+
);
221+
}
222+
223+
#[test]
224+
fn ssr_blockexpr_match_trailing_expr() {
225+
assert_matches(
226+
"if $a() {$b;}",
227+
"{
228+
if foo() {
229+
bar();
230+
}
231+
}",
232+
&["if foo() {
233+
bar();
234+
}"],
235+
);
236+
}
237+
238+
#[test]
239+
fn ssr_blockexpr_replace_trailing_expr_with_stmt() {
240+
assert_ssr_transform(
241+
"if $a() {$b;} ==>> $b;",
242+
"{
243+
if foo() {
244+
bar();
245+
}
246+
}",
247+
expect![["{
248+
bar();
249+
}"]],
250+
);
251+
}
252+
206253
#[test]
207254
fn ssr_function_to_method() {
208255
assert_ssr_transform(

0 commit comments

Comments
 (0)