Skip to content

Commit 961b5b0

Browse files
Merge pull request #22335 from A4-Tacks/lazy-method-param
fix: add param on result methods for replace_method_eager_lazy
2 parents 9f890c5 + 9273d2e commit 961b5b0

2 files changed

Lines changed: 92 additions & 17 deletions

File tree

crates/ide-assists/src/handlers/replace_method_eager_lazy.rs

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use hir::Semantics;
2-
use ide_db::{RootDatabase, assists::AssistId, defs::Definition};
2+
use ide_db::{RootDatabase, assists::AssistId, defs::Definition, famous_defs::FamousDefs};
33
use syntax::{
44
AstNode,
5-
ast::{self, Expr, HasArgList, make, syntax_factory::SyntaxFactory},
5+
ast::{self, Expr, HasArgList, syntax_factory::SyntaxFactory},
66
};
77

88
use crate::{AssistContext, Assists, utils::wrap_paren_in_call};
@@ -64,9 +64,26 @@ pub(crate) fn replace_with_lazy_method(
6464
format!("Replace {method_name} with {method_name_lazy}"),
6565
call.syntax().text_range(),
6666
|builder| {
67-
let closured = into_closure(&last_arg, &method_name_lazy);
68-
builder.replace(method_name.syntax().text_range(), method_name_lazy);
69-
builder.replace_ast(last_arg, closured);
67+
let editor = builder.make_editor(call.syntax());
68+
let add_param = match &*method_name_lazy {
69+
"and_then" => true,
70+
"or_else" | "unwrap_or_else" => {
71+
FamousDefs(&ctx.sema, scope.krate()).core_result_Result().is_some_and(
72+
|result| result.ty(ctx.db()).could_unify_with(ctx.db(), &receiver_ty),
73+
)
74+
}
75+
_ => false,
76+
};
77+
let closured = into_closure(&last_arg, add_param, editor.make());
78+
editor.replace(method_name.syntax(), editor.make().name(&method_name_lazy).syntax());
79+
editor.replace(last_arg.syntax(), closured.syntax());
80+
if let Some(cap) = ctx.config.snippet_cap
81+
&& let ast::Expr::ClosureExpr(closured) = closured
82+
&& let Some(param) = closured.param_list().and_then(|it| it.params().next())
83+
{
84+
editor.add_annotation(param.syntax(), builder.make_placeholder_snippet(cap));
85+
}
86+
builder.add_file_edits(ctx.vfs_file_id(), editor);
7087
},
7188
)
7289
}
@@ -83,7 +100,7 @@ fn lazy_method_name(name: &str) -> String {
83100
}
84101
}
85102

86-
fn into_closure(param: &Expr, name_lazy: &str) -> Expr {
103+
fn into_closure(param: &Expr, add_param: bool, make: &SyntaxFactory) -> Expr {
87104
(|| {
88105
if let ast::Expr::CallExpr(call) = param {
89106
if call.arg_list()?.args().count() == 0 { Some(call.expr()?) } else { None }
@@ -92,9 +109,8 @@ fn into_closure(param: &Expr, name_lazy: &str) -> Expr {
92109
}
93110
})()
94111
.unwrap_or_else(|| {
95-
let pats = (name_lazy == "and_then")
96-
.then(|| make::untyped_param(make::ext::simple_ident_pat(make::name("it")).into()));
97-
make::expr_closure(pats, param.clone()).into()
112+
let pats = add_param.then(|| make.untyped_param(make.wildcard_pat().into()));
113+
make.expr_closure(pats, param.clone()).into()
98114
})
99115
}
100116

@@ -156,14 +172,16 @@ pub(crate) fn replace_with_eager_method(
156172
format!("Replace {method_name} with {method_name_eager}"),
157173
call.syntax().text_range(),
158174
|builder| {
159-
builder.replace(method_name.syntax().text_range(), method_name_eager);
160-
let called = into_call(&last_arg, &ctx.sema);
161-
builder.replace_ast(last_arg, called);
175+
let editor = builder.make_editor(call.syntax());
176+
let called = into_call(&last_arg, &ctx.sema, editor.make());
177+
editor.replace(method_name.syntax(), editor.make().name(method_name_eager).syntax());
178+
editor.replace(last_arg.syntax(), called.syntax());
179+
builder.add_file_edits(ctx.vfs_file_id(), editor);
162180
},
163181
)
164182
}
165183

166-
fn into_call(param: &Expr, sema: &Semantics<'_, RootDatabase>) -> Expr {
184+
fn into_call(param: &Expr, sema: &Semantics<'_, RootDatabase>, make: &SyntaxFactory) -> Expr {
167185
(|| {
168186
if let ast::Expr::ClosureExpr(closure) = param {
169187
let mut params = closure.param_list()?.params();
@@ -183,8 +201,8 @@ fn into_call(param: &Expr, sema: &Semantics<'_, RootDatabase>) -> Expr {
183201
}
184202
})()
185203
.unwrap_or_else(|| {
186-
let callable = wrap_paren_in_call(param.clone(), &SyntaxFactory::without_mappings());
187-
make::expr_call(callable, make::arg_list(Vec::new())).into()
204+
let callable = wrap_paren_in_call(param.clone(), make);
205+
make.expr_call(callable, make.arg_list(Vec::new())).into()
188206
})
189207
}
190208

@@ -213,7 +231,7 @@ mod tests {
213231
check_assist(
214232
replace_with_lazy_method,
215233
r#"
216-
//- minicore: option, fn
234+
//- minicore: option, result, fn
217235
fn foo() {
218236
let foo = Some(1);
219237
return foo.unwrap_$0or(2);
@@ -228,6 +246,26 @@ fn foo() {
228246
)
229247
}
230248

249+
#[test]
250+
fn replace_or_with_or_else_with_parameter() {
251+
check_assist(
252+
replace_with_lazy_method,
253+
r#"
254+
//- minicore: option, result, fn
255+
fn foo() {
256+
let foo = Ok(1);
257+
return foo.unwrap_$0or(2);
258+
}
259+
"#,
260+
r#"
261+
fn foo() {
262+
let foo = Ok(1);
263+
return foo.unwrap_or_else(|${0:_}| 2);
264+
}
265+
"#,
266+
)
267+
}
268+
231269
#[test]
232270
fn replace_or_with_or_else_call() {
233271
check_assist(
@@ -358,7 +396,7 @@ fn foo() {
358396
r#"
359397
fn foo() {
360398
let foo = Some("foo");
361-
return foo.and_then(|it| Some("bar"));
399+
return foo.and_then(|${0:_}| Some("bar"));
362400
}
363401
"#,
364402
)

crates/test-utils/src/minicore.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,6 +1713,43 @@ pub mod result {
17131713
#[lang = "Err"]
17141714
Err(E),
17151715
}
1716+
impl<T, E> Result<T, E> {
1717+
pub const fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
1718+
match self {
1719+
Ok(v) => Ok(v),
1720+
Err(_) => res,
1721+
}
1722+
}
1723+
1724+
pub const fn unwrap_or(self, default: T) -> T {
1725+
match self {
1726+
Ok(t) => t,
1727+
Err(_) => default,
1728+
}
1729+
}
1730+
1731+
// region:fn
1732+
pub const fn or_else<F, O>(self, op: O) -> Result<T, F>
1733+
where
1734+
O: FnOnce(E) -> Result<T, F>,
1735+
{
1736+
match self {
1737+
Ok(t) => Ok(t),
1738+
Err(e) => op(e),
1739+
}
1740+
}
1741+
1742+
pub const fn unwrap_or_else<F>(self, op: F) -> T
1743+
where
1744+
F: FnOnce(E) -> T,
1745+
{
1746+
match self {
1747+
Ok(t) => t,
1748+
Err(e) => op(e),
1749+
}
1750+
}
1751+
// endregion:fn
1752+
}
17161753
}
17171754
// endregion:result
17181755

0 commit comments

Comments
 (0)