Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #11991 - iDawer:completion_detail.impl_trait, r=iDawer
fix: completion detail shows `{unknown}` for async functions and for RPITs Fix: completion detail shows `{unknown}` for `impl Trait` in return position. Fix #11438 : completion detail shows `{unknown}` for return types in async functions. #### API changes Add `hir::Function::async_ret_type` method
bors 2022-04-16
parent 66c232d · parent c534120 · commit 40396b4
-rw-r--r--crates/hir/src/lib.rs23
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs15
-rw-r--r--crates/ide_completion/src/render/function.rs5
-rw-r--r--crates/ide_completion/src/tests/expression.rs40
4 files changed, 77 insertions, 6 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 06056217fd..5aa1ca7e0b 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1358,12 +1358,29 @@ 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)
}
+ pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option<Type> {
+ 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<SelfParam> {
if !db.function_data(self.id).has_self_param() {
return None;
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index b2cda87f93..4df7c4177c 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<i32, i32> {
check_assist(
extract_function,
r#"
+//- minicore: future
fn main() {
$0function_call("a", some_function().await);$0
}
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 38520e1832..9e5f91db39 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 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 ");
diff --git a/crates/ide_completion/src/tests/expression.rs b/crates/ide_completion/src/tests/expression.rs
index f1950235d4..77296d9099 100644
--- a/crates/ide_completion/src/tests/expression.rs
+++ b/crates/ide_completion/src/tests/expression.rs
@@ -602,3 +602,43 @@ fn func() {
"#]],
);
}
+
+#[test]
+fn detail_impl_trait_in_return_position() {
+ check_empty(
+ r"
+//- minicore: sized
+trait Trait<T> {}
+fn foo<U>() -> impl Trait<U> {}
+fn main() {
+ self::$0
+}
+",
+ expect![[r"
+ tt Trait
+ fn main() fn()
+ fn foo() fn() -> impl Trait<U>
+ "]],
+ );
+}
+
+#[test]
+fn detail_async_fn() {
+ check_empty(
+ r#"
+//- minicore: future, sized
+trait Trait<T> {}
+async fn foo() -> u8 {}
+async fn bar<U>() -> impl Trait<U> {}
+fn main() {
+ self::$0
+}
+"#,
+ expect![[r"
+ tt Trait
+ fn main() fn()
+ fn bar() async fn() -> impl Trait<U>
+ fn foo() async fn() -> u8
+ "]],
+ );
+}