mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 20:09:19 +00:00
Find IntoFuture::IntoFuture's poll method
This commit is contained in:
parent
dc3219bb11
commit
cebf95718c
4 changed files with 65 additions and 10 deletions
|
@ -2777,9 +2777,10 @@ impl Type {
|
||||||
self.ty.is_unknown()
|
self.ty.is_unknown()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that particular type `ty` implements `std::future::Future`.
|
/// Checks that particular type `ty` implements `std::future::IntoFuture` or
|
||||||
|
/// `std::future::Future`.
|
||||||
/// This function is used in `.await` syntax completion.
|
/// This function is used in `.await` syntax completion.
|
||||||
pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
|
pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool {
|
||||||
let trait_ = db
|
let trait_ = db
|
||||||
.lang_item(self.env.krate, SmolStr::new_inline("into_future"))
|
.lang_item(self.env.krate, SmolStr::new_inline("into_future"))
|
||||||
.and_then(|it| {
|
.and_then(|it| {
|
||||||
|
|
|
@ -27,6 +27,7 @@ use hir_def::{
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
builtin_fn_macro::BuiltinFnLikeExpander,
|
builtin_fn_macro::BuiltinFnLikeExpander,
|
||||||
hygiene::Hygiene,
|
hygiene::Hygiene,
|
||||||
|
mod_path::path,
|
||||||
name,
|
name,
|
||||||
name::{AsName, Name},
|
name::{AsName, Name},
|
||||||
HirFileId, InFile,
|
HirFileId, InFile,
|
||||||
|
@ -269,16 +270,35 @@ impl SourceAnalyzer {
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
await_expr: &ast::AwaitExpr,
|
await_expr: &ast::AwaitExpr,
|
||||||
) -> Option<FunctionId> {
|
) -> Option<FunctionId> {
|
||||||
// FIXME This should be pointing to the poll of IntoFuture::Output's Future impl, but I
|
let mut ty = self.ty_of_expr(db, &await_expr.expr()?.into())?.clone();
|
||||||
// don't know how to resolve the Output type so that we can query for its poll method.
|
|
||||||
let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?;
|
|
||||||
|
|
||||||
let op_fn = db
|
let into_future_trait = self
|
||||||
|
.resolver
|
||||||
|
.resolve_known_trait(db.upcast(), &path![core::future::IntoFuture])
|
||||||
|
.map(Trait::from);
|
||||||
|
|
||||||
|
if let Some(into_future_trait) = into_future_trait {
|
||||||
|
let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone());
|
||||||
|
if type_.impls_trait(db, into_future_trait, &[]) {
|
||||||
|
let items = into_future_trait.items(db);
|
||||||
|
let into_future_type = items.into_iter().find_map(|item| match item {
|
||||||
|
AssocItem::TypeAlias(alias)
|
||||||
|
if alias.name(db) == hir_expand::name![IntoFuture] =>
|
||||||
|
{
|
||||||
|
Some(alias)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})?;
|
||||||
|
let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?;
|
||||||
|
ty = future_trait.ty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let poll_fn = db
|
||||||
.lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
|
.lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
|
||||||
.as_function()?;
|
.as_function()?;
|
||||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
|
let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
|
||||||
|
Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
|
||||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_prefix_expr(
|
pub(crate) fn resolve_prefix_expr(
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub(crate) fn complete_dot(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Suggest .await syntax for types that implement Future trait
|
// Suggest .await syntax for types that implement Future trait
|
||||||
if receiver_ty.impls_future(ctx.db) {
|
if receiver_ty.impls_into_future(ctx.db) {
|
||||||
let mut item =
|
let mut item =
|
||||||
CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await");
|
CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await");
|
||||||
item.detail("expr.await");
|
item.detail("expr.await");
|
||||||
|
|
|
@ -1664,6 +1664,40 @@ fn f() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn goto_await_into_future_poll() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- minicore: future
|
||||||
|
|
||||||
|
struct Futurable;
|
||||||
|
|
||||||
|
impl core::future::IntoFuture for Futurable {
|
||||||
|
type IntoFuture = MyFut;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyFut;
|
||||||
|
|
||||||
|
impl core::future::Future for MyFut {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn poll(
|
||||||
|
//^^^^
|
||||||
|
self: std::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>
|
||||||
|
) -> std::task::Poll<Self::Output>
|
||||||
|
{
|
||||||
|
()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
Futurable.await$0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_try_op() {
|
fn goto_try_op() {
|
||||||
check(
|
check(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue