From 624f99b4b9f66cd056fc07a83fbb287fd4960aa5 Mon Sep 17 00:00:00 2001 From: maxwase Date: Fri, 24 May 2024 01:10:18 +0300 Subject: [PATCH] Review fixes: Split into 2, check tuple fields --- .../src/handlers/toggle_async_sugar.rs | 161 ++++++++++++------ crates/ide-assists/src/lib.rs | 3 +- crates/ide-assists/src/tests/generated.rs | 30 +++- 3 files changed, 137 insertions(+), 57 deletions(-) diff --git a/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/crates/ide-assists/src/handlers/toggle_async_sugar.rs index ea127d65e5..356e1d50ae 100644 --- a/crates/ide-assists/src/handlers/toggle_async_sugar.rs +++ b/crates/ide-assists/src/handlers/toggle_async_sugar.rs @@ -9,42 +9,38 @@ use syntax::{ use crate::{AssistContext, Assists}; -// Assist: toggle_async_sugar +// Assist: sugar_impl_future_into_async // -// Rewrites asynchronous function into `impl Future` and back. +// Rewrites asynchronous function from `impl Future` to `async fn`. // This action does not touch the function body and therefore `async { 0 }` // block does not transform to just `0`. // // ``` -// pub async f$0n foo() -> usize { -// 0 +// # //- minicore: future +// pub f$0n foo() -> impl core::future::Future { +// async { 0 } // } // ``` // -> // ``` -// pub fn foo() -> impl Future { -// 0 +// pub async fn foo() -> usize { +// async { 0 } // } // ``` -pub(crate) fn toggle_async_sugar(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let function: ast::Fn = ctx.find_node_at_offset()?; - match (function.async_token(), function.ret_type()) { - // async function returning futures cannot be flattened - // const async is not yet supported - (None, Some(ret_type)) if function.const_token().is_none() => { - add_async(acc, ctx, function, ret_type) - } - (Some(async_token), ret_type) => remove_async(function, ret_type, acc, async_token), - _ => None, - } -} - -fn add_async( +pub(crate) fn sugar_impl_future_into_async( acc: &mut Assists, ctx: &AssistContext<'_>, - function: ast::Fn, - ret_type: ast::RetType, ) -> Option<()> { + let function: ast::Fn = ctx.find_node_at_offset()?; + if function.async_token().is_some() { + return None; + } + + let ret_type = function.ret_type()?; + if function.const_token().is_some() { + return None; + } + let ast::Type::ImplTraitType(return_impl_trait) = ret_type.ty()? else { return None; }; @@ -66,12 +62,12 @@ fn add_async( let future_output = unwrap_future_output(main_trait_path)?; acc.add( - AssistId("toggle_async_sugar", AssistKind::RefactorRewrite), + AssistId("sugar_impl_future_into_async", AssistKind::RefactorRewrite), "Convert `impl Future` into async", function.syntax().text_range(), |builder| { match future_output { - ast::Type::TupleType(_) => { + ast::Type::TupleType(t) if t.fields().next().is_none() => { let mut ret_type_range = ret_type.syntax().text_range(); // find leftover whitespace @@ -105,14 +101,32 @@ fn add_async( ) } -fn remove_async( - function: ast::Fn, - ret_type: Option, +// Assist: desugar_async_into_impl_future +// +// Rewrites asynchronous function from `async fn` to `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 { +// 0 +// } +// ``` +// -> +// ``` +// pub fn foo() -> impl Future { +// 0 +// } +// ``` +pub(crate) fn desugar_async_into_impl_future( acc: &mut Assists, - async_token: SyntaxToken, + ctx: &AssistContext<'_>, ) -> Option<()> { + let function: ast::Fn = ctx.find_node_at_offset()?; + let async_token = function.async_token()?; + let rparen = function.param_list()?.r_paren_token()?; - let return_type = match ret_type { + let return_type = match function.ret_type() { // unable to get a `ty` makes the action unapplicable Some(ret_type) => Some(ret_type.ty()?), // No type means `-> ()` @@ -120,7 +134,7 @@ fn remove_async( }; acc.add( - AssistId("toggle_async_sugar", AssistKind::RefactorRewrite), + AssistId("desugar_async_into_impl_future", AssistKind::RefactorRewrite), "Convert async into `impl Future`", function.syntax().text_range(), |builder| { @@ -168,7 +182,7 @@ mod tests { #[test] fn sugar_with_use() { check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future use core::future::Future; @@ -185,7 +199,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future use core::future::Future; @@ -205,7 +219,7 @@ mod tests { #[test] fn desugar_with_use() { check_assist( - toggle_async_sugar, + desugar_async_into_impl_future, r#" //- minicore: future use core::future::Future; @@ -222,7 +236,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + desugar_async_into_impl_future, r#" //- minicore: future use core::future::Future; @@ -242,7 +256,7 @@ mod tests { #[test] fn sugar_without_use() { check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future f$0n foo() -> impl core::future::Future { @@ -257,7 +271,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future f$0n foo() -> impl core::future::Future { @@ -275,7 +289,7 @@ mod tests { #[test] fn desugar_without_use() { check_assist( - toggle_async_sugar, + desugar_async_into_impl_future, r#" //- minicore: future async f$0n foo() { @@ -290,7 +304,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + desugar_async_into_impl_future, r#" //- minicore: future async f$0n foo() -> usize { @@ -308,7 +322,7 @@ mod tests { #[test] fn sugar_not_applicable() { check_assist_not_applicable( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future trait Future { @@ -321,7 +335,7 @@ mod tests { ); check_assist_not_applicable( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future trait Future { @@ -337,7 +351,7 @@ mod tests { #[test] fn sugar_definition_with_use() { check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future use core::future::Future; @@ -350,7 +364,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future use core::future::Future; @@ -366,7 +380,7 @@ mod tests { #[test] fn sugar_definition_without_use() { check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future f$0n foo() -> impl core::future::Future; @@ -377,7 +391,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future f$0n foo() -> impl core::future::Future; @@ -388,10 +402,57 @@ mod tests { ); } + #[test] + fn sugar_more_types() { + check_assist( + sugar_impl_future_into_async, + r#" + //- minicore: future + f$0n foo() -> impl core::future::Future + Send + Sync; + "#, + r#" + async fn foo(); + "#, + ); + + check_assist( + sugar_impl_future_into_async, + r#" + //- minicore: future + f$0n foo() -> impl core::future::Future + Debug; + "#, + r#" + async fn foo() -> usize; + "#, + ); + + check_assist( + sugar_impl_future_into_async, + r#" + //- minicore: future + f$0n foo() -> impl core::future::Future + Debug; + "#, + r#" + async fn foo() -> (usize); + "#, + ); + + check_assist( + sugar_impl_future_into_async, + r#" + //- minicore: future + f$0n foo() -> impl core::future::Future + Debug; + "#, + r#" + async fn foo() -> (usize, usize); + "#, + ); + } + #[test] fn sugar_with_modifiers() { check_assist_not_applicable( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future const f$0n foo() -> impl core::future::Future; @@ -399,7 +460,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future pub(crate) unsafe f$0n foo() -> impl core::future::Future; @@ -410,7 +471,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future unsafe f$0n foo() -> impl core::future::Future; @@ -421,7 +482,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future unsafe extern "C" f$0n foo() -> impl core::future::Future; @@ -432,7 +493,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future f$0n foo() -> impl core::future::Future; @@ -443,7 +504,7 @@ mod tests { ); check_assist( - toggle_async_sugar, + sugar_impl_future_into_async, r#" //- minicore: future f$0n foo() -> impl core::future::Future diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index d26ac23099..34ef341c44 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -239,7 +239,8 @@ mod handlers { change_visibility::change_visibility, convert_bool_then::convert_bool_then_to_if, convert_bool_then::convert_if_to_bool_then, - toggle_async_sugar::toggle_async_sugar, + toggle_async_sugar::desugar_async_into_impl_future, + toggle_async_sugar::sugar_impl_future_into_async, convert_comment_block::convert_comment_block, convert_from_to_tryfrom::convert_from_to_tryfrom, convert_integer_literal::convert_integer_literal, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 8e0d1bd667..5f187880b0 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -800,6 +800,23 @@ fn main() { ) } +#[test] +fn doctest_desugar_async_into_impl_future() { + check_doc_test( + "desugar_async_into_impl_future", + r#####" +pub async f$0n foo() -> usize { + 0 +} +"#####, + r#####" +pub fn foo() -> impl Future { + 0 +} +"#####, + ) +} + #[test] fn doctest_desugar_doc_comment() { check_doc_test( @@ -3021,17 +3038,18 @@ use std::{collections::HashMap}; } #[test] -fn doctest_toggle_async_sugar() { +fn doctest_sugar_impl_future_into_async() { check_doc_test( - "toggle_async_sugar", + "sugar_impl_future_into_async", r#####" -pub async f$0n foo() -> usize { - 0 +//- minicore: future +pub f$0n foo() -> impl core::future::Future { + async { 0 } } "#####, r#####" -pub fn foo() -> impl Future { - 0 +pub async fn foo() -> usize { + async { 0 } } "#####, )