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 /crates/hir_ty/src/traits | |
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]>
Diffstat (limited to 'crates/hir_ty/src/traits')
-rw-r--r-- | crates/hir_ty/src/traits/chalk.rs | 105 | ||||
-rw-r--r-- | crates/hir_ty/src/traits/chalk/tls.rs | 3 |
2 files changed, 87 insertions, 21 deletions
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())?; |