diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-09-13 18:28:22 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-09-13 18:28:22 +0100 |
commit | 0d03fe6ef57d3956e92382e0e1f1a916015191cb (patch) | |
tree | 02d51d9e08c50812b895e5b5d1b2fc30ff9150d6 | |
parent | fda6937d7f91dc723229d1045d9a57b22a846dc7 (diff) | |
parent | 529c369c9bc15a73e7a03260eca84ccef99ac281 (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.rs | 7 | ||||
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 5 | ||||
-rw-r--r-- | crates/hir_def/src/expr.rs | 5 | ||||
-rw-r--r-- | crates/hir_ty/src/display.rs | 28 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/expr.rs | 11 | ||||
-rw-r--r-- | crates/hir_ty/src/lib.rs | 34 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/simple.rs | 45 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/traits.rs | 40 | ||||
-rw-r--r-- | crates/hir_ty/src/traits/chalk.rs | 105 | ||||
-rw-r--r-- | crates/hir_ty/src/traits/chalk/tls.rs | 3 | ||||
-rw-r--r-- | crates/ide/src/completion/complete_keyword.rs | 22 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 64 |
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 | ||
24 | use super::{ | 24 | use 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)] |
1066 | pub enum OpaqueTyId { | 1095 | pub 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() { | |||
1889 | fn effects_smoke_test() { | 1889 | fn 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] |
89 | fn infer_async_block() { | ||
90 | check_types( | ||
91 | r#" | ||
92 | //- /main.rs crate:main deps:core | ||
93 | async 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 | |||
113 | enum Option<T> { None, Some(T) } | ||
114 | |||
115 | //- /core.rs crate:core | ||
116 | #[prelude_import] use future::*; | ||
117 | mod future { | ||
118 | #[lang = "future_trait"] | ||
119 | trait Future { | ||
120 | type Output; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | "#, | ||
125 | ); | ||
126 | } | ||
127 | |||
128 | #[test] | ||
89 | fn infer_try() { | 129 | fn 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 | }; |
14 | use hir_expand::name::name; | ||
14 | 15 | ||
15 | use super::ChalkContext; | 16 | use super::ChalkContext; |
16 | use crate::{ | 17 | use 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 | }; |
23 | use mapping::{ | 25 | use 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 | ||
518 | use std::future::*; | ||
519 | fn foo() { | ||
520 | let a = async {}; | ||
521 | a.<|> | ||
522 | } | ||
523 | |||
524 | //- /std/lib.rs | ||
525 | pub 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#" | ||
2653 | struct S; | ||
2654 | fn foo() { | ||
2655 | let fo<|>o = async { S }; | ||
2656 | } | ||
2657 | |||
2658 | #[prelude_import] use future::*; | ||
2659 | mod 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#" |