Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/toggle_async_sugar.rs')
| -rw-r--r-- | crates/ide-assists/src/handlers/toggle_async_sugar.rs | 164 |
1 files changed, 122 insertions, 42 deletions
diff --git a/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/crates/ide-assists/src/handlers/toggle_async_sugar.rs index 356e1d50ae..30e09648ea 100644 --- a/crates/ide-assists/src/handlers/toggle_async_sugar.rs +++ b/crates/ide-assists/src/handlers/toggle_async_sugar.rs @@ -1,3 +1,4 @@ +use hir::{ImportPathConfig, ModuleDef}; use ide_db::{ assists::{AssistId, AssistKind}, famous_defs::FamousDefs, @@ -11,13 +12,13 @@ use crate::{AssistContext, Assists}; // Assist: sugar_impl_future_into_async // -// Rewrites asynchronous function from `impl Future` to `async fn`. +// Rewrites asynchronous function from `-> impl Future` into `async fn`. // This action does not touch the function body and therefore `async { 0 }` // block does not transform to just `0`. // // ``` // # //- minicore: future -// pub f$0n foo() -> impl core::future::Future<Output = usize> { +// pub fn foo() -> impl core::future::F$0uture<Output = usize> { // async { 0 } // } // ``` @@ -31,13 +32,10 @@ pub(crate) fn sugar_impl_future_into_async( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { - let function: ast::Fn = ctx.find_node_at_offset()?; - if function.async_token().is_some() { - return None; - } + let ret_type: ast::RetType = ctx.find_node_at_offset()?; + let function = ret_type.syntax().parent().and_then(ast::Fn::cast)?; - let ret_type = function.ret_type()?; - if function.const_token().is_some() { + if function.async_token().is_some() || function.const_token().is_some() { return None; } @@ -67,6 +65,7 @@ pub(crate) fn sugar_impl_future_into_async( function.syntax().text_range(), |builder| { match future_output { + // Empty tuple ast::Type::TupleType(t) if t.fields().next().is_none() => { let mut ret_type_range = ret_type.syntax().text_range(); @@ -103,18 +102,19 @@ pub(crate) fn sugar_impl_future_into_async( // Assist: desugar_async_into_impl_future // -// Rewrites asynchronous function from `async fn` to `impl Future`. +// Rewrites asynchronous function from `async fn` into `-> impl Future`. // This action does not touch the function body and therefore `0` // block does not transform to `async { 0 }`. // // ``` -// pub async f$0n foo() -> usize { +// # //- minicore: future +// pub as$0ync fn foo() -> usize { // 0 // } // ``` // -> // ``` -// pub fn foo() -> impl Future<Output = usize> { +// pub fn foo() -> impl core::future::Future<Output = usize> { // 0 // } // ``` @@ -122,8 +122,8 @@ pub(crate) fn desugar_async_into_impl_future( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { - let function: ast::Fn = ctx.find_node_at_offset()?; - let async_token = function.async_token()?; + let async_token = ctx.find_token_syntax_at_offset(SyntaxKind::ASYNC_KW)?; + let function = async_token.parent().and_then(ast::Fn::cast)?; let rparen = function.param_list()?.r_paren_token()?; let return_type = match function.ret_type() { @@ -133,6 +133,19 @@ pub(crate) fn desugar_async_into_impl_future( None => None, }; + let scope = ctx.sema.scope(function.syntax())?; + let module = scope.module(); + let future_trait = FamousDefs(&ctx.sema, scope.krate()).core_future_Future()?; + let trait_path = module.find_path( + ctx.db(), + ModuleDef::Trait(future_trait), + ImportPathConfig { + prefer_no_std: ctx.config.prefer_no_std, + prefer_prelude: ctx.config.prefer_prelude, + }, + )?; + let trait_path = trait_path.display(ctx.db()); + acc.add( AssistId("desugar_async_into_impl_future", AssistKind::RefactorRewrite), "Convert async into `impl Future`", @@ -148,9 +161,12 @@ pub(crate) fn desugar_async_into_impl_future( match return_type { Some(ret_type) => builder.replace( ret_type.syntax().text_range(), - format!("impl Future<Output = {ret_type}>"), + format!("impl {trait_path}<Output = {ret_type}>"), + ), + None => builder.insert( + rparen.text_range().end(), + format!(" -> impl {trait_path}<Output = ()>"), ), - None => builder.insert(rparen.text_range().end(), " -> impl Future<Output = ()>"), } }, ) @@ -186,7 +202,7 @@ mod tests { r#" //- minicore: future use core::future::Future; - f$0n foo() -> impl Future<Output = ()> { + fn foo() -> impl F$0uture<Output = ()> { todo!() } "#, @@ -203,7 +219,7 @@ mod tests { r#" //- minicore: future use core::future::Future; - f$0n foo() -> impl Future<Output = usize> { + fn foo() -> impl F$0uture<Output = usize> { todo!() } "#, @@ -223,7 +239,7 @@ mod tests { r#" //- minicore: future use core::future::Future; - async f$0n foo() { + as$0ync fn foo() { todo!() } "#, @@ -239,8 +255,25 @@ mod tests { desugar_async_into_impl_future, r#" //- minicore: future + use core::future; + as$0ync fn foo() { + todo!() + } + "#, + r#" + use core::future; + fn foo() -> impl future::Future<Output = ()> { + todo!() + } + "#, + ); + + check_assist( + desugar_async_into_impl_future, + r#" + //- minicore: future use core::future::Future; - async f$0n foo() -> usize { + as$0ync fn foo() -> usize { todo!() } "#, @@ -251,6 +284,23 @@ mod tests { } "#, ); + + check_assist( + desugar_async_into_impl_future, + r#" + //- minicore: future + use core::future::Future; + as$0ync fn foo() -> impl Future<Output = usize> { + todo!() + } + "#, + r#" + use core::future::Future; + fn foo() -> impl Future<Output = impl Future<Output = usize>> { + todo!() + } + "#, + ); } #[test] @@ -259,7 +309,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future<Output = ()> { + fn foo() -> impl core::future::F$0uture<Output = ()> { todo!() } "#, @@ -274,7 +324,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future<Output = usize> { + fn foo() -> impl core::future::F$0uture<Output = usize> { todo!() } "#, @@ -292,12 +342,12 @@ mod tests { desugar_async_into_impl_future, r#" //- minicore: future - async f$0n foo() { + as$0ync fn foo() { todo!() } "#, r#" - fn foo() -> impl Future<Output = ()> { + fn foo() -> impl core::future::Future<Output = ()> { todo!() } "#, @@ -307,12 +357,12 @@ mod tests { desugar_async_into_impl_future, r#" //- minicore: future - async f$0n foo() -> usize { + as$0ync fn foo() -> usize { todo!() } "#, r#" - fn foo() -> impl Future<Output = usize> { + fn foo() -> impl core::future::Future<Output = usize> { todo!() } "#, @@ -320,7 +370,7 @@ mod tests { } #[test] - fn sugar_not_applicable() { + fn not_applicable() { check_assist_not_applicable( sugar_impl_future_into_async, r#" @@ -328,7 +378,7 @@ mod tests { trait Future { type Output; } - f$0n foo() -> impl Future<Output = ()> { + fn foo() -> impl F$0uture<Output = ()> { todo!() } "#, @@ -341,7 +391,26 @@ mod tests { trait Future { type Output; } - f$0n foo() -> impl Future<Output = usize> { + fn foo() -> impl F$0uture<Output = usize> { + todo!() + } + "#, + ); + + check_assist_not_applicable( + sugar_impl_future_into_async, + r#" + //- minicore: future + f$0n foo() -> impl core::future::Future<Output = usize> { + todo!() + } + "#, + ); + + check_assist_not_applicable( + desugar_async_into_impl_future, + r#" + async f$0n foo() { todo!() } "#, @@ -355,7 +424,7 @@ mod tests { r#" //- minicore: future use core::future::Future; - f$0n foo() -> impl Future<Output = ()>; + fn foo() -> impl F$0uture<Output = ()>; "#, r#" use core::future::Future; @@ -368,7 +437,7 @@ mod tests { r#" //- minicore: future use core::future::Future; - f$0n foo() -> impl Future<Output = usize>; + fn foo() -> impl F$0uture<Output = usize>; "#, r#" use core::future::Future; @@ -383,7 +452,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future<Output = ()>; + fn foo() -> impl core::future::F$0uture<Output = ()>; "#, r#" async fn foo(); @@ -394,7 +463,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future<Output = usize>; + fn foo() -> impl core::future::F$0uture<Output = usize>; "#, r#" async fn foo() -> usize; @@ -408,7 +477,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future<Output = ()> + Send + Sync; + fn foo() -> impl core::future::F$0uture<Output = ()> + Send + Sync; "#, r#" async fn foo(); @@ -419,7 +488,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future<Output = usize> + Debug; + fn foo() -> impl core::future::F$0uture<Output = usize> + Debug; "#, r#" async fn foo() -> usize; @@ -430,7 +499,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future<Output = (usize)> + Debug; + fn foo() -> impl core::future::F$0uture<Output = (usize)> + Debug; "#, r#" async fn foo() -> (usize); @@ -441,12 +510,23 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future<Output = (usize, usize)> + Debug; + fn foo() -> impl core::future::F$0uture<Output = (usize, usize)> + Debug; "#, r#" async fn foo() -> (usize, usize); "#, ); + + check_assist( + sugar_impl_future_into_async, + r#" + //- minicore: future + fn foo() -> impl core::future::Future<Output = impl core::future::F$0uture<Output = ()> + Send>; + "#, + r#" + async fn foo() -> impl core::future::Future<Output = ()> + Send; + "#, + ); } #[test] @@ -455,7 +535,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - const f$0n foo() -> impl core::future::Future<Output = ()>; + const fn foo() -> impl core::future::F$0uture<Output = ()>; "#, ); @@ -463,7 +543,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - pub(crate) unsafe f$0n foo() -> impl core::future::Future<Output = usize>; + pub(crate) unsafe fn foo() -> impl core::future::F$0uture<Output = usize>; "#, r#" pub(crate) async unsafe fn foo() -> usize; @@ -474,7 +554,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - unsafe f$0n foo() -> impl core::future::Future<Output = ()>; + unsafe fn foo() -> impl core::future::F$0uture<Output = ()>; "#, r#" async unsafe fn foo(); @@ -485,7 +565,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - unsafe extern "C" f$0n foo() -> impl core::future::Future<Output = ()>; + unsafe extern "C" fn foo() -> impl core::future::F$0uture<Output = ()>; "#, r#" async unsafe extern "C" fn foo(); @@ -496,7 +576,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo<T>() -> impl core::future::Future<Output = T>; + fn foo<T>() -> impl core::future::F$0uture<Output = T>; "#, r#" async fn foo<T>() -> T; @@ -507,7 +587,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo<T>() -> impl core::future::Future<Output = T> + fn foo<T>() -> impl core::future::F$0uture<Output = T> where T: Sized; "#, |