Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower.rs')
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 108 |
1 files changed, 69 insertions, 39 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index b1a7ad3e94..86abe1af68 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -36,7 +36,7 @@ use hir_def::{ use hir_expand::{name::Name, ExpandResult}; use intern::Interned; use itertools::Either; -use la_arena::ArenaMap; +use la_arena::{Arena, ArenaMap}; use rustc_hash::FxHashSet; use smallvec::SmallVec; use stdx::{impl_from, never}; @@ -58,6 +58,51 @@ use crate::{ }; #[derive(Debug)] +enum ImplTraitLoweringState { + /// When turning `impl Trait` into opaque types, we have to collect the + /// bounds at the same time to get the IDs correct (without becoming too + /// complicated). I don't like using interior mutability (as for the + /// counter), but I've tried and failed to make the lifetimes work for + /// passing around a `&mut TyLoweringContext`. The core problem is that + /// we're grouping the mutable data (the counter and this field) together + /// with the immutable context (the references to the DB and resolver). + /// Splitting this up would be a possible fix. + Opaque(RefCell<Arena<ReturnTypeImplTrait>>), + Param(Cell<u16>), + Variable(Cell<u16>), + Disallowed, +} +impl ImplTraitLoweringState { + fn new(impl_trait_mode: ImplTraitLoweringMode) -> ImplTraitLoweringState { + match impl_trait_mode { + ImplTraitLoweringMode::Opaque => Self::Opaque(RefCell::new(Arena::new())), + ImplTraitLoweringMode::Param => Self::Param(Cell::new(0)), + ImplTraitLoweringMode::Variable => Self::Variable(Cell::new(0)), + ImplTraitLoweringMode::Disallowed => Self::Disallowed, + } + } + + fn take(&self) -> Self { + match self { + Self::Opaque(x) => Self::Opaque(RefCell::new(x.take())), + Self::Param(x) => Self::Param(Cell::new(x.get())), + Self::Variable(x) => Self::Variable(Cell::new(x.get())), + Self::Disallowed => Self::Disallowed, + } + } + + fn swap(&self, impl_trait_mode: &Self) { + match (self, impl_trait_mode) { + (Self::Opaque(x), Self::Opaque(y)) => x.swap(y), + (Self::Param(x), Self::Param(y)) => x.swap(y), + (Self::Variable(x), Self::Variable(y)) => x.swap(y), + (Self::Disallowed, Self::Disallowed) => (), + _ => panic!("mismatched lowering mode"), + } + } +} + +#[derive(Debug)] pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, pub resolver: &'a Resolver, @@ -67,17 +112,7 @@ pub struct TyLoweringContext<'a> { /// should be converted to variables. I think in practice, this isn't /// possible currently, so this should be fine for now. pub type_param_mode: ParamLoweringMode, - pub impl_trait_mode: ImplTraitLoweringMode, - impl_trait_counter: Cell<u16>, - /// When turning `impl Trait` into opaque types, we have to collect the - /// bounds at the same time to get the IDs correct (without becoming too - /// complicated). I don't like using interior mutability (as for the - /// counter), but I've tried and failed to make the lifetimes work for - /// passing around a `&mut TyLoweringContext`. The core problem is that - /// we're grouping the mutable data (the counter and this field) together - /// with the immutable context (the references to the DB and resolver). - /// Splitting this up would be a possible fix. - opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>, + impl_trait_mode: ImplTraitLoweringState, expander: RefCell<Option<Expander>>, /// Tracks types with explicit `?Sized` bounds. pub(crate) unsized_types: RefCell<FxHashSet<Ty>>, @@ -85,19 +120,15 @@ pub struct TyLoweringContext<'a> { impl<'a> TyLoweringContext<'a> { pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { - let impl_trait_counter = Cell::new(0); - let impl_trait_mode = ImplTraitLoweringMode::Disallowed; + let impl_trait_mode = ImplTraitLoweringState::Disallowed; let type_param_mode = ParamLoweringMode::Placeholder; let in_binders = DebruijnIndex::INNERMOST; - let opaque_type_data = RefCell::new(Vec::new()); Self { db, resolver, in_binders, impl_trait_mode, - impl_trait_counter, type_param_mode, - opaque_type_data, expander: RefCell::new(None), unsized_types: RefCell::default(), } @@ -108,20 +139,18 @@ impl<'a> TyLoweringContext<'a> { debruijn: DebruijnIndex, f: impl FnOnce(&TyLoweringContext<'_>) -> T, ) -> T { - let opaque_ty_data_vec = self.opaque_type_data.take(); + let impl_trait_mode = self.impl_trait_mode.take(); let expander = self.expander.take(); let unsized_types = self.unsized_types.take(); let new_ctx = Self { in_binders: debruijn, - impl_trait_counter: Cell::new(self.impl_trait_counter.get()), - opaque_type_data: RefCell::new(opaque_ty_data_vec), + impl_trait_mode, expander: RefCell::new(expander), unsized_types: RefCell::new(unsized_types), ..*self }; let result = f(&new_ctx); - self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); - self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); + self.impl_trait_mode.swap(&new_ctx.impl_trait_mode); self.expander.replace(new_ctx.expander.into_inner()); self.unsized_types.replace(new_ctx.unsized_types.into_inner()); result @@ -136,7 +165,7 @@ impl<'a> TyLoweringContext<'a> { } pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { - Self { impl_trait_mode, ..self } + Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self } } pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self { @@ -244,20 +273,17 @@ impl<'a> TyLoweringContext<'a> { } TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds), TypeRef::ImplTrait(bounds) => { - match self.impl_trait_mode { - ImplTraitLoweringMode::Opaque => { - let idx = self.impl_trait_counter.get(); - self.impl_trait_counter.set(idx + 1); + match &self.impl_trait_mode { + ImplTraitLoweringState::Opaque(opaque_type_data) => { let func = match self.resolver.generic_def() { Some(GenericDefId::FunctionId(f)) => f, _ => panic!("opaque impl trait lowering in non-function"), }; - assert!(idx as usize == self.opaque_type_data.borrow().len()); // this dance is to make sure the data is in the right // place even if we encounter more opaque types while // lowering the bounds - self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait { + let idx = opaque_type_data.borrow_mut().alloc(ReturnTypeImplTrait { bounds: crate::make_single_type_binders(Vec::new()), }); // We don't want to lower the bounds inside the binders @@ -273,7 +299,7 @@ impl<'a> TyLoweringContext<'a> { .with_debruijn(DebruijnIndex::INNERMOST, |ctx| { ctx.lower_impl_trait(bounds, func) }); - self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data; + opaque_type_data.borrow_mut()[idx] = actual_opaque_type_data; let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx); let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); @@ -281,10 +307,10 @@ impl<'a> TyLoweringContext<'a> { let parameters = generics.bound_vars_subst(self.db, self.in_binders); TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner) } - ImplTraitLoweringMode::Param => { - let idx = self.impl_trait_counter.get(); + ImplTraitLoweringState::Param(counter) => { + let idx = counter.get(); // FIXME we're probably doing something wrong here - self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); + counter.set(idx + count_impl_traits(type_ref) as u16); if let Some(def) = self.resolver.generic_def() { let generics = generics(self.db.upcast(), def); let param = generics @@ -305,10 +331,10 @@ impl<'a> TyLoweringContext<'a> { TyKind::Error.intern(Interner) } } - ImplTraitLoweringMode::Variable => { - let idx = self.impl_trait_counter.get(); + ImplTraitLoweringState::Variable(counter) => { + let idx = counter.get(); // FIXME we're probably doing something wrong here - self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); + counter.set(idx + count_impl_traits(type_ref) as u16); let ( _parent_params, self_params, @@ -327,7 +353,7 @@ impl<'a> TyLoweringContext<'a> { )) .intern(Interner) } - ImplTraitLoweringMode::Disallowed => { + ImplTraitLoweringState::Disallowed => { // FIXME: report error TyKind::Error.intern(Interner) } @@ -1863,8 +1889,12 @@ pub(crate) fn return_type_impl_traits( .with_type_param_mode(ParamLoweringMode::Variable); let _ret = ctx_ret.lower_ty(&data.ret_type); let generics = generics(db.upcast(), def.into()); - let return_type_impl_traits = - ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() }; + let return_type_impl_traits = ReturnTypeImplTraits { + impl_traits: match ctx_ret.impl_trait_mode { + ImplTraitLoweringState::Opaque(x) => x.into_inner(), + _ => unreachable!(), + }, + }; if return_type_impl_traits.impl_traits.is_empty() { None } else { |