@@ -6,10 +6,9 @@ use ide_db::{
6
6
famous_defs:: FamousDefs ,
7
7
syntax_helpers:: node_ext:: { for_each_tail_expr, walk_expr} ,
8
8
} ;
9
- use itertools:: Itertools ;
10
9
use syntax:: {
11
- ast:: { self , make , Expr , HasGenericParams } ,
12
- match_ast, ted , AstNode , ToSmolStr ,
10
+ ast:: { self , syntax_factory :: SyntaxFactory , Expr , HasGenericArgs , HasGenericParams } ,
11
+ match_ast, AstNode ,
13
12
} ;
14
13
15
14
use crate :: { AssistContext , AssistId , AssistKind , Assists } ;
@@ -43,11 +42,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
43
42
pub ( crate ) fn wrap_return_type ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
44
43
let ret_type = ctx. find_node_at_offset :: < ast:: RetType > ( ) ?;
45
44
let parent = ret_type. syntax ( ) . parent ( ) ?;
46
- let body = match_ast ! {
45
+ let body_expr = match_ast ! {
47
46
match parent {
48
- ast:: Fn ( func) => func. body( ) ?,
47
+ ast:: Fn ( func) => func. body( ) ?. into ( ) ,
49
48
ast:: ClosureExpr ( closure) => match closure. body( ) ? {
50
- Expr :: BlockExpr ( block) => block,
49
+ Expr :: BlockExpr ( block) => block. into ( ) ,
51
50
// closures require a block when a return type is specified
52
51
_ => return None ,
53
52
} ,
@@ -75,56 +74,65 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
75
74
kind. assist_id ( ) ,
76
75
kind. label ( ) ,
77
76
type_ref. syntax ( ) . text_range ( ) ,
78
- |edit| {
79
- let alias = wrapper_alias ( ctx, & core_wrapper, type_ref, kind. symbol ( ) ) ;
80
- let new_return_ty =
81
- alias. unwrap_or_else ( || kind. wrap_type ( type_ref) ) . clone_for_update ( ) ;
82
-
83
- let body = edit. make_mut ( ast:: Expr :: BlockExpr ( body. clone ( ) ) ) ;
77
+ |builder| {
78
+ let mut editor = builder. make_editor ( & parent) ;
79
+ let make = SyntaxFactory :: new ( ) ;
80
+ let alias = wrapper_alias ( ctx, & make, & core_wrapper, type_ref, kind. symbol ( ) ) ;
81
+ let new_return_ty = alias. unwrap_or_else ( || match kind {
82
+ WrapperKind :: Option => make. ty_option ( type_ref. clone ( ) ) ,
83
+ WrapperKind :: Result => make. ty_result ( type_ref. clone ( ) , make. ty_infer ( ) . into ( ) ) ,
84
+ } ) ;
84
85
85
86
let mut exprs_to_wrap = Vec :: new ( ) ;
86
87
let tail_cb = & mut |e : & _ | tail_cb_impl ( & mut exprs_to_wrap, e) ;
87
- walk_expr ( & body , & mut |expr| {
88
+ walk_expr ( & body_expr , & mut |expr| {
88
89
if let Expr :: ReturnExpr ( ret_expr) = expr {
89
90
if let Some ( ret_expr_arg) = & ret_expr. expr ( ) {
90
91
for_each_tail_expr ( ret_expr_arg, tail_cb) ;
91
92
}
92
93
}
93
94
} ) ;
94
- for_each_tail_expr ( & body , tail_cb) ;
95
+ for_each_tail_expr ( & body_expr , tail_cb) ;
95
96
96
97
for ret_expr_arg in exprs_to_wrap {
97
- let happy_wrapped = make:: expr_call (
98
- make:: expr_path ( make:: ext:: ident_path ( kind. happy_ident ( ) ) ) ,
99
- make:: arg_list ( iter:: once ( ret_expr_arg. clone ( ) ) ) ,
100
- )
101
- . clone_for_update ( ) ;
102
- ted:: replace ( ret_expr_arg. syntax ( ) , happy_wrapped. syntax ( ) ) ;
98
+ let happy_wrapped = make. expr_call (
99
+ make. expr_path ( make. ident_path ( kind. happy_ident ( ) ) ) ,
100
+ make. arg_list ( iter:: once ( ret_expr_arg. clone ( ) ) ) ,
101
+ ) ;
102
+ editor. replace ( ret_expr_arg. syntax ( ) , happy_wrapped. syntax ( ) ) ;
103
103
}
104
104
105
- let old_return_ty = edit. make_mut ( type_ref. clone ( ) ) ;
106
- ted:: replace ( old_return_ty. syntax ( ) , new_return_ty. syntax ( ) ) ;
105
+ editor. replace ( type_ref. syntax ( ) , new_return_ty. syntax ( ) ) ;
107
106
108
107
if let WrapperKind :: Result = kind {
109
108
// Add a placeholder snippet at the first generic argument that doesn't equal the return type.
110
109
// This is normally the error type, but that may not be the case when we inserted a type alias.
111
- let args =
112
- new_return_ty. syntax ( ) . descendants ( ) . find_map ( ast:: GenericArgList :: cast) ;
113
- let error_type_arg = args. and_then ( |list| {
114
- list. generic_args ( ) . find ( |arg| match arg {
115
- ast:: GenericArg :: TypeArg ( _) => {
116
- arg. syntax ( ) . text ( ) != type_ref. syntax ( ) . text ( )
117
- }
118
- ast:: GenericArg :: LifetimeArg ( _) => false ,
119
- _ => true ,
120
- } )
110
+ let args = new_return_ty
111
+ . path ( )
112
+ . unwrap ( )
113
+ . segment ( )
114
+ . unwrap ( )
115
+ . generic_arg_list ( )
116
+ . unwrap ( ) ;
117
+ let error_type_arg = args. generic_args ( ) . find ( |arg| match arg {
118
+ ast:: GenericArg :: TypeArg ( _) => {
119
+ arg. syntax ( ) . text ( ) != type_ref. syntax ( ) . text ( )
120
+ }
121
+ ast:: GenericArg :: LifetimeArg ( _) => false ,
122
+ _ => true ,
121
123
} ) ;
122
124
if let Some ( error_type_arg) = error_type_arg {
123
125
if let Some ( cap) = ctx. config . snippet_cap {
124
- edit. add_placeholder_snippet ( cap, error_type_arg) ;
126
+ editor. add_annotation (
127
+ error_type_arg. syntax ( ) ,
128
+ builder. make_placeholder_snippet ( cap) ,
129
+ ) ;
125
130
}
126
131
}
127
132
}
133
+
134
+ editor. add_mappings ( make. finish_with_mappings ( ) ) ;
135
+ builder. add_file_edits ( ctx. file_id ( ) , editor) ;
128
136
} ,
129
137
) ;
130
138
}
@@ -176,22 +184,16 @@ impl WrapperKind {
176
184
WrapperKind :: Result => hir:: sym:: Result . clone ( ) ,
177
185
}
178
186
}
179
-
180
- fn wrap_type ( & self , type_ref : & ast:: Type ) -> ast:: Type {
181
- match self {
182
- WrapperKind :: Option => make:: ext:: ty_option ( type_ref. clone ( ) ) ,
183
- WrapperKind :: Result => make:: ext:: ty_result ( type_ref. clone ( ) , make:: ty_placeholder ( ) ) ,
184
- }
185
- }
186
187
}
187
188
188
189
// Try to find an wrapper type alias in the current scope (shadowing the default).
189
190
fn wrapper_alias (
190
191
ctx : & AssistContext < ' _ > ,
192
+ make : & SyntaxFactory ,
191
193
core_wrapper : & hir:: Enum ,
192
194
ret_type : & ast:: Type ,
193
195
wrapper : hir:: Symbol ,
194
- ) -> Option < ast:: Type > {
196
+ ) -> Option < ast:: PathType > {
195
197
let wrapper_path = hir:: ModPath :: from_segments (
196
198
hir:: PathKind :: Plain ,
197
199
iter:: once ( hir:: Name :: new_symbol_root ( wrapper) ) ,
@@ -207,25 +209,28 @@ fn wrapper_alias(
207
209
} )
208
210
. find_map ( |alias| {
209
211
let mut inserted_ret_type = false ;
210
- let generic_params = alias
211
- . source ( ctx. db ( ) ) ?
212
- . value
213
- . generic_param_list ( ) ?
214
- . generic_params ( )
215
- . map ( |param| match param {
216
- // Replace the very first type parameter with the functions return type.
217
- ast:: GenericParam :: TypeParam ( _) if !inserted_ret_type => {
218
- inserted_ret_type = true ;
219
- ret_type. to_smolstr ( )
212
+ let generic_args =
213
+ alias. source ( ctx. db ( ) ) ?. value . generic_param_list ( ) ?. generic_params ( ) . map ( |param| {
214
+ match param {
215
+ // Replace the very first type parameter with the function's return type.
216
+ ast:: GenericParam :: TypeParam ( _) if !inserted_ret_type => {
217
+ inserted_ret_type = true ;
218
+ make. type_arg ( ret_type. clone ( ) ) . into ( )
219
+ }
220
+ ast:: GenericParam :: LifetimeParam ( _) => {
221
+ make. lifetime_arg ( make. lifetime ( "'_" ) ) . into ( )
222
+ }
223
+ _ => make. type_arg ( make. ty_infer ( ) . into ( ) ) . into ( ) ,
220
224
}
221
- ast:: GenericParam :: LifetimeParam ( _) => make:: lifetime ( "'_" ) . to_smolstr ( ) ,
222
- _ => make:: ty_placeholder ( ) . to_smolstr ( ) ,
223
- } )
224
- . join ( ", " ) ;
225
+ } ) ;
225
226
226
227
let name = alias. name ( ctx. db ( ) ) ;
227
- let name = name. as_str ( ) ;
228
- Some ( make:: ty ( & format ! ( "{name}<{generic_params}>" ) ) )
228
+ let generic_arg_list = make. generic_arg_list ( generic_args, false ) ;
229
+ let path = make. path_unqualified (
230
+ make. path_segment_generics ( make. name_ref ( name. as_str ( ) ) , generic_arg_list) ,
231
+ ) ;
232
+
233
+ Some ( make. ty_path ( path) )
229
234
} )
230
235
} )
231
236
}
0 commit comments