aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/lower.rs
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-03-04 22:00:44 +0000
committerFlorian Diebold <[email protected]>2020-06-05 16:08:27 +0100
commit02962b374ecefd6f2a75956f4fb18806531d1d51 (patch)
tree7c807d6a09db7e485ea39c3e67331b99829a364c /crates/ra_hir_ty/src/lower.rs
parent9c52f527a1cef7d39c2b1c55b49dc5459d392a4d (diff)
Implement return position impl trait / opaque type support
This is working, but I'm not that happy with how the lowering works. We might need an additional representation between `TypeRef` and `Ty` where names are resolved and `impl Trait` bounds are separated out, but things like inference variables don't exist and `impl Trait` is always represented the same way. Also note that this doesn't implement correct handling of RPIT *inside* the function (which involves turning the `impl Trait`s into variables and creating obligations for them). That intermediate representation might help there as well.
Diffstat (limited to 'crates/ra_hir_ty/src/lower.rs')
-rw-r--r--crates/ra_hir_ty/src/lower.rs143
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};
37use hir_expand::name::Name; 38use 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
53impl<'a> TyLoweringContext<'a> { 63impl<'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
720impl 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
733fn 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).
667pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { 744pub 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
1167pub(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}