Fix type walking about type of async block

This commit is contained in:
oxalica 2020-09-12 01:03:28 +08:00
parent cc4e287bb5
commit 529c369c9b
No known key found for this signature in database
GPG Key ID: CED392DE0C483D00
3 changed files with 78 additions and 14 deletions
crates
hir/src
hir_ty/src
ide/src

@ -1602,6 +1602,11 @@ impl Type {
cb(type_.derived(ty.clone()));
}
}
TypeCtor::OpaqueType(..) => {
if let Some(bounds) = ty.impl_trait_bounds(db) {
walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
}
}
_ => (),
}

@ -33,7 +33,6 @@ use hir_def::{
AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId,
TypeParamId,
};
use hir_expand::name::name;
use itertools::Itertools;
use crate::{
@ -848,26 +847,22 @@ impl Ty {
pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> {
match self {
Ty::Apply(ApplicationTy { ctor: TypeCtor::OpaqueType(opaque_ty_id), parameters }) => {
Ty::Apply(ApplicationTy { ctor: TypeCtor::OpaqueType(opaque_ty_id), .. }) => {
match opaque_ty_id {
OpaqueTyId::AsyncBlockTypeImplTrait(def, _expr) => {
let krate = def.module(db.upcast()).krate;
if let Some(future_output) = db
if let Some(future_trait) = db
.lang_item(krate, "future_trait".into())
.and_then(|item| item.as_trait())
.and_then(|trait_| {
db.trait_data(trait_).associated_type_by_name(&name![Output])
})
{
let proj = GenericPredicate::Projection(ProjectionPredicate {
projection_ty: ProjectionTy {
associated_ty: future_output,
// Self type.
parameters: Substs::single(self.clone()),
},
ty: parameters[0].clone(),
// This is only used by type walking.
// Parameters will be walked outside, and projection predicate is not used.
// So just provide the Future trait.
let impl_bound = GenericPredicate::Implemented(TraitRef {
trait_: future_trait,
substs: Substs::empty(),
});
Some(vec![proj])
Some(vec![impl_bound])
} else {
None
}

@ -2646,6 +2646,70 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
);
}
#[test]
fn test_hover_async_block_impl_trait_has_goto_type_action() {
check_actions(
r#"
struct S;
fn foo() {
let fo<|>o = async { S };
}
#[prelude_import] use future::*;
mod future {
#[lang = "future_trait"]
pub trait Future { type Output; }
}
"#,
expect![[r#"
[
GoToType(
[
HoverGotoTypeData {
mod_path: "test::future::Future",
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 101..163,
focus_range: Some(
140..146,
),
name: "Future",
kind: TRAIT,
container_name: None,
description: Some(
"pub trait Future",
),
docs: None,
},
},
HoverGotoTypeData {
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..9,
focus_range: Some(
7..8,
),
name: "S",
kind: STRUCT,
container_name: None,
description: Some(
"struct S",
),
docs: None,
},
},
],
),
]
"#]],
);
}
#[test]
fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
check_actions(