aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-09-13 18:28:22 +0100
committerGitHub <[email protected]>2020-09-13 18:28:22 +0100
commit0d03fe6ef57d3956e92382e0e1f1a916015191cb (patch)
tree02d51d9e08c50812b895e5b5d1b2fc30ff9150d6
parentfda6937d7f91dc723229d1045d9a57b22a846dc7 (diff)
parent529c369c9bc15a73e7a03260eca84ccef99ac281 (diff)
Merge #5971
5971: Implement async blocks r=flodiebold a=oxalica Fix #4018 @flodiebold already gave a generic guide in the issue. Here's some concern about implementation detail: - Chalk doesn't support generator type yet. - Adding generator type as a brand new type (ctor) can be complex and need to *re-introduced* builtin impls. (Like how we implement closures before native closure support of chalk, which is already removed in #5401 ) - The output type of async block should be known after type inference of the whole body. - We cannot directly get the type from source like return-positon-impl-trait. But we still need to provide trait bounds when chalk asking for `opaque_ty_data`. - During the inference, the output type of async block can be temporary unknown and participate the later inference. `let a = async { None }; let _: i32 = a.await.unwrap();` So in this PR, the type of async blocks is inferred as an opaque type parameterized by the `Future::Output` type it should be, like what we do with closure type. And it really works now. Well, I still have some questions: - The bounds `AsyncBlockImplType<T>: Future<Output = T>` is currently generated in `opaque_ty_data`. I'm not sure if we should put this code here. - Type of async block is now rendered as `impl Future<Output = OutputType>`. Do we need to special display to hint that it's a async block? Note that closure type has its special format, instead of `impl Fn(..) -> ..` or function type. Co-authored-by: oxalica <[email protected]>
-rw-r--r--crates/hir/src/code_model.rs7
-rw-r--r--crates/hir_def/src/body/lower.rs5
-rw-r--r--crates/hir_def/src/expr.rs5
-rw-r--r--crates/hir_ty/src/display.rs28
-rw-r--r--crates/hir_ty/src/infer/expr.rs11
-rw-r--r--crates/hir_ty/src/lib.rs34
-rw-r--r--crates/hir_ty/src/tests/simple.rs45
-rw-r--r--crates/hir_ty/src/tests/traits.rs40
-rw-r--r--crates/hir_ty/src/traits/chalk.rs105
-rw-r--r--crates/hir_ty/src/traits/chalk/tls.rs3
-rw-r--r--crates/ide/src/completion/complete_keyword.rs22
-rw-r--r--crates/ide/src/hover.rs64
12 files changed, 314 insertions, 55 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index c2fc819e7..7a9747fc7 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -1283,6 +1283,8 @@ impl Type {
1283 /// Checks that particular type `ty` implements `std::future::Future`. 1283 /// Checks that particular type `ty` implements `std::future::Future`.
1284 /// This function is used in `.await` syntax completion. 1284 /// This function is used in `.await` syntax completion.
1285 pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { 1285 pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
1286 // No special case for the type of async block, since Chalk can figure it out.
1287
1286 let krate = self.krate; 1288 let krate = self.krate;
1287 1289
1288 let std_future_trait = 1290 let std_future_trait =
@@ -1600,6 +1602,11 @@ impl Type {
1600 cb(type_.derived(ty.clone())); 1602 cb(type_.derived(ty.clone()));
1601 } 1603 }
1602 } 1604 }
1605 TypeCtor::OpaqueType(..) => {
1606 if let Some(bounds) = ty.impl_trait_bounds(db) {
1607 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1608 }
1609 }
1603 _ => (), 1610 _ => (),
1604 } 1611 }
1605 1612
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 9ea3d5291..2d91bb21f 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -239,7 +239,10 @@ impl ExprCollector<'_> {
239 None => self.missing_expr(), 239 None => self.missing_expr(),
240 }, 240 },
241 // FIXME: we need to record these effects somewhere... 241 // FIXME: we need to record these effects somewhere...
242 ast::Effect::Async(_) => self.collect_block_opt(e.block_expr()), 242 ast::Effect::Async(_) => {
243 let body = self.collect_block_opt(e.block_expr());
244 self.alloc_expr(Expr::Async { body }, syntax_ptr)
245 }
243 }, 246 },
244 ast::Expr::BlockExpr(e) => self.collect_block(e), 247 ast::Expr::BlockExpr(e) => self.collect_block(e),
245 ast::Expr::LoopExpr(e) => { 248 ast::Expr::LoopExpr(e) => {
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index dc975d42f..e5d740a36 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -111,6 +111,9 @@ pub enum Expr {
111 TryBlock { 111 TryBlock {
112 body: ExprId, 112 body: ExprId,
113 }, 113 },
114 Async {
115 body: ExprId,
116 },
114 Cast { 117 Cast {
115 expr: ExprId, 118 expr: ExprId,
116 type_ref: TypeRef, 119 type_ref: TypeRef,
@@ -250,7 +253,7 @@ impl Expr {
250 f(*expr); 253 f(*expr);
251 } 254 }
252 } 255 }
253 Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body), 256 Expr::TryBlock { body } | Expr::Unsafe { body } | Expr::Async { body } => f(*body),
254 Expr::Loop { body, .. } => f(*body), 257 Expr::Loop { body, .. } => f(*body),
255 Expr::While { condition, body, .. } => { 258 Expr::While { condition, body, .. } => {
256 f(*condition); 259 f(*condition);
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 64b68014d..efb48c7ee 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -381,19 +381,24 @@ impl HirDisplay for ApplicationTy {
381 } 381 }
382 } 382 }
383 TypeCtor::OpaqueType(opaque_ty_id) => { 383 TypeCtor::OpaqueType(opaque_ty_id) => {
384 let bounds = match opaque_ty_id { 384 match opaque_ty_id {
385 OpaqueTyId::ReturnTypeImplTrait(func, idx) => { 385 OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
386 let datas = 386 let datas =
387 f.db.return_type_impl_traits(func).expect("impl trait id without data"); 387 f.db.return_type_impl_traits(func).expect("impl trait id without data");
388 let data = (*datas) 388 let data = (*datas)
389 .as_ref() 389 .as_ref()
390 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 390 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
391 data.subst(&self.parameters) 391 let bounds = data.subst(&self.parameters);
392 write!(f, "impl ")?;
393 write_bounds_like_dyn_trait(&bounds.value, f)?;
394 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
392 } 395 }
393 }; 396 OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
394 write!(f, "impl ")?; 397 write!(f, "impl Future<Output = ")?;
395 write_bounds_like_dyn_trait(&bounds.value, f)?; 398 self.parameters[0].hir_fmt(f)?;
396 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution 399 write!(f, ">")?;
400 }
401 }
397 } 402 }
398 TypeCtor::Closure { .. } => { 403 TypeCtor::Closure { .. } => {
399 let sig = self.parameters[0].callable_sig(f.db); 404 let sig = self.parameters[0].callable_sig(f.db);
@@ -474,18 +479,21 @@ impl HirDisplay for Ty {
474 write_bounds_like_dyn_trait(predicates, f)?; 479 write_bounds_like_dyn_trait(predicates, f)?;
475 } 480 }
476 Ty::Opaque(opaque_ty) => { 481 Ty::Opaque(opaque_ty) => {
477 let bounds = match opaque_ty.opaque_ty_id { 482 match opaque_ty.opaque_ty_id {
478 OpaqueTyId::ReturnTypeImplTrait(func, idx) => { 483 OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
479 let datas = 484 let datas =
480 f.db.return_type_impl_traits(func).expect("impl trait id without data"); 485 f.db.return_type_impl_traits(func).expect("impl trait id without data");
481 let data = (*datas) 486 let data = (*datas)
482 .as_ref() 487 .as_ref()
483 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 488 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
484 data.subst(&opaque_ty.parameters) 489 let bounds = data.subst(&opaque_ty.parameters);
490 write!(f, "impl ")?;
491 write_bounds_like_dyn_trait(&bounds.value, f)?;
492 }
493 OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
494 write!(f, "{{async block}}")?;
485 } 495 }
486 }; 496 };
487 write!(f, "impl ")?;
488 write_bounds_like_dyn_trait(&bounds.value, f)?;
489 } 497 }
490 Ty::Unknown => write!(f, "{{unknown}}")?, 498 Ty::Unknown => write!(f, "{{unknown}}")?,
491 Ty::Infer(..) => write!(f, "_")?, 499 Ty::Infer(..) => write!(f, "_")?,
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index a2f849d02..0a141b9cb 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -17,8 +17,8 @@ use crate::{
17 autoderef, method_resolution, op, 17 autoderef, method_resolution, op,
18 traits::{FnTrait, InEnvironment}, 18 traits::{FnTrait, InEnvironment},
19 utils::{generics, variant_data, Generics}, 19 utils::{generics, variant_data, Generics},
20 ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, 20 ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, OpaqueTyId,
21 TraitRef, Ty, TypeCtor, 21 Rawness, Substs, TraitRef, Ty, TypeCtor,
22}; 22};
23 23
24use super::{ 24use super::{
@@ -146,6 +146,13 @@ impl<'a> InferenceContext<'a> {
146 // FIXME should be std::result::Result<{inner}, _> 146 // FIXME should be std::result::Result<{inner}, _>
147 Ty::Unknown 147 Ty::Unknown
148 } 148 }
149 Expr::Async { body } => {
150 // Use the first type parameter as the output type of future.
151 // existenail type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
152 let inner_ty = self.infer_expr(*body, &Expectation::none());
153 let opaque_ty_id = OpaqueTyId::AsyncBlockTypeImplTrait(self.owner, *body);
154 Ty::apply_one(TypeCtor::OpaqueType(opaque_ty_id), inner_ty)
155 }
149 Expr::Loop { body, label } => { 156 Expr::Loop { body, label } => {
150 self.breakables.push(BreakableContext { 157 self.breakables.push(BreakableContext {
151 may_break: false, 158 may_break: false,
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 1e748476a..f16d1fc97 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -129,8 +129,9 @@ pub enum TypeCtor {
129 129
130 /// This represents a placeholder for an opaque type in situations where we 130 /// This represents a placeholder for an opaque type in situations where we
131 /// don't know the hidden type (i.e. currently almost always). This is 131 /// don't know the hidden type (i.e. currently almost always). This is
132 /// analogous to the `AssociatedType` type constructor. As with that one, 132 /// analogous to the `AssociatedType` type constructor.
133 /// these are only produced by Chalk. 133 /// It is also used as the type of async block, with one type parameter
134 /// representing the Future::Output type.
134 OpaqueType(OpaqueTyId), 135 OpaqueType(OpaqueTyId),
135 136
136 /// The type of a specific closure. 137 /// The type of a specific closure.
@@ -173,6 +174,8 @@ impl TypeCtor {
173 let generic_params = generics(db.upcast(), func.into()); 174 let generic_params = generics(db.upcast(), func.into());
174 generic_params.len() 175 generic_params.len()
175 } 176 }
177 // 1 param representing Future::Output type.
178 OpaqueTyId::AsyncBlockTypeImplTrait(..) => 1,
176 } 179 }
177 } 180 }
178 TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1, 181 TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1,
@@ -205,6 +208,7 @@ impl TypeCtor {
205 OpaqueTyId::ReturnTypeImplTrait(func, _) => { 208 OpaqueTyId::ReturnTypeImplTrait(func, _) => {
206 Some(func.lookup(db.upcast()).module(db.upcast()).krate) 209 Some(func.lookup(db.upcast()).module(db.upcast()).krate)
207 } 210 }
211 OpaqueTyId::AsyncBlockTypeImplTrait(def, _) => Some(def.module(db.upcast()).krate),
208 }, 212 },
209 } 213 }
210 } 214 }
@@ -843,6 +847,29 @@ impl Ty {
843 847
844 pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> { 848 pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> {
845 match self { 849 match self {
850 Ty::Apply(ApplicationTy { ctor: TypeCtor::OpaqueType(opaque_ty_id), .. }) => {
851 match opaque_ty_id {
852 OpaqueTyId::AsyncBlockTypeImplTrait(def, _expr) => {
853 let krate = def.module(db.upcast()).krate;
854 if let Some(future_trait) = db
855 .lang_item(krate, "future_trait".into())
856 .and_then(|item| item.as_trait())
857 {
858 // This is only used by type walking.
859 // Parameters will be walked outside, and projection predicate is not used.
860 // So just provide the Future trait.
861 let impl_bound = GenericPredicate::Implemented(TraitRef {
862 trait_: future_trait,
863 substs: Substs::empty(),
864 });
865 Some(vec![impl_bound])
866 } else {
867 None
868 }
869 }
870 OpaqueTyId::ReturnTypeImplTrait(..) => None,
871 }
872 }
846 Ty::Opaque(opaque_ty) => { 873 Ty::Opaque(opaque_ty) => {
847 let predicates = match opaque_ty.opaque_ty_id { 874 let predicates = match opaque_ty.opaque_ty_id {
848 OpaqueTyId::ReturnTypeImplTrait(func, idx) => { 875 OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
@@ -853,6 +880,8 @@ impl Ty {
853 data.subst(&opaque_ty.parameters) 880 data.subst(&opaque_ty.parameters)
854 }) 881 })
855 } 882 }
883 // It always has an parameter for Future::Output type.
884 OpaqueTyId::AsyncBlockTypeImplTrait(..) => unreachable!(),
856 }; 885 };
857 886
858 predicates.map(|it| it.value) 887 predicates.map(|it| it.value)
@@ -1065,6 +1094,7 @@ impl<T: TypeWalk> TypeWalk for Vec<T> {
1065#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 1094#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
1066pub enum OpaqueTyId { 1095pub enum OpaqueTyId {
1067 ReturnTypeImplTrait(hir_def::FunctionId, u16), 1096 ReturnTypeImplTrait(hir_def::FunctionId, u16),
1097 AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
1068} 1098}
1069 1099
1070#[derive(Clone, PartialEq, Eq, Debug, Hash)] 1100#[derive(Clone, PartialEq, Eq, Debug, Hash)]
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 48db23a34..5b07948f3 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1889,31 +1889,40 @@ fn fn_pointer_return() {
1889fn effects_smoke_test() { 1889fn effects_smoke_test() {
1890 check_infer( 1890 check_infer(
1891 r#" 1891 r#"
1892 fn main() { 1892 async fn main() {
1893 let x = unsafe { 92 }; 1893 let x = unsafe { 92 };
1894 let y = async { async { () }.await }; 1894 let y = async { async { () }.await };
1895 let z = try { () }; 1895 let z = try { () };
1896 let t = 'a: { 92 }; 1896 let t = 'a: { 92 };
1897 } 1897 }
1898
1899 #[prelude_import] use future::*;
1900
1901 mod future {
1902 #[lang = "future_trait"]
1903 pub trait Future { type Output; }
1904 }
1898 "#, 1905 "#,
1899 expect![[r#" 1906 expect![[r#"
1900 10..130 '{ ...2 }; }': () 1907 16..136 '{ ...2 }; }': ()
1901 20..21 'x': i32 1908 26..27 'x': i32
1902 24..37 'unsafe { 92 }': i32 1909 30..43 'unsafe { 92 }': i32
1903 31..37 '{ 92 }': i32 1910 37..43 '{ 92 }': i32
1904 33..35 '92': i32 1911 39..41 '92': i32
1905 47..48 'y': {unknown} 1912 53..54 'y': impl Future<Output = ()>
1906 57..79 '{ asyn...wait }': {unknown} 1913 57..85 'async ...wait }': impl Future<Output = ()>
1907 59..77 'async ....await': {unknown} 1914 63..85 '{ asyn...wait }': ()
1908 65..71 '{ () }': () 1915 65..77 'async { () }': impl Future<Output = ()>
1909 67..69 '()': () 1916 65..83 'async ....await': ()
1910 89..90 'z': {unknown} 1917 71..77 '{ () }': ()
1911 93..103 'try { () }': {unknown} 1918 73..75 '()': ()
1912 97..103 '{ () }': () 1919 95..96 'z': {unknown}
1913 99..101 '()': () 1920 99..109 'try { () }': {unknown}
1914 113..114 't': i32 1921 103..109 '{ () }': ()
1915 121..127 '{ 92 }': i32 1922 105..107 '()': ()
1916 123..125 '92': i32 1923 119..120 't': i32
1924 127..133 '{ 92 }': i32
1925 129..131 '92': i32
1917 "#]], 1926 "#]],
1918 ) 1927 )
1919} 1928}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 1f1056962..41d097519 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -86,6 +86,46 @@ mod future {
86} 86}
87 87
88#[test] 88#[test]
89fn infer_async_block() {
90 check_types(
91 r#"
92//- /main.rs crate:main deps:core
93async fn test() {
94 let a = async { 42 };
95 a;
96// ^ impl Future<Output = i32>
97 let x = a.await;
98 x;
99// ^ i32
100 let b = async {}.await;
101 b;
102// ^ ()
103 let c = async {
104 let y = Option::None;
105 y
106 // ^ Option<u64>
107 };
108 let _: Option<u64> = c.await;
109 c;
110// ^ impl Future<Output = Option<u64>>
111}
112
113enum Option<T> { None, Some(T) }
114
115//- /core.rs crate:core
116#[prelude_import] use future::*;
117mod future {
118 #[lang = "future_trait"]
119 trait Future {
120 type Output;
121 }
122}
123
124"#,
125 );
126}
127
128#[test]
89fn infer_try() { 129fn infer_try() {
90 check_types( 130 check_types(
91 r#" 131 r#"
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 01b5717a3..57d0a32df 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -11,6 +11,7 @@ use hir_def::{
11 lang_item::{lang_attr, LangItemTarget}, 11 lang_item::{lang_attr, LangItemTarget},
12 AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, 12 AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId,
13}; 13};
14use hir_expand::name::name;
14 15
15use super::ChalkContext; 16use super::ChalkContext;
16use crate::{ 17use crate::{
@@ -18,7 +19,8 @@ use crate::{
18 display::HirDisplay, 19 display::HirDisplay,
19 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, 20 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
20 utils::generics, 21 utils::generics,
21 CallableDefId, DebruijnIndex, FnSig, GenericPredicate, Substs, Ty, TypeCtor, 22 BoundVar, CallableDefId, DebruijnIndex, FnSig, GenericPredicate, ProjectionPredicate,
23 ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
22}; 24};
23use mapping::{ 25use mapping::{
24 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, 26 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
@@ -166,27 +168,88 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
166 fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> { 168 fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> {
167 let interned_id = crate::db::InternedOpaqueTyId::from(id); 169 let interned_id = crate::db::InternedOpaqueTyId::from(id);
168 let full_id = self.db.lookup_intern_impl_trait_id(interned_id); 170 let full_id = self.db.lookup_intern_impl_trait_id(interned_id);
169 let (func, idx) = match full_id { 171 let bound = match full_id {
170 crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx), 172 crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
171 }; 173 let datas = self
172 let datas = 174 .db
173 self.db.return_type_impl_traits(func).expect("impl trait id without impl traits"); 175 .return_type_impl_traits(func)
174 let data = &datas.value.impl_traits[idx as usize]; 176 .expect("impl trait id without impl traits");
175 let bound = OpaqueTyDatumBound { 177 let data = &datas.value.impl_traits[idx as usize];
176 bounds: make_binders( 178 let bound = OpaqueTyDatumBound {
177 data.bounds 179 bounds: make_binders(
178 .value 180 data.bounds
179 .iter() 181 .value
180 .cloned() 182 .iter()
181 .filter(|b| !b.is_error()) 183 .cloned()
182 .map(|b| b.to_chalk(self.db)) 184 .filter(|b| !b.is_error())
183 .collect(), 185 .map(|b| b.to_chalk(self.db))
184 1, 186 .collect(),
185 ), 187 1,
186 where_clauses: make_binders(vec![], 0), 188 ),
189 where_clauses: make_binders(vec![], 0),
190 };
191 let num_vars = datas.num_binders;
192 make_binders(bound, num_vars)
193 }
194 crate::OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
195 if let Some((future_trait, future_output)) = self
196 .db
197 .lang_item(self.krate, "future_trait".into())
198 .and_then(|item| item.as_trait())
199 .and_then(|trait_| {
200 let alias =
201 self.db.trait_data(trait_).associated_type_by_name(&name![Output])?;
202 Some((trait_, alias))
203 })
204 {
205 // Making up `AsyncBlock<T>: Future<Output = T>`
206 //
207 // |--------------------OpaqueTyDatum-------------------|
208 // |-------------OpaqueTyDatumBound--------------|
209 // for<T> <Self> [Future<Self>, Future::Output<Self> = T]
210 // ^1 ^0 ^0 ^0 ^1
211 let impl_bound = GenericPredicate::Implemented(TraitRef {
212 trait_: future_trait,
213 // Self type as the first parameter.
214 substs: Substs::single(Ty::Bound(BoundVar {
215 debruijn: DebruijnIndex::INNERMOST,
216 index: 0,
217 })),
218 });
219 let proj_bound = GenericPredicate::Projection(ProjectionPredicate {
220 // The parameter of the opaque type.
221 ty: Ty::Bound(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 }),
222 projection_ty: ProjectionTy {
223 associated_ty: future_output,
224 // Self type as the first parameter.
225 parameters: Substs::single(Ty::Bound(BoundVar::new(
226 DebruijnIndex::INNERMOST,
227 0,
228 ))),
229 },
230 });
231 let bound = OpaqueTyDatumBound {
232 bounds: make_binders(
233 vec![impl_bound.to_chalk(self.db), proj_bound.to_chalk(self.db)],
234 1,
235 ),
236 where_clauses: make_binders(vec![], 0),
237 };
238 // The opaque type has 1 parameter.
239 make_binders(bound, 1)
240 } else {
241 // If failed to find `Future::Output`, return empty bounds as fallback.
242 let bound = OpaqueTyDatumBound {
243 bounds: make_binders(vec![], 0),
244 where_clauses: make_binders(vec![], 0),
245 };
246 // The opaque type has 1 parameter.
247 make_binders(bound, 1)
248 }
249 }
187 }; 250 };
188 let num_vars = datas.num_binders; 251
189 Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) }) 252 Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound })
190 } 253 }
191 254
192 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { 255 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
diff --git a/crates/hir_ty/src/traits/chalk/tls.rs b/crates/hir_ty/src/traits/chalk/tls.rs
index db915625c..cb6b0fe81 100644
--- a/crates/hir_ty/src/traits/chalk/tls.rs
+++ b/crates/hir_ty/src/traits/chalk/tls.rs
@@ -73,6 +73,9 @@ impl DebugContext<'_> {
73 crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { 73 crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
74 write!(f, "{{impl trait {} of {:?}}}", idx, func)?; 74 write!(f, "{{impl trait {} of {:?}}}", idx, func)?;
75 } 75 }
76 crate::OpaqueTyId::AsyncBlockTypeImplTrait(def, idx) => {
77 write!(f, "{{impl trait of async block {} of {:?}}}", idx.into_raw(), def)?;
78 }
76 }, 79 },
77 TypeCtor::Closure { def, expr } => { 80 TypeCtor::Closure { def, expr } => {
78 write!(f, "{{closure {:?} in ", expr.into_raw())?; 81 write!(f, "{{closure {:?} in ", expr.into_raw())?;
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/ide/src/completion/complete_keyword.rs
index 53ba76e0e..5645b41fa 100644
--- a/crates/ide/src/completion/complete_keyword.rs
+++ b/crates/ide/src/completion/complete_keyword.rs
@@ -510,6 +510,28 @@ pub mod future {
510 expect![[r#" 510 expect![[r#"
511 kw await expr.await 511 kw await expr.await
512 "#]], 512 "#]],
513 );
514
515 check(
516 r#"
517//- /main.rs
518use std::future::*;
519fn foo() {
520 let a = async {};
521 a.<|>
522}
523
524//- /std/lib.rs
525pub mod future {
526 #[lang = "future_trait"]
527 pub trait Future {
528 type Output;
529 }
530}
531"#,
532 expect![[r#"
533 kw await expr.await
534 "#]],
513 ) 535 )
514 } 536 }
515 537
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index efec0184e..37171cbef 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -2647,6 +2647,70 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
2647 } 2647 }
2648 2648
2649 #[test] 2649 #[test]
2650 fn test_hover_async_block_impl_trait_has_goto_type_action() {
2651 check_actions(
2652 r#"
2653struct S;
2654fn foo() {
2655 let fo<|>o = async { S };
2656}
2657
2658#[prelude_import] use future::*;
2659mod future {
2660 #[lang = "future_trait"]
2661 pub trait Future { type Output; }
2662}
2663"#,
2664 expect![[r#"
2665 [
2666 GoToType(
2667 [
2668 HoverGotoTypeData {
2669 mod_path: "test::future::Future",
2670 nav: NavigationTarget {
2671 file_id: FileId(
2672 1,
2673 ),
2674 full_range: 101..163,
2675 focus_range: Some(
2676 140..146,
2677 ),
2678 name: "Future",
2679 kind: TRAIT,
2680 container_name: None,
2681 description: Some(
2682 "pub trait Future",
2683 ),
2684 docs: None,
2685 },
2686 },
2687 HoverGotoTypeData {
2688 mod_path: "test::S",
2689 nav: NavigationTarget {
2690 file_id: FileId(
2691 1,
2692 ),
2693 full_range: 0..9,
2694 focus_range: Some(
2695 7..8,
2696 ),
2697 name: "S",
2698 kind: STRUCT,
2699 container_name: None,
2700 description: Some(
2701 "struct S",
2702 ),
2703 docs: None,
2704 },
2705 },
2706 ],
2707 ),
2708 ]
2709 "#]],
2710 );
2711 }
2712
2713 #[test]
2650 fn test_hover_arg_generic_impl_trait_has_goto_type_action() { 2714 fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
2651 check_actions( 2715 check_actions(
2652 r#" 2716 r#"