Implement IntoFuture type inference

This commit is contained in:
Justin Ridgewell 2022-08-08 20:20:45 -04:00
parent 3792720086
commit 5810c8188a
9 changed files with 75 additions and 22 deletions

View File

@ -257,6 +257,7 @@ macro_rules! __known_path {
(core::ops::RangeToInclusive) => {}; (core::ops::RangeToInclusive) => {};
(core::ops::RangeInclusive) => {}; (core::ops::RangeInclusive) => {};
(core::future::Future) => {}; (core::future::Future) => {};
(core::future::IntoFuture) => {};
(core::ops::Try) => {}; (core::ops::Try) => {};
($path:path) => { ($path:path) => {
compile_error!("Please register your known path in the path module") compile_error!("Please register your known path in the path module")

View File

@ -258,6 +258,7 @@ pub mod known {
Try, Try,
Ok, Ok,
Future, Future,
IntoFuture,
Result, Result,
Option, Option,
Output, Output,
@ -391,6 +392,7 @@ pub mod known {
future_trait, future_trait,
index, index,
index_mut, index_mut,
into_future,
mul_assign, mul_assign,
mul, mul,
neg, neg,

View File

@ -875,7 +875,10 @@ impl<'a> InferenceContext<'a> {
} }
fn resolve_future_future_output(&self) -> Option<TypeAliasId> { fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?; let trait_ = self
.resolver
.resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
.or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
self.db.trait_data(trait_).associated_type_by_name(&name![Output]) self.db.trait_data(trait_).associated_type_by_name(&name![Output])
} }

View File

@ -137,6 +137,31 @@ fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
); );
} }
#[test]
fn into_future_trait() {
check_types(
r#"
//- minicore: future
struct Futurable;
impl core::future::IntoFuture for Futurable {
type Output = u64;
type IntoFuture = IntFuture;
}
struct IntFuture;
impl core::future::Future for IntFuture {
type Output = u64;
}
fn test() {
let r = Futurable;
let v = r.await;
v;
} //^ u64
"#,
);
}
#[test] #[test]
fn infer_try() { fn infer_try() {
check_types( check_types(

View File

@ -2780,6 +2780,8 @@ impl Type {
/// Checks that particular type `ty` implements `std::future::Future`. /// Checks that particular type `ty` implements `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_future(&self, db: &dyn HirDatabase) -> bool {
// FIXME: This should be checking for IntoFuture trait, but I don't know how to find the
// right TraitId in this crate.
let std_future_trait = db let std_future_trait = db
.lang_item(self.env.krate, SmolStr::new_inline("future_trait")) .lang_item(self.env.krate, SmolStr::new_inline("future_trait"))
.and_then(|it| it.as_trait()); .and_then(|it| it.as_trait());

View File

@ -269,6 +269,8 @@ 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
// 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 ty = self.ty_of_expr(db, &await_expr.expr()?.into())?;
let op_fn = db let op_fn = db

View File

@ -55,6 +55,7 @@ const USELESS_METHODS: &[&str] = &[
"iter", "iter",
"into_iter", "into_iter",
"iter_mut", "iter_mut",
"into_future",
]; ];
pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr { pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {

View File

@ -75,16 +75,17 @@ impl Future for A {}
fn foo(a: A) { a.$0 } fn foo(a: A) { a.$0 }
"#, "#,
expect![[r#" expect![[r#"
kw await expr.await kw await expr.await
sn box Box::new(expr) me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
sn call function(expr) sn box Box::new(expr)
sn dbg dbg!(expr) sn call function(expr)
sn dbgr dbg!(&expr) sn dbg dbg!(expr)
sn let let sn dbgr dbg!(&expr)
sn letm let mut sn let let
sn match match expr {} sn letm let mut
sn ref &expr sn match match expr {}
sn refm &mut expr sn ref &expr
sn refm &mut expr
"#]], "#]],
); );
@ -98,18 +99,19 @@ fn foo() {
} }
"#, "#,
expect![[r#" expect![[r#"
kw await expr.await kw await expr.await
sn box Box::new(expr) me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
sn call function(expr) sn box Box::new(expr)
sn dbg dbg!(expr) sn call function(expr)
sn dbgr dbg!(&expr) sn dbg dbg!(expr)
sn let let sn dbgr dbg!(&expr)
sn letm let mut sn let let
sn match match expr {} sn letm let mut
sn ref &expr sn match match expr {}
sn refm &mut expr sn ref &expr
sn refm &mut expr
"#]], "#]],
) );
} }
#[test] #[test]

View File

@ -471,6 +471,21 @@ pub mod future {
#[lang = "poll"] #[lang = "poll"]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
} }
pub trait IntoFuture {
type Output;
type IntoFuture: Future<Output = Self::Output>;
#[lang = "into_future"]
fn into_future(self) -> Self::IntoFuture;
}
impl<F: Future> IntoFuture for F {
type Output = F::Output;
type IntoFuture = F;
fn into_future(self) -> F {
self
}
}
} }
pub mod task { pub mod task {
pub enum Poll<T> { pub enum Poll<T> {