From f972adc2012fc49b35124d080a000a0d44c95452 Mon Sep 17 00:00:00 2001 From: iDawer Date: Tue, 12 Apr 2022 20:40:31 +0500 Subject: [PATCH 1/4] fix: comletion detail shows `{unknown}` for `impl Trait` in return position --- crates/hir/src/lib.rs | 6 +-- crates/ide_completion/src/tests/expression.rs | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 06056217fdb..7cda75b3478 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1358,9 +1358,9 @@ impl Function { /// Get this function's return type pub fn ret_type(self, db: &dyn HirDatabase) -> Type { let resolver = self.id.resolver(db.upcast()); - let ret_type = &db.function_data(self.id).ret_type; - let ctx = hir_ty::TyLoweringContext::new(db, &resolver); - let ty = ctx.lower_ty(ret_type); + let substs = TyBuilder::placeholder_subst(db, self.id); + let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + let ty = callable_sig.ret().clone(); Type::new_with_resolver_inner(db, &resolver, ty) } diff --git a/crates/ide_completion/src/tests/expression.rs b/crates/ide_completion/src/tests/expression.rs index f1950235d46..f25e14e0fcd 100644 --- a/crates/ide_completion/src/tests/expression.rs +++ b/crates/ide_completion/src/tests/expression.rs @@ -602,3 +602,42 @@ fn func() { "#]], ); } + +#[test] +fn detail_impl_trait_in_return_position() { + check_empty( + r" +//- minicore: sized +trait Trait {} +fn foo() -> impl Trait {} +fn main() { + self::$0 +} +", + expect![[r" + tt Trait + fn main() fn() + fn foo() fn() -> impl Trait + "]], + ); +} + +#[test] +fn detail_async_fn() { + // FIXME: #11438 + check_empty( + r#" +//- minicore: future, sized +trait Trait {} +async fn foo() -> u8 {} +fn main() { + self::$0 +} +"#, + expect![[r" + tt Trait + fn main() fn() + fn foo() async fn() -> impl Future + "]], + ); +} From 9d787e1bfe79064be4376c914ce11948041ccbef Mon Sep 17 00:00:00 2001 From: iDawer Date: Thu, 14 Apr 2022 17:44:17 +0500 Subject: [PATCH 2/4] Add `hir::Function::async_ret_type` method Adjust completion detail for `async fn` return types --- crates/hir/src/lib.rs | 17 +++++++++++++++++ crates/ide_completion/src/render/function.rs | 2 +- crates/ide_completion/src/tests/expression.rs | 5 +++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 7cda75b3478..5aa1ca7e0ba 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1364,6 +1364,23 @@ impl Function { Type::new_with_resolver_inner(db, &resolver, ty) } + pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option { + if !self.is_async(db) { + return None; + } + let resolver = self.id.resolver(db.upcast()); + let substs = TyBuilder::placeholder_subst(db, self.id); + let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + let ret_ty = callable_sig.ret().clone(); + for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() { + if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 { + return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into(); + } + } + never!("Async fn ret_type should be impl Future"); + None + } + pub fn self_param(self, db: &dyn HirDatabase) -> Option { if !db.function_data(self.id).has_self_param() { return None; diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index 38520e1832f..cbaecd208df 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs @@ -228,7 +228,7 @@ fn should_add_parens(ctx: &CompletionContext) -> bool { } fn detail(db: &dyn HirDatabase, func: hir::Function) -> String { - let ret_ty = func.ret_type(db); + let ret_ty = func.async_ret_type(db).unwrap_or_else(|| func.ret_type(db)); let mut detail = String::new(); if func.is_const(db) { diff --git a/crates/ide_completion/src/tests/expression.rs b/crates/ide_completion/src/tests/expression.rs index f25e14e0fcd..77296d9099f 100644 --- a/crates/ide_completion/src/tests/expression.rs +++ b/crates/ide_completion/src/tests/expression.rs @@ -624,12 +624,12 @@ fn main() { #[test] fn detail_async_fn() { - // FIXME: #11438 check_empty( r#" //- minicore: future, sized trait Trait {} async fn foo() -> u8 {} +async fn bar() -> impl Trait {} fn main() { self::$0 } @@ -637,7 +637,8 @@ fn main() { expect![[r" tt Trait fn main() fn() - fn foo() async fn() -> impl Future + fn bar() async fn() -> impl Trait + fn foo() async fn() -> u8 "]], ); } From 03c5dd1252f0e1bc0407f29a058c7bc0671c15fb Mon Sep 17 00:00:00 2001 From: iDawer Date: Thu, 14 Apr 2022 21:12:26 +0500 Subject: [PATCH 3/4] `extract_function`: use appropriate return type for async fns --- .../ide_assists/src/handlers/extract_function.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index b2cda87f93e..4df7c4177c8 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs @@ -692,7 +692,14 @@ impl FunctionBody { (constness, expr.clone(), infer_expr_opt(expr)) }, ast::Fn(fn_) => { - (fn_.const_token().is_some(), fn_.body().map(ast::Expr::BlockExpr), Some(sema.to_def(&fn_)?.ret_type(sema.db))) + let func = sema.to_def(&fn_)?; + let mut ret_ty = func.ret_type(sema.db); + if func.is_async(sema.db) { + if let Some(async_ret) = func.async_ret_type(sema.db) { + ret_ty = async_ret; + } + } + (fn_.const_token().is_some(), fn_.body().map(ast::Expr::BlockExpr), Some(ret_ty)) }, ast::Static(statik) => { (true, statik.body(), Some(sema.to_def(&statik)?.ty(sema.db))) @@ -4026,6 +4033,7 @@ fn $0fun_name(n: i32) -> i32 { check_assist( extract_function, r#" +//- minicore: future fn main() { $0some_function().await;$0 } @@ -4055,6 +4063,7 @@ async fn some_function() { check_assist( extract_function, r#" +//- minicore: future, result async fn foo() -> Result<(), ()> { $0async {}.await; Err(())?$0 @@ -4065,7 +4074,7 @@ async fn foo() -> Result<(), ()> { fun_name().await? } -async fn $0fun_name() -> _ { +async fn $0fun_name() -> Result<(), ()> { async {}.await; Err(())? } @@ -4078,6 +4087,7 @@ async fn $0fun_name() -> _ { check_assist( extract_function, r#" +//- minicore: future async fn foo() -> i32 { loop { let n = 1;$0 @@ -4119,6 +4129,7 @@ async fn $0fun_name() -> Result { check_assist( extract_function, r#" +//- minicore: future fn main() { $0function_call("a", some_function().await);$0 } From c53412046f8af55ed462fd4c213d93ed192827b7 Mon Sep 17 00:00:00 2001 From: iDawer Date: Thu, 14 Apr 2022 21:16:25 +0500 Subject: [PATCH 4/4] minor: address nit --- crates/ide_completion/src/render/function.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index cbaecd208df..9e5f91db39c 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs @@ -228,7 +228,7 @@ fn should_add_parens(ctx: &CompletionContext) -> bool { } fn detail(db: &dyn HirDatabase, func: hir::Function) -> String { - let ret_ty = func.async_ret_type(db).unwrap_or_else(|| func.ret_type(db)); + let mut ret_ty = func.ret_type(db); let mut detail = String::new(); if func.is_const(db) { @@ -236,6 +236,9 @@ fn detail(db: &dyn HirDatabase, func: hir::Function) -> String { } if func.is_async(db) { format_to!(detail, "async "); + if let Some(async_ret) = func.async_ret_type(db) { + ret_ty = async_ret; + } } if func.is_unsafe_to_call(db) { format_to!(detail, "unsafe ");