@@ -30,33 +30,33 @@ use crate::{AssistContext, Assists};
3030pub ( crate ) fn replace_or_with_or_else ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
3131 let call: ast:: MethodCallExpr = ctx. find_node_at_offset ( ) ?;
3232
33- is_option_or_result ( call. receiver ( ) ?, ctx) ?;
33+ let kind = is_option_or_result ( call. receiver ( ) ?, ctx) ?;
3434
3535 let ( name, arg_list) = ( call. name_ref ( ) ?, call. arg_list ( ) ?) ;
3636
37+ let mut map_or = false ;
38+
3739 let replace = match & * name. text ( ) {
3840 "unwrap_or" => "unwrap_or_else" . to_string ( ) ,
39- "ok_or" => "ok_or_else" . to_string ( ) ,
41+ "or" => "or_else" . to_string ( ) ,
42+ "ok_or" if kind == Kind :: Option => "ok_or_else" . to_string ( ) ,
43+ "map_or" => {
44+ map_or = true ;
45+ "map_or_else" . to_string ( )
46+ }
4047 _ => return None ,
4148 } ;
4249
4350 let arg = match arg_list. args ( ) . collect :: < Vec < _ > > ( ) . as_slice ( ) {
4451 [ ] => make:: arg_list ( Vec :: new ( ) ) ,
4552 [ first] => {
46- let param = ( || {
47- if let ast:: Expr :: CallExpr ( call) = first {
48- if call. arg_list ( ) ?. args ( ) . count ( ) == 0 {
49- Some ( call. expr ( ) ?. clone ( ) )
50- } else {
51- None
52- }
53- } else {
54- None
55- }
56- } ) ( )
57- . unwrap_or_else ( || make:: expr_closure ( None , first. clone ( ) ) ) ;
53+ let param = into_closure ( first) ;
5854 make:: arg_list ( vec ! [ param] )
5955 }
56+ [ first, second] if map_or => {
57+ let param = into_closure ( first) ;
58+ make:: arg_list ( vec ! [ param, second. clone( ) ] )
59+ }
6060 _ => return None ,
6161 } ;
6262
@@ -71,6 +71,21 @@ pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>
7171 )
7272}
7373
74+ fn into_closure ( param : & Expr ) -> Expr {
75+ ( || {
76+ if let ast:: Expr :: CallExpr ( call) = param {
77+ if call. arg_list ( ) ?. args ( ) . count ( ) == 0 {
78+ Some ( call. expr ( ) ?. clone ( ) )
79+ } else {
80+ None
81+ }
82+ } else {
83+ None
84+ }
85+ } ) ( )
86+ . unwrap_or_else ( || make:: expr_closure ( None , param. clone ( ) ) )
87+ }
88+
7489// Assist: replace_or_else_with_or
7590//
7691// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
@@ -92,33 +107,32 @@ pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>
92107pub ( crate ) fn replace_or_else_with_or ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
93108 let call: ast:: MethodCallExpr = ctx. find_node_at_offset ( ) ?;
94109
95- is_option_or_result ( call. receiver ( ) ?, ctx) ?;
110+ let kind = is_option_or_result ( call. receiver ( ) ?, ctx) ?;
96111
97112 let ( name, arg_list) = ( call. name_ref ( ) ?, call. arg_list ( ) ?) ;
98113
114+ let mut map_or = false ;
99115 let replace = match & * name. text ( ) {
100116 "unwrap_or_else" => "unwrap_or" . to_string ( ) ,
101- "ok_or_else" => "ok_or" . to_string ( ) ,
117+ "or_else" => "or" . to_string ( ) ,
118+ "ok_or_else" if kind == Kind :: Option => "ok_or" . to_string ( ) ,
119+ "map_or_else" => {
120+ map_or = true ;
121+ "map_or" . to_string ( )
122+ }
102123 _ => return None ,
103124 } ;
104125
105126 let arg = match arg_list. args ( ) . collect :: < Vec < _ > > ( ) . as_slice ( ) {
106127 [ ] => make:: arg_list ( Vec :: new ( ) ) ,
107128 [ first] => {
108- let param = ( || {
109- if let ast:: Expr :: ClosureExpr ( closure) = first {
110- if closure. param_list ( ) ?. params ( ) . count ( ) == 0 {
111- Some ( closure. body ( ) ?. clone ( ) )
112- } else {
113- None
114- }
115- } else {
116- None
117- }
118- } ) ( )
119- . unwrap_or_else ( || make:: expr_call ( first. clone ( ) , make:: arg_list ( Vec :: new ( ) ) ) ) ;
129+ let param = into_call ( first) ;
120130 make:: arg_list ( vec ! [ param] )
121131 }
132+ [ first, second] if map_or => {
133+ let param = into_call ( first) ;
134+ make:: arg_list ( vec ! [ param, second. clone( ) ] )
135+ }
122136 _ => return None ,
123137 } ;
124138
@@ -133,14 +147,35 @@ pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>
133147 )
134148}
135149
136- fn is_option_or_result ( receiver : Expr , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
150+ fn into_call ( param : & Expr ) -> Expr {
151+ ( || {
152+ if let ast:: Expr :: ClosureExpr ( closure) = param {
153+ if closure. param_list ( ) ?. params ( ) . count ( ) == 0 {
154+ Some ( closure. body ( ) ?. clone ( ) )
155+ } else {
156+ None
157+ }
158+ } else {
159+ None
160+ }
161+ } ) ( )
162+ . unwrap_or_else ( || make:: expr_call ( param. clone ( ) , make:: arg_list ( Vec :: new ( ) ) ) )
163+ }
164+
165+ #[ derive( PartialEq , Eq ) ]
166+ enum Kind {
167+ Option ,
168+ Result ,
169+ }
170+
171+ fn is_option_or_result ( receiver : Expr , ctx : & AssistContext < ' _ > ) -> Option < Kind > {
137172 let ty = ctx. sema . type_of_expr ( & receiver) ?. adjusted ( ) . as_adt ( ) ?. as_enum ( ) ?;
138173 let option_enum =
139174 FamousDefs ( & ctx. sema , ctx. sema . scope ( receiver. syntax ( ) ) ?. krate ( ) ) . core_option_Option ( ) ;
140175
141176 if let Some ( option_enum) = option_enum {
142177 if ty == option_enum {
143- return Some ( ( ) ) ;
178+ return Some ( Kind :: Option ) ;
144179 }
145180 }
146181
@@ -149,7 +184,7 @@ fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<()> {
149184
150185 if let Some ( result_enum) = result_enum {
151186 if ty == result_enum {
152- return Some ( ( ) ) ;
187+ return Some ( Kind :: Result ) ;
153188 }
154189 }
155190
@@ -294,6 +329,26 @@ fn foo() {
294329 )
295330 }
296331
332+ #[ test]
333+ fn replace_or_else_with_or_map ( ) {
334+ check_assist (
335+ replace_or_else_with_or,
336+ r#"
337+ //- minicore: result
338+ fn foo() {
339+ let foo = Ok("foo");
340+ return foo.map$0_or_else(|| 42, |v| v.len());
341+ }
342+ "# ,
343+ r#"
344+ fn foo() {
345+ let foo = Ok("foo");
346+ return foo.map_or(42, |v| v.len());
347+ }
348+ "# ,
349+ )
350+ }
351+
297352 #[ test]
298353 fn replace_or_else_with_or_not_applicable ( ) {
299354 check_assist_not_applicable (
0 commit comments