Use future lang item instead of hardcoded std::future::Future

This commit is contained in:
Evgenii P 2019-08-03 01:53:51 +07:00
parent 30bc3b93be
commit ab7774545c
2 changed files with 21 additions and 37 deletions

View File

@ -24,6 +24,7 @@
BodySourceMap,
},
ids::LocationCtx,
lang_item::LangItemTarget,
ty::method_resolution::implements_trait,
AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId,
MacroDef, Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty,
@ -410,40 +411,18 @@ pub fn autoderef<'a>(
crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value)
}
/// Checks that particular type `ty` implements `std::future::Future` trait.
/// Checks that particular type `ty` implements `Future` trait (`future_trait` lang item).
/// This function is used in `.await` syntax completion.
pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool {
// Search for std::future::Future trait in scope
let future_trait = self
.resolver
.traits_in_scope(db)
.into_iter()
.filter(|t| {
let std = t
.module(db)
.parent(db)
.and_then(|m| m.name(db).and_then(|n| Some(n.to_string() == "std")))
.unwrap_or(false);
let krate = self.resolver.krate();
if let Some(krate) = krate {
let future_trait = match db.lang_item(krate, "future_trait".into()) {
Some(LangItemTarget::Trait(t)) => t,
_ => return false,
};
let future = t
.module(db)
.name(db)
.and_then(|n| Some(n.to_string() == "future"))
.unwrap_or(false);
let future_trait =
t.name(db).and_then(|n| Some(n.to_string() == "Future")).unwrap_or(false);
std && future && future_trait
})
.nth(0);
if let Some(trait_) = future_trait {
let krate = self.resolver.krate();
if let Some(krate) = krate {
let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 };
return implements_trait(&canonical_ty, db, &self.resolver, krate, trait_);
}
let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 };
return implements_trait(&canonical_ty, db, &self.resolver, krate, future_trait);
}
false

View File

@ -37,7 +37,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
}
complete_methods(acc, ctx, receiver_ty.clone());
// Suggest .await syntax for types that implement std::future::Future
// Suggest .await syntax for types that implement Future trait
if ctx.analyzer.impls_future(ctx.db, receiver_ty) {
postfix_reference(ctx, ".await", "expr.await", &format!("{}.await", receiver_text))
.add_to(acc);
@ -441,9 +441,14 @@ struct A { the_field: u32 }
fn test_completion_await_impls_future() {
assert_debug_snapshot_matches!(
do_ref_completion(
r"
r###"
// Mock Future trait from stdlib
pub mod std { pub mod future { pub trait Future {} } }
pub mod std {
pub mod future {
#[lang = "future_trait"]
pub trait Future {}
}
}
use std::future::*;
struct A {}
@ -452,13 +457,13 @@ impl Future for A {}
fn foo(a: A) {
a.<|>
}
"),
"###),
@r###"
[
CompletionItem {
label: ".await",
source_range: [249; 249),
delete: [247; 249),
source_range: [358; 358),
delete: [356; 358),
insert: "a.await",
detail: "expr.await",
},