@@ -6,10 +6,9 @@ use ide_db::{
66 famous_defs:: FamousDefs ,
77 syntax_helpers:: node_ext:: { for_each_tail_expr, walk_expr} ,
88} ;
9- use itertools:: Itertools ;
109use 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 ,
1312} ;
1413
1514use crate :: { AssistContext , AssistId , AssistKind , Assists } ;
@@ -43,11 +42,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
4342pub ( crate ) fn wrap_return_type ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
4443 let ret_type = ctx. find_node_at_offset :: < ast:: RetType > ( ) ?;
4544 let parent = ret_type. syntax ( ) . parent ( ) ?;
46- let body = match_ast ! {
45+ let body_expr = match_ast ! {
4746 match parent {
48- ast:: Fn ( func) => func. body( ) ?,
47+ ast:: Fn ( func) => func. body( ) ?. into ( ) ,
4948 ast:: ClosureExpr ( closure) => match closure. body( ) ? {
50- Expr :: BlockExpr ( block) => block,
49+ Expr :: BlockExpr ( block) => block. into ( ) ,
5150 // closures require a block when a return type is specified
5251 _ => return None ,
5352 } ,
@@ -75,56 +74,65 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
7574 kind. assist_id ( ) ,
7675 kind. label ( ) ,
7776 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+ } ) ;
8485
8586 let mut exprs_to_wrap = Vec :: new ( ) ;
8687 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| {
8889 if let Expr :: ReturnExpr ( ret_expr) = expr {
8990 if let Some ( ret_expr_arg) = & ret_expr. expr ( ) {
9091 for_each_tail_expr ( ret_expr_arg, tail_cb) ;
9192 }
9293 }
9394 } ) ;
94- for_each_tail_expr ( & body , tail_cb) ;
95+ for_each_tail_expr ( & body_expr , tail_cb) ;
9596
9697 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 ( ) ) ;
103103 }
104104
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 ( ) ) ;
107106
108107 if let WrapperKind :: Result = kind {
109108 // Add a placeholder snippet at the first generic argument that doesn't equal the return type.
110109 // 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 ,
121123 } ) ;
122124 if let Some ( error_type_arg) = error_type_arg {
123125 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+ ) ;
125130 }
126131 }
127132 }
133+
134+ editor. add_mappings ( make. finish_with_mappings ( ) ) ;
135+ builder. add_file_edits ( ctx. file_id ( ) , editor) ;
128136 } ,
129137 ) ;
130138 }
@@ -176,22 +184,16 @@ impl WrapperKind {
176184 WrapperKind :: Result => hir:: sym:: Result . clone ( ) ,
177185 }
178186 }
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- }
186187}
187188
188189// Try to find an wrapper type alias in the current scope (shadowing the default).
189190fn wrapper_alias (
190191 ctx : & AssistContext < ' _ > ,
192+ make : & SyntaxFactory ,
191193 core_wrapper : & hir:: Enum ,
192194 ret_type : & ast:: Type ,
193195 wrapper : hir:: Symbol ,
194- ) -> Option < ast:: Type > {
196+ ) -> Option < ast:: PathType > {
195197 let wrapper_path = hir:: ModPath :: from_segments (
196198 hir:: PathKind :: Plain ,
197199 iter:: once ( hir:: Name :: new_symbol_root ( wrapper) ) ,
@@ -207,25 +209,28 @@ fn wrapper_alias(
207209 } )
208210 . find_map ( |alias| {
209211 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 ( ) ,
220224 }
221- ast:: GenericParam :: LifetimeParam ( _) => make:: lifetime ( "'_" ) . to_smolstr ( ) ,
222- _ => make:: ty_placeholder ( ) . to_smolstr ( ) ,
223- } )
224- . join ( ", " ) ;
225+ } ) ;
225226
226227 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) )
229234 } )
230235 } )
231236}
0 commit comments