diff options
Diffstat (limited to 'crates/ra_hir_ty/src/lower.rs')
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 143 |
1 files changed, 122 insertions, 21 deletions
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 35ac86a46..dfc018b0b 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -31,8 +31,9 @@ use crate::{ | |||
31 | all_super_trait_refs, associated_type_by_name_including_super_traits, generics, | 31 | all_super_trait_refs, associated_type_by_name_including_super_traits, generics, |
32 | make_mut_slice, variant_data, | 32 | make_mut_slice, variant_data, |
33 | }, | 33 | }, |
34 | Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, | 34 | Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, OpaqueTy, OpaqueTyId, PolyFnSig, |
35 | ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, | 35 | ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substs, |
36 | TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, | ||
36 | }; | 37 | }; |
37 | use hir_expand::name::Name; | 38 | use hir_expand::name::Name; |
38 | 39 | ||
@@ -47,7 +48,16 @@ pub struct TyLoweringContext<'a> { | |||
47 | /// possible currently, so this should be fine for now. | 48 | /// possible currently, so this should be fine for now. |
48 | pub type_param_mode: TypeParamLoweringMode, | 49 | pub type_param_mode: TypeParamLoweringMode, |
49 | pub impl_trait_mode: ImplTraitLoweringMode, | 50 | pub impl_trait_mode: ImplTraitLoweringMode, |
50 | pub impl_trait_counter: std::cell::Cell<u16>, | 51 | impl_trait_counter: std::cell::Cell<u16>, |
52 | /// When turning `impl Trait` into opaque types, we have to collect the | ||
53 | /// bounds at the same time to get the IDs correct (without becoming too | ||
54 | /// complicated). I don't like using interior mutability (as for the | ||
55 | /// counter), but I've tried and failed to make the lifetimes work for | ||
56 | /// passing around a `&mut TyLoweringContext`. The core problem is that | ||
57 | /// we're grouping the mutable data (the counter and this field) together | ||
58 | /// with the immutable context (the references to the DB and resolver). | ||
59 | /// Splitting this up would be a possible fix. | ||
60 | opaque_type_data: std::cell::RefCell<Vec<ReturnTypeImplTrait>>, | ||
51 | } | 61 | } |
52 | 62 | ||
53 | impl<'a> TyLoweringContext<'a> { | 63 | impl<'a> TyLoweringContext<'a> { |
@@ -56,26 +66,42 @@ impl<'a> TyLoweringContext<'a> { | |||
56 | let impl_trait_mode = ImplTraitLoweringMode::Disallowed; | 66 | let impl_trait_mode = ImplTraitLoweringMode::Disallowed; |
57 | let type_param_mode = TypeParamLoweringMode::Placeholder; | 67 | let type_param_mode = TypeParamLoweringMode::Placeholder; |
58 | let in_binders = DebruijnIndex::INNERMOST; | 68 | let in_binders = DebruijnIndex::INNERMOST; |
59 | Self { db, resolver, in_binders, impl_trait_mode, impl_trait_counter, type_param_mode } | 69 | let opaque_type_data = std::cell::RefCell::new(Vec::new()); |
70 | Self { | ||
71 | db, | ||
72 | resolver, | ||
73 | in_binders, | ||
74 | impl_trait_mode, | ||
75 | impl_trait_counter, | ||
76 | type_param_mode, | ||
77 | opaque_type_data, | ||
78 | } | ||
60 | } | 79 | } |
61 | 80 | ||
62 | pub fn with_shifted_in<T>( | 81 | pub fn with_debruijn<T>( |
63 | &self, | 82 | &self, |
64 | debruijn: DebruijnIndex, | 83 | debruijn: DebruijnIndex, |
65 | f: impl FnOnce(&TyLoweringContext) -> T, | 84 | f: impl FnOnce(&TyLoweringContext) -> T, |
66 | ) -> T { | 85 | ) -> T { |
86 | let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); | ||
67 | let new_ctx = Self { | 87 | let new_ctx = Self { |
68 | in_binders: self.in_binders.shifted_in_from(debruijn), | 88 | in_binders: debruijn, |
69 | impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), | 89 | impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), |
90 | opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec), | ||
70 | ..*self | 91 | ..*self |
71 | }; | 92 | }; |
72 | let result = f(&new_ctx); | 93 | let result = f(&new_ctx); |
73 | self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); | 94 | self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); |
95 | self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); | ||
74 | result | 96 | result |
75 | } | 97 | } |
76 | 98 | ||
77 | pub fn shifted_in(self, debruijn: DebruijnIndex) -> Self { | 99 | pub fn with_shifted_in<T>( |
78 | Self { in_binders: self.in_binders.shifted_in_from(debruijn), ..self } | 100 | &self, |
101 | debruijn: DebruijnIndex, | ||
102 | f: impl FnOnce(&TyLoweringContext) -> T, | ||
103 | ) -> T { | ||
104 | self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f) | ||
79 | } | 105 | } |
80 | 106 | ||
81 | pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { | 107 | pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { |
@@ -167,20 +193,47 @@ impl Ty { | |||
167 | TypeRef::ImplTrait(bounds) => { | 193 | TypeRef::ImplTrait(bounds) => { |
168 | match ctx.impl_trait_mode { | 194 | match ctx.impl_trait_mode { |
169 | ImplTraitLoweringMode::Opaque => { | 195 | ImplTraitLoweringMode::Opaque => { |
170 | let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); | 196 | let idx = ctx.impl_trait_counter.get(); |
171 | let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { | 197 | ctx.impl_trait_counter.set(idx + 1); |
172 | bounds | 198 | |
173 | .iter() | 199 | assert!(idx as usize == ctx.opaque_type_data.borrow().len()); |
174 | .flat_map(|b| { | 200 | // this dance is to make sure the data is in the right |
175 | GenericPredicate::from_type_bound(ctx, b, self_ty.clone()) | 201 | // place even if we encounter more opaque types while |
176 | }) | 202 | // lowering the bounds |
177 | .collect() | 203 | ctx.opaque_type_data |
178 | }); | 204 | .borrow_mut() |
179 | Ty::Opaque(predicates) | 205 | .push(ReturnTypeImplTrait { bounds: Binders::new(1, Vec::new()) }); |
206 | // We don't want to lower the bounds inside the binders | ||
207 | // we're currently in, because they don't end up inside | ||
208 | // those binders. E.g. when we have `impl Trait<impl | ||
209 | // OtherTrait<T>>`, the `impl OtherTrait<T>` can't refer | ||
210 | // to the self parameter from `impl Trait`, and the | ||
211 | // bounds aren't actually stored nested within each | ||
212 | // other, but separately. So if the `T` refers to a type | ||
213 | // parameter of the outer function, it's just one binder | ||
214 | // away instead of two. | ||
215 | let actual_opaque_type_data = ctx | ||
216 | .with_debruijn(DebruijnIndex::INNERMOST, |ctx| { | ||
217 | ReturnTypeImplTrait::from_hir(ctx, &bounds) | ||
218 | }); | ||
219 | ctx.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data; | ||
220 | |||
221 | let func = match ctx.resolver.generic_def() { | ||
222 | Some(GenericDefId::FunctionId(f)) => f, | ||
223 | _ => { | ||
224 | // this shouldn't happen | ||
225 | return (Ty::Unknown, None); | ||
226 | } | ||
227 | }; | ||
228 | let impl_trait_id = OpaqueTyId::ReturnTypeImplTrait(func, idx); | ||
229 | let generics = generics(ctx.db.upcast(), func.into()); | ||
230 | let parameters = Substs::bound_vars(&generics, ctx.in_binders); | ||
231 | Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) | ||
180 | } | 232 | } |
181 | ImplTraitLoweringMode::Param => { | 233 | ImplTraitLoweringMode::Param => { |
182 | let idx = ctx.impl_trait_counter.get(); | 234 | let idx = ctx.impl_trait_counter.get(); |
183 | ctx.impl_trait_counter.set(idx + 1); | 235 | // FIXME we're probably doing something wrong here |
236 | ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); | ||
184 | if let Some(def) = ctx.resolver.generic_def() { | 237 | if let Some(def) = ctx.resolver.generic_def() { |
185 | let generics = generics(ctx.db.upcast(), def); | 238 | let generics = generics(ctx.db.upcast(), def); |
186 | let param = generics | 239 | let param = generics |
@@ -197,7 +250,8 @@ impl Ty { | |||
197 | } | 250 | } |
198 | ImplTraitLoweringMode::Variable => { | 251 | ImplTraitLoweringMode::Variable => { |
199 | let idx = ctx.impl_trait_counter.get(); | 252 | let idx = ctx.impl_trait_counter.get(); |
200 | ctx.impl_trait_counter.set(idx + 1); | 253 | // FIXME we're probably doing something wrong here |
254 | ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); | ||
201 | let (parent_params, self_params, list_params, _impl_trait_params) = | 255 | let (parent_params, self_params, list_params, _impl_trait_params) = |
202 | if let Some(def) = ctx.resolver.generic_def() { | 256 | if let Some(def) = ctx.resolver.generic_def() { |
203 | let generics = generics(ctx.db.upcast(), def); | 257 | let generics = generics(ctx.db.upcast(), def); |
@@ -663,6 +717,29 @@ fn assoc_type_bindings_from_type_bound<'a>( | |||
663 | }) | 717 | }) |
664 | } | 718 | } |
665 | 719 | ||
720 | impl ReturnTypeImplTrait { | ||
721 | fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self { | ||
722 | let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); | ||
723 | let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { | ||
724 | bounds | ||
725 | .iter() | ||
726 | .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) | ||
727 | .collect() | ||
728 | }); | ||
729 | ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } | ||
730 | } | ||
731 | } | ||
732 | |||
733 | fn count_impl_traits(type_ref: &TypeRef) -> usize { | ||
734 | let mut count = 0; | ||
735 | type_ref.walk(&mut |type_ref| { | ||
736 | if matches!(type_ref, TypeRef::ImplTrait(_)) { | ||
737 | count += 1; | ||
738 | } | ||
739 | }); | ||
740 | count | ||
741 | } | ||
742 | |||
666 | /// Build the signature of a callable item (function, struct or enum variant). | 743 | /// Build the signature of a callable item (function, struct or enum variant). |
667 | pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { | 744 | pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { |
668 | match def { | 745 | match def { |
@@ -864,7 +941,9 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { | |||
864 | .with_impl_trait_mode(ImplTraitLoweringMode::Variable) | 941 | .with_impl_trait_mode(ImplTraitLoweringMode::Variable) |
865 | .with_type_param_mode(TypeParamLoweringMode::Variable); | 942 | .with_type_param_mode(TypeParamLoweringMode::Variable); |
866 | let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::<Vec<_>>(); | 943 | let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::<Vec<_>>(); |
867 | let ctx_ret = ctx_params.with_impl_trait_mode(ImplTraitLoweringMode::Opaque); | 944 | let ctx_ret = TyLoweringContext::new(db, &resolver) |
945 | .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) | ||
946 | .with_type_param_mode(TypeParamLoweringMode::Variable); | ||
868 | let ret = Ty::from_hir(&ctx_ret, &data.ret_type); | 947 | let ret = Ty::from_hir(&ctx_ret, &data.ret_type); |
869 | let generics = generics(db.upcast(), def.into()); | 948 | let generics = generics(db.upcast(), def.into()); |
870 | let num_binders = generics.len(); | 949 | let num_binders = generics.len(); |
@@ -1084,3 +1163,25 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option< | |||
1084 | TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value))?, | 1163 | TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value))?, |
1085 | )) | 1164 | )) |
1086 | } | 1165 | } |
1166 | |||
1167 | pub(crate) fn return_type_impl_traits( | ||
1168 | db: &impl HirDatabase, | ||
1169 | def: hir_def::FunctionId, | ||
1170 | ) -> Option<Arc<Binders<ReturnTypeImplTraits>>> { | ||
1171 | // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe | ||
1172 | let data = db.function_data(def); | ||
1173 | let resolver = def.resolver(db.upcast()); | ||
1174 | let ctx_ret = TyLoweringContext::new(db, &resolver) | ||
1175 | .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) | ||
1176 | .with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1177 | let _ret = Ty::from_hir(&ctx_ret, &data.ret_type); | ||
1178 | let generics = generics(db.upcast(), def.into()); | ||
1179 | let num_binders = generics.len(); | ||
1180 | let return_type_impl_traits = | ||
1181 | ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() }; | ||
1182 | if return_type_impl_traits.impl_traits.is_empty() { | ||
1183 | None | ||
1184 | } else { | ||
1185 | Some(Arc::new(Binders::new(num_binders, return_type_impl_traits))) | ||
1186 | } | ||
1187 | } | ||