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
This commit is contained in:
commit
40396b463e
@ -1358,12 +1358,29 @@ pub fn name(self, db: &dyn HirDatabase) -> Name {
|
||||
/// 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;
|
||||
|
@ -692,7 +692,14 @@ fn analyze_container(&self, sema: &Semantics<RootDatabase>) -> Option<ContainerI
|
||||
(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 extract_with_await() {
|
||||
check_assist(
|
||||
extract_function,
|
||||
r#"
|
||||
//- minicore: future
|
||||
fn main() {
|
||||
$0some_function().await;$0
|
||||
}
|
||||
@ -4055,6 +4063,7 @@ fn extract_with_await_and_result_not_producing_match_expr() {
|
||||
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 @@ fn extract_with_await_and_result_producing_match_expr() {
|
||||
check_assist(
|
||||
extract_function,
|
||||
r#"
|
||||
//- minicore: future
|
||||
async fn foo() -> i32 {
|
||||
loop {
|
||||
let n = 1;$0
|
||||
@ -4119,6 +4129,7 @@ fn extract_with_await_in_args() {
|
||||
check_assist(
|
||||
extract_function,
|
||||
r#"
|
||||
//- minicore: future
|
||||
fn main() {
|
||||
$0function_call("a", some_function().await);$0
|
||||
}
|
||||
|
@ -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 ");
|
||||
|
@ -602,3 +602,43 @@ fn variant fn() -> Enum
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[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
|
||||
"]],
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user