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