mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 20:42:04 +00:00
Implement async blocks
This commit is contained in:
parent
0275b08d15
commit
251ef93ac3
11 changed files with 248 additions and 55 deletions
|
@ -1283,6 +1283,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 {
|
||||||
|
// No special case for the type of async block, since Chalk can figure it out.
|
||||||
|
|
||||||
let krate = self.krate;
|
let krate = self.krate;
|
||||||
|
|
||||||
let std_future_trait =
|
let std_future_trait =
|
||||||
|
|
|
@ -239,7 +239,10 @@ impl ExprCollector<'_> {
|
||||||
None => self.missing_expr(),
|
None => self.missing_expr(),
|
||||||
},
|
},
|
||||||
// FIXME: we need to record these effects somewhere...
|
// FIXME: we need to record these effects somewhere...
|
||||||
ast::Effect::Async(_) => self.collect_block_opt(e.block_expr()),
|
ast::Effect::Async(_) => {
|
||||||
|
let body = self.collect_block_opt(e.block_expr());
|
||||||
|
self.alloc_expr(Expr::Async { body }, syntax_ptr)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ast::Expr::BlockExpr(e) => self.collect_block(e),
|
ast::Expr::BlockExpr(e) => self.collect_block(e),
|
||||||
ast::Expr::LoopExpr(e) => {
|
ast::Expr::LoopExpr(e) => {
|
||||||
|
|
|
@ -111,6 +111,9 @@ pub enum Expr {
|
||||||
TryBlock {
|
TryBlock {
|
||||||
body: ExprId,
|
body: ExprId,
|
||||||
},
|
},
|
||||||
|
Async {
|
||||||
|
body: ExprId,
|
||||||
|
},
|
||||||
Cast {
|
Cast {
|
||||||
expr: ExprId,
|
expr: ExprId,
|
||||||
type_ref: TypeRef,
|
type_ref: TypeRef,
|
||||||
|
@ -250,7 +253,7 @@ impl Expr {
|
||||||
f(*expr);
|
f(*expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body),
|
Expr::TryBlock { body } | Expr::Unsafe { body } | Expr::Async { body } => f(*body),
|
||||||
Expr::Loop { body, .. } => f(*body),
|
Expr::Loop { body, .. } => f(*body),
|
||||||
Expr::While { condition, body, .. } => {
|
Expr::While { condition, body, .. } => {
|
||||||
f(*condition);
|
f(*condition);
|
||||||
|
|
|
@ -381,20 +381,25 @@ impl HirDisplay for ApplicationTy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeCtor::OpaqueType(opaque_ty_id) => {
|
TypeCtor::OpaqueType(opaque_ty_id) => {
|
||||||
let bounds = match opaque_ty_id {
|
match opaque_ty_id {
|
||||||
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
||||||
let datas =
|
let datas =
|
||||||
f.db.return_type_impl_traits(func).expect("impl trait id without data");
|
f.db.return_type_impl_traits(func).expect("impl trait id without data");
|
||||||
let data = (*datas)
|
let data = (*datas)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||||
data.subst(&self.parameters)
|
let bounds = data.subst(&self.parameters);
|
||||||
}
|
|
||||||
};
|
|
||||||
write!(f, "impl ")?;
|
write!(f, "impl ")?;
|
||||||
write_bounds_like_dyn_trait(&bounds.value, f)?;
|
write_bounds_like_dyn_trait(&bounds.value, f)?;
|
||||||
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
|
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
|
||||||
}
|
}
|
||||||
|
OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
|
||||||
|
write!(f, "impl Future<Output = ")?;
|
||||||
|
self.parameters[0].hir_fmt(f)?;
|
||||||
|
write!(f, ">")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
TypeCtor::Closure { .. } => {
|
TypeCtor::Closure { .. } => {
|
||||||
let sig = self.parameters[0].callable_sig(f.db);
|
let sig = self.parameters[0].callable_sig(f.db);
|
||||||
if let Some(sig) = sig {
|
if let Some(sig) = sig {
|
||||||
|
@ -474,19 +479,22 @@ impl HirDisplay for Ty {
|
||||||
write_bounds_like_dyn_trait(predicates, f)?;
|
write_bounds_like_dyn_trait(predicates, f)?;
|
||||||
}
|
}
|
||||||
Ty::Opaque(opaque_ty) => {
|
Ty::Opaque(opaque_ty) => {
|
||||||
let bounds = match opaque_ty.opaque_ty_id {
|
match opaque_ty.opaque_ty_id {
|
||||||
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
||||||
let datas =
|
let datas =
|
||||||
f.db.return_type_impl_traits(func).expect("impl trait id without data");
|
f.db.return_type_impl_traits(func).expect("impl trait id without data");
|
||||||
let data = (*datas)
|
let data = (*datas)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||||
data.subst(&opaque_ty.parameters)
|
let bounds = data.subst(&opaque_ty.parameters);
|
||||||
}
|
|
||||||
};
|
|
||||||
write!(f, "impl ")?;
|
write!(f, "impl ")?;
|
||||||
write_bounds_like_dyn_trait(&bounds.value, f)?;
|
write_bounds_like_dyn_trait(&bounds.value, f)?;
|
||||||
}
|
}
|
||||||
|
OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
|
||||||
|
write!(f, "{{async block}}")?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Ty::Unknown => write!(f, "{{unknown}}")?,
|
Ty::Unknown => write!(f, "{{unknown}}")?,
|
||||||
Ty::Infer(..) => write!(f, "_")?,
|
Ty::Infer(..) => write!(f, "_")?,
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ use crate::{
|
||||||
autoderef, method_resolution, op,
|
autoderef, method_resolution, op,
|
||||||
traits::{FnTrait, InEnvironment},
|
traits::{FnTrait, InEnvironment},
|
||||||
utils::{generics, variant_data, Generics},
|
utils::{generics, variant_data, Generics},
|
||||||
ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs,
|
ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, OpaqueTyId,
|
||||||
TraitRef, Ty, TypeCtor,
|
Rawness, Substs, TraitRef, Ty, TypeCtor,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -146,6 +146,13 @@ impl<'a> InferenceContext<'a> {
|
||||||
// FIXME should be std::result::Result<{inner}, _>
|
// FIXME should be std::result::Result<{inner}, _>
|
||||||
Ty::Unknown
|
Ty::Unknown
|
||||||
}
|
}
|
||||||
|
Expr::Async { body } => {
|
||||||
|
// Use the first type parameter as the output type of future.
|
||||||
|
// existenail type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
|
||||||
|
let inner_ty = self.infer_expr(*body, &Expectation::none());
|
||||||
|
let opaque_ty_id = OpaqueTyId::AsyncBlockTypeImplTrait(self.owner, *body);
|
||||||
|
Ty::apply_one(TypeCtor::OpaqueType(opaque_ty_id), inner_ty)
|
||||||
|
}
|
||||||
Expr::Loop { body, label } => {
|
Expr::Loop { body, label } => {
|
||||||
self.breakables.push(BreakableContext {
|
self.breakables.push(BreakableContext {
|
||||||
may_break: false,
|
may_break: false,
|
||||||
|
|
|
@ -33,6 +33,7 @@ use hir_def::{
|
||||||
AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId,
|
AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId,
|
||||||
TypeParamId,
|
TypeParamId,
|
||||||
};
|
};
|
||||||
|
use hir_expand::name::name;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -129,8 +130,9 @@ pub enum TypeCtor {
|
||||||
|
|
||||||
/// This represents a placeholder for an opaque type in situations where we
|
/// This represents a placeholder for an opaque type in situations where we
|
||||||
/// don't know the hidden type (i.e. currently almost always). This is
|
/// don't know the hidden type (i.e. currently almost always). This is
|
||||||
/// analogous to the `AssociatedType` type constructor. As with that one,
|
/// analogous to the `AssociatedType` type constructor.
|
||||||
/// these are only produced by Chalk.
|
/// It is also used as the type of async block, with one type parameter
|
||||||
|
/// representing the Future::Output type.
|
||||||
OpaqueType(OpaqueTyId),
|
OpaqueType(OpaqueTyId),
|
||||||
|
|
||||||
/// The type of a specific closure.
|
/// The type of a specific closure.
|
||||||
|
@ -173,6 +175,8 @@ impl TypeCtor {
|
||||||
let generic_params = generics(db.upcast(), func.into());
|
let generic_params = generics(db.upcast(), func.into());
|
||||||
generic_params.len()
|
generic_params.len()
|
||||||
}
|
}
|
||||||
|
// 1 param representing Future::Output type.
|
||||||
|
OpaqueTyId::AsyncBlockTypeImplTrait(..) => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1,
|
TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1,
|
||||||
|
@ -205,6 +209,7 @@ impl TypeCtor {
|
||||||
OpaqueTyId::ReturnTypeImplTrait(func, _) => {
|
OpaqueTyId::ReturnTypeImplTrait(func, _) => {
|
||||||
Some(func.lookup(db.upcast()).module(db.upcast()).krate)
|
Some(func.lookup(db.upcast()).module(db.upcast()).krate)
|
||||||
}
|
}
|
||||||
|
OpaqueTyId::AsyncBlockTypeImplTrait(def, _) => Some(def.module(db.upcast()).krate),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -843,6 +848,33 @@ impl Ty {
|
||||||
|
|
||||||
pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> {
|
pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> {
|
||||||
match self {
|
match self {
|
||||||
|
Ty::Apply(ApplicationTy { ctor: TypeCtor::OpaqueType(opaque_ty_id), parameters }) => {
|
||||||
|
match opaque_ty_id {
|
||||||
|
OpaqueTyId::AsyncBlockTypeImplTrait(def, _expr) => {
|
||||||
|
let krate = def.module(db.upcast()).krate;
|
||||||
|
if let Some(future_output) = 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(),
|
||||||
|
});
|
||||||
|
Some(vec![proj])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OpaqueTyId::ReturnTypeImplTrait(..) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
Ty::Opaque(opaque_ty) => {
|
Ty::Opaque(opaque_ty) => {
|
||||||
let predicates = match opaque_ty.opaque_ty_id {
|
let predicates = match opaque_ty.opaque_ty_id {
|
||||||
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
||||||
|
@ -853,6 +885,8 @@ impl Ty {
|
||||||
data.subst(&opaque_ty.parameters)
|
data.subst(&opaque_ty.parameters)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// It always has an parameter for Future::Output type.
|
||||||
|
OpaqueTyId::AsyncBlockTypeImplTrait(..) => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
predicates.map(|it| it.value)
|
predicates.map(|it| it.value)
|
||||||
|
@ -1065,6 +1099,7 @@ impl<T: TypeWalk> TypeWalk for Vec<T> {
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub enum OpaqueTyId {
|
pub enum OpaqueTyId {
|
||||||
ReturnTypeImplTrait(hir_def::FunctionId, u16),
|
ReturnTypeImplTrait(hir_def::FunctionId, u16),
|
||||||
|
AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
|
|
|
@ -1889,31 +1889,40 @@ fn fn_pointer_return() {
|
||||||
fn effects_smoke_test() {
|
fn effects_smoke_test() {
|
||||||
check_infer(
|
check_infer(
|
||||||
r#"
|
r#"
|
||||||
fn main() {
|
async fn main() {
|
||||||
let x = unsafe { 92 };
|
let x = unsafe { 92 };
|
||||||
let y = async { async { () }.await };
|
let y = async { async { () }.await };
|
||||||
let z = try { () };
|
let z = try { () };
|
||||||
let t = 'a: { 92 };
|
let t = 'a: { 92 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[prelude_import] use future::*;
|
||||||
|
|
||||||
|
mod future {
|
||||||
|
#[lang = "future_trait"]
|
||||||
|
pub trait Future { type Output; }
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
10..130 '{ ...2 }; }': ()
|
16..136 '{ ...2 }; }': ()
|
||||||
20..21 'x': i32
|
26..27 'x': i32
|
||||||
24..37 'unsafe { 92 }': i32
|
30..43 'unsafe { 92 }': i32
|
||||||
31..37 '{ 92 }': i32
|
37..43 '{ 92 }': i32
|
||||||
33..35 '92': i32
|
39..41 '92': i32
|
||||||
47..48 'y': {unknown}
|
53..54 'y': impl Future<Output = ()>
|
||||||
57..79 '{ asyn...wait }': {unknown}
|
57..85 'async ...wait }': impl Future<Output = ()>
|
||||||
59..77 'async ....await': {unknown}
|
63..85 '{ asyn...wait }': ()
|
||||||
65..71 '{ () }': ()
|
65..77 'async { () }': impl Future<Output = ()>
|
||||||
67..69 '()': ()
|
65..83 'async ....await': ()
|
||||||
89..90 'z': {unknown}
|
71..77 '{ () }': ()
|
||||||
93..103 'try { () }': {unknown}
|
73..75 '()': ()
|
||||||
97..103 '{ () }': ()
|
95..96 'z': {unknown}
|
||||||
99..101 '()': ()
|
99..109 'try { () }': {unknown}
|
||||||
113..114 't': i32
|
103..109 '{ () }': ()
|
||||||
121..127 '{ 92 }': i32
|
105..107 '()': ()
|
||||||
123..125 '92': i32
|
119..120 't': i32
|
||||||
|
127..133 '{ 92 }': i32
|
||||||
|
129..131 '92': i32
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,46 @@ mod future {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_async_block() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
//- /main.rs crate:main deps:core
|
||||||
|
async fn test() {
|
||||||
|
let a = async { 42 };
|
||||||
|
a;
|
||||||
|
// ^ impl Future<Output = i32>
|
||||||
|
let x = a.await;
|
||||||
|
x;
|
||||||
|
// ^ i32
|
||||||
|
let b = async {}.await;
|
||||||
|
b;
|
||||||
|
// ^ ()
|
||||||
|
let c = async {
|
||||||
|
let y = Option::None;
|
||||||
|
y
|
||||||
|
// ^ Option<u64>
|
||||||
|
};
|
||||||
|
let _: Option<u64> = c.await;
|
||||||
|
c;
|
||||||
|
// ^ impl Future<Output = Option<u64>>
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Option<T> { None, Some(T) }
|
||||||
|
|
||||||
|
//- /core.rs crate:core
|
||||||
|
#[prelude_import] use future::*;
|
||||||
|
mod future {
|
||||||
|
#[lang = "future_trait"]
|
||||||
|
trait Future {
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_try() {
|
fn infer_try() {
|
||||||
check_types(
|
check_types(
|
||||||
|
|
|
@ -11,6 +11,7 @@ use hir_def::{
|
||||||
lang_item::{lang_attr, LangItemTarget},
|
lang_item::{lang_attr, LangItemTarget},
|
||||||
AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId,
|
AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId,
|
||||||
};
|
};
|
||||||
|
use hir_expand::name::name;
|
||||||
|
|
||||||
use super::ChalkContext;
|
use super::ChalkContext;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -18,7 +19,8 @@ use crate::{
|
||||||
display::HirDisplay,
|
display::HirDisplay,
|
||||||
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
|
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
|
||||||
utils::generics,
|
utils::generics,
|
||||||
CallableDefId, DebruijnIndex, FnSig, GenericPredicate, Substs, Ty, TypeCtor,
|
BoundVar, CallableDefId, DebruijnIndex, FnSig, GenericPredicate, ProjectionPredicate,
|
||||||
|
ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
|
||||||
};
|
};
|
||||||
use mapping::{
|
use mapping::{
|
||||||
convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
|
convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
|
||||||
|
@ -166,11 +168,12 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
||||||
fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> {
|
fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> {
|
||||||
let interned_id = crate::db::InternedOpaqueTyId::from(id);
|
let interned_id = crate::db::InternedOpaqueTyId::from(id);
|
||||||
let full_id = self.db.lookup_intern_impl_trait_id(interned_id);
|
let full_id = self.db.lookup_intern_impl_trait_id(interned_id);
|
||||||
let (func, idx) = match full_id {
|
let bound = match full_id {
|
||||||
crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx),
|
crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
||||||
};
|
let datas = self
|
||||||
let datas =
|
.db
|
||||||
self.db.return_type_impl_traits(func).expect("impl trait id without impl traits");
|
.return_type_impl_traits(func)
|
||||||
|
.expect("impl trait id without impl traits");
|
||||||
let data = &datas.value.impl_traits[idx as usize];
|
let data = &datas.value.impl_traits[idx as usize];
|
||||||
let bound = OpaqueTyDatumBound {
|
let bound = OpaqueTyDatumBound {
|
||||||
bounds: make_binders(
|
bounds: make_binders(
|
||||||
|
@ -186,7 +189,65 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
||||||
where_clauses: make_binders(vec![], 0),
|
where_clauses: make_binders(vec![], 0),
|
||||||
};
|
};
|
||||||
let num_vars = datas.num_binders;
|
let num_vars = datas.num_binders;
|
||||||
Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) })
|
make_binders(bound, num_vars)
|
||||||
|
}
|
||||||
|
crate::OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
|
||||||
|
if let Some((future_trait, future_output)) = self
|
||||||
|
.db
|
||||||
|
.lang_item(self.krate, "future_trait".into())
|
||||||
|
.and_then(|item| item.as_trait())
|
||||||
|
.and_then(|trait_| {
|
||||||
|
let alias =
|
||||||
|
self.db.trait_data(trait_).associated_type_by_name(&name![Output])?;
|
||||||
|
Some((trait_, alias))
|
||||||
|
})
|
||||||
|
{
|
||||||
|
// AsyncBlock<T>: Future</* Self */>
|
||||||
|
// This is required by `fn impls_future` to check if we need to provide `.await` completion.
|
||||||
|
let impl_bound = GenericPredicate::Implemented(TraitRef {
|
||||||
|
trait_: future_trait,
|
||||||
|
// Self type as the first parameter.
|
||||||
|
substs: Substs::single(Ty::Bound(BoundVar {
|
||||||
|
debruijn: DebruijnIndex::INNERMOST,
|
||||||
|
index: 0,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
// AsyncBlock<T>: Future</* Self, */ Output = T>;
|
||||||
|
// debruijn: ^1 ^0
|
||||||
|
let proj_bound = GenericPredicate::Projection(ProjectionPredicate {
|
||||||
|
// The parameter of the opaque type.
|
||||||
|
ty: Ty::Bound(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 }),
|
||||||
|
projection_ty: ProjectionTy {
|
||||||
|
associated_ty: future_output,
|
||||||
|
// Self type as the first parameter.
|
||||||
|
parameters: Substs::single(Ty::Bound(BoundVar::new(
|
||||||
|
DebruijnIndex::INNERMOST,
|
||||||
|
0,
|
||||||
|
))),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
let bound = OpaqueTyDatumBound {
|
||||||
|
bounds: make_binders(
|
||||||
|
vec![impl_bound.to_chalk(self.db), proj_bound.to_chalk(self.db)],
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
where_clauses: make_binders(vec![], 0),
|
||||||
|
};
|
||||||
|
// The opaque type has 1 parameter.
|
||||||
|
make_binders(bound, 1)
|
||||||
|
} else {
|
||||||
|
// If failed to find `Future::Output`, return empty bounds as fallback.
|
||||||
|
let bound = OpaqueTyDatumBound {
|
||||||
|
bounds: make_binders(vec![], 0),
|
||||||
|
where_clauses: make_binders(vec![], 0),
|
||||||
|
};
|
||||||
|
// The opaque type has 1 parameter.
|
||||||
|
make_binders(bound, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
|
fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
|
||||||
|
|
|
@ -73,6 +73,9 @@ impl DebugContext<'_> {
|
||||||
crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
|
||||||
write!(f, "{{impl trait {} of {:?}}}", idx, func)?;
|
write!(f, "{{impl trait {} of {:?}}}", idx, func)?;
|
||||||
}
|
}
|
||||||
|
crate::OpaqueTyId::AsyncBlockTypeImplTrait(def, idx) => {
|
||||||
|
write!(f, "{{impl trait of async block {} of {:?}}}", idx.into_raw(), def)?;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
TypeCtor::Closure { def, expr } => {
|
TypeCtor::Closure { def, expr } => {
|
||||||
write!(f, "{{closure {:?} in ", expr.into_raw())?;
|
write!(f, "{{closure {:?} in ", expr.into_raw())?;
|
||||||
|
|
|
@ -506,6 +506,28 @@ pub mod future {
|
||||||
#[lang = "future_trait"]
|
#[lang = "future_trait"]
|
||||||
pub trait Future {}
|
pub trait Future {}
|
||||||
}
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw await expr.await
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
use std::future::*;
|
||||||
|
fn foo() {
|
||||||
|
let a = async {};
|
||||||
|
a.<|>
|
||||||
|
}
|
||||||
|
|
||||||
|
//- /std/lib.rs
|
||||||
|
pub mod future {
|
||||||
|
#[lang = "future_trait"]
|
||||||
|
pub trait Future {
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
kw await expr.await
|
kw await expr.await
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue