diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs index 356e1d50ae8..30e09648ea1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs +++ b/src/tools/rust-analyzer/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 { +// pub fn foo() -> impl core::future::F$0uture { // 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 { +// pub fn foo() -> impl core::future::Future { // 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"), + format!("impl {trait_path}"), + ), + None => builder.insert( + rparen.text_range().end(), + format!(" -> impl {trait_path}"), ), - None => builder.insert(rparen.text_range().end(), " -> impl Future"), } }, ) @@ -186,7 +202,7 @@ mod tests { r#" //- minicore: future use core::future::Future; - f$0n foo() -> impl Future { + fn foo() -> impl F$0uture { todo!() } "#, @@ -203,7 +219,7 @@ mod tests { r#" //- minicore: future use core::future::Future; - f$0n foo() -> impl Future { + fn foo() -> impl F$0uture { 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 { + 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!() } "#, @@ -249,6 +282,23 @@ mod tests { fn foo() -> impl Future { todo!() } + "#, + ); + + check_assist( + desugar_async_into_impl_future, + r#" + //- minicore: future + use core::future::Future; + as$0ync fn foo() -> impl Future { + todo!() + } + "#, + r#" + use core::future::Future; + fn foo() -> impl Future> { + todo!() + } "#, ); } @@ -259,7 +309,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future { + fn foo() -> impl core::future::F$0uture { todo!() } "#, @@ -274,7 +324,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future { + fn foo() -> impl core::future::F$0uture { 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 { + fn foo() -> impl core::future::Future { 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 { + fn foo() -> impl core::future::Future { 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 { + fn foo() -> impl F$0uture { todo!() } "#, @@ -341,7 +391,26 @@ mod tests { trait Future { type Output; } - f$0n foo() -> impl Future { + fn foo() -> impl F$0uture { + todo!() + } + "#, + ); + + check_assist_not_applicable( + sugar_impl_future_into_async, + r#" + //- minicore: future + f$0n foo() -> impl core::future::Future { + 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; + fn foo() -> impl F$0uture; "#, r#" use core::future::Future; @@ -368,7 +437,7 @@ mod tests { r#" //- minicore: future use core::future::Future; - f$0n foo() -> impl Future; + fn foo() -> impl F$0uture; "#, 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; + fn foo() -> impl core::future::F$0uture; "#, 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; + fn foo() -> impl core::future::F$0uture; "#, 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 + Send + Sync; + fn foo() -> impl core::future::F$0uture + 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 + Debug; + fn foo() -> impl core::future::F$0uture + 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 + Debug; + fn foo() -> impl core::future::F$0uture + Debug; "#, r#" async fn foo() -> (usize); @@ -441,10 +510,21 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future + Debug; + fn foo() -> impl core::future::F$0uture + Debug; "#, r#" async fn foo() -> (usize, usize); + "#, + ); + + check_assist( + sugar_impl_future_into_async, + r#" + //- minicore: future + fn foo() -> impl core::future::Future + Send>; + "#, + r#" + async fn foo() -> impl core::future::Future + Send; "#, ); } @@ -455,7 +535,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - const f$0n foo() -> impl core::future::Future; + const fn foo() -> impl core::future::F$0uture; "#, ); @@ -463,7 +543,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - pub(crate) unsafe f$0n foo() -> impl core::future::Future; + pub(crate) unsafe fn foo() -> impl core::future::F$0uture; "#, 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; + unsafe fn foo() -> impl core::future::F$0uture; "#, 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; + unsafe extern "C" fn foo() -> impl core::future::F$0uture; "#, r#" async unsafe extern "C" fn foo(); @@ -496,7 +576,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future; + fn foo() -> impl core::future::F$0uture; "#, r#" async fn foo() -> T; @@ -507,7 +587,7 @@ mod tests { sugar_impl_future_into_async, r#" //- minicore: future - f$0n foo() -> impl core::future::Future + fn foo() -> impl core::future::F$0uture where T: Sized; "#, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 5f187880b01..94d9e5edeff 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -805,12 +805,13 @@ fn doctest_desugar_async_into_impl_future() { check_doc_test( "desugar_async_into_impl_future", r#####" -pub async f$0n foo() -> usize { +//- minicore: future +pub as$0ync fn foo() -> usize { 0 } "#####, r#####" -pub fn foo() -> impl Future { +pub fn foo() -> impl core::future::Future { 0 } "#####, @@ -3043,7 +3044,7 @@ fn doctest_sugar_impl_future_into_async() { "sugar_impl_future_into_async", r#####" //- minicore: future -pub f$0n foo() -> impl core::future::Future { +pub fn foo() -> impl core::future::F$0uture { async { 0 } } "#####,