@@ -4000,14 +4000,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
4000
4000
4001
4001
// ... whose signature is `async` (i.e. this is an AFIT)
4002
4002
let ( sig, body) = item. expect_fn ( ) ;
4003
- let hir:: IsAsync :: Async ( async_span) = sig. header . asyncness else {
4004
- return ;
4005
- } ;
4006
- let Ok ( async_span) =
4007
- self . tcx . sess . source_map ( ) . span_extend_while ( async_span, |c| c. is_whitespace ( ) )
4008
- else {
4009
- return ;
4010
- } ;
4011
4003
let hir:: FnRetTy :: Return ( hir:: Ty { kind : hir:: TyKind :: OpaqueDef ( def, ..) , .. } ) =
4012
4004
sig. decl . output
4013
4005
else {
@@ -4021,55 +4013,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
4021
4013
return ;
4022
4014
}
4023
4015
4024
- let future = self . tcx . hir ( ) . item ( * def) . expect_opaque_ty ( ) ;
4025
- let Some ( hir:: GenericBound :: LangItemTrait ( _, _, _, generics) ) = future. bounds . get ( 0 ) else {
4026
- // `async fn` should always lower to a lang item bound... but don't ICE.
4027
- return ;
4028
- } ;
4029
- let Some ( hir:: TypeBindingKind :: Equality { term : hir:: Term :: Ty ( future_output_ty) } ) =
4030
- generics. bindings . get ( 0 ) . map ( |binding| binding. kind )
4031
- else {
4032
- // Also should never happen.
4016
+ let Some ( sugg) = suggest_desugaring_async_fn_to_impl_future_in_trait (
4017
+ self . tcx ,
4018
+ * sig,
4019
+ * body,
4020
+ opaque_def_id. expect_local ( ) ,
4021
+ & format ! ( " + {auto_trait}" ) ,
4022
+ ) else {
4033
4023
return ;
4034
4024
} ;
4035
4025
4036
4026
let function_name = self . tcx . def_path_str ( fn_def_id) ;
4037
-
4038
- let mut sugg = if future_output_ty. span . is_empty ( ) {
4039
- vec ! [
4040
- ( async_span, String :: new( ) ) ,
4041
- (
4042
- future_output_ty. span,
4043
- format!( " -> impl std::future::Future<Output = ()> + {auto_trait}" ) ,
4044
- ) ,
4045
- ]
4046
- } else {
4047
- vec ! [
4048
- (
4049
- future_output_ty. span. shrink_to_lo( ) ,
4050
- "impl std::future::Future<Output = " . to_owned( ) ,
4051
- ) ,
4052
- ( future_output_ty. span. shrink_to_hi( ) , format!( "> + {auto_trait}" ) ) ,
4053
- ( async_span, String :: new( ) ) ,
4054
- ]
4055
- } ;
4056
-
4057
- // If there's a body, we also need to wrap it in `async {}`
4058
- if let hir:: TraitFn :: Provided ( body) = body {
4059
- let body = self . tcx . hir ( ) . body ( * body) ;
4060
- let body_span = body. value . span ;
4061
- let body_span_without_braces =
4062
- body_span. with_lo ( body_span. lo ( ) + BytePos ( 1 ) ) . with_hi ( body_span. hi ( ) - BytePos ( 1 ) ) ;
4063
- if body_span_without_braces. is_empty ( ) {
4064
- sugg. push ( ( body_span_without_braces, " async {} " . to_owned ( ) ) ) ;
4065
- } else {
4066
- sugg. extend ( [
4067
- ( body_span_without_braces. shrink_to_lo ( ) , "async {" . to_owned ( ) ) ,
4068
- ( body_span_without_braces. shrink_to_hi ( ) , "} " . to_owned ( ) ) ,
4069
- ] ) ;
4070
- }
4071
- }
4072
-
4073
4027
err. multipart_suggestion (
4074
4028
format ! (
4075
4029
"`{auto_trait}` can be made part of the associated future's \
@@ -4321,3 +4275,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> {
4321
4275
self . tcx
4322
4276
}
4323
4277
}
4278
+
4279
+ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait < ' tcx > (
4280
+ tcx : TyCtxt < ' tcx > ,
4281
+ sig : hir:: FnSig < ' tcx > ,
4282
+ body : hir:: TraitFn < ' tcx > ,
4283
+ opaque_def_id : LocalDefId ,
4284
+ add_bounds : & str ,
4285
+ ) -> Option < Vec < ( Span , String ) > > {
4286
+ let hir:: IsAsync :: Async ( async_span) = sig. header . asyncness else {
4287
+ return None ;
4288
+ } ;
4289
+ let Ok ( async_span) = tcx. sess . source_map ( ) . span_extend_while ( async_span, |c| c. is_whitespace ( ) )
4290
+ else {
4291
+ return None ;
4292
+ } ;
4293
+
4294
+ let future = tcx. hir ( ) . get_by_def_id ( opaque_def_id) . expect_item ( ) . expect_opaque_ty ( ) ;
4295
+ let Some ( hir:: GenericBound :: LangItemTrait ( _, _, _, generics) ) = future. bounds . get ( 0 ) else {
4296
+ // `async fn` should always lower to a lang item bound... but don't ICE.
4297
+ return None ;
4298
+ } ;
4299
+ let Some ( hir:: TypeBindingKind :: Equality { term : hir:: Term :: Ty ( future_output_ty) } ) =
4300
+ generics. bindings . get ( 0 ) . map ( |binding| binding. kind )
4301
+ else {
4302
+ // Also should never happen.
4303
+ return None ;
4304
+ } ;
4305
+
4306
+ let mut sugg = if future_output_ty. span . is_empty ( ) {
4307
+ vec ! [
4308
+ ( async_span, String :: new( ) ) ,
4309
+ (
4310
+ future_output_ty. span,
4311
+ format!( " -> impl std::future::Future<Output = ()>{add_bounds}" ) ,
4312
+ ) ,
4313
+ ]
4314
+ } else {
4315
+ vec ! [
4316
+ ( future_output_ty. span. shrink_to_lo( ) , "impl std::future::Future<Output = " . to_owned( ) ) ,
4317
+ ( future_output_ty. span. shrink_to_hi( ) , format!( ">{add_bounds}" ) ) ,
4318
+ ( async_span, String :: new( ) ) ,
4319
+ ]
4320
+ } ;
4321
+
4322
+ // If there's a body, we also need to wrap it in `async {}`
4323
+ if let hir:: TraitFn :: Provided ( body) = body {
4324
+ let body = tcx. hir ( ) . body ( body) ;
4325
+ let body_span = body. value . span ;
4326
+ let body_span_without_braces =
4327
+ body_span. with_lo ( body_span. lo ( ) + BytePos ( 1 ) ) . with_hi ( body_span. hi ( ) - BytePos ( 1 ) ) ;
4328
+ if body_span_without_braces. is_empty ( ) {
4329
+ sugg. push ( ( body_span_without_braces, " async {} " . to_owned ( ) ) ) ;
4330
+ } else {
4331
+ sugg. extend ( [
4332
+ ( body_span_without_braces. shrink_to_lo ( ) , "async {" . to_owned ( ) ) ,
4333
+ ( body_span_without_braces. shrink_to_hi ( ) , "} " . to_owned ( ) ) ,
4334
+ ] ) ;
4335
+ }
4336
+ }
4337
+
4338
+ Some ( sugg)
4339
+ }
0 commit comments