From baa959fa99b094b8795126f2937bd1da2e1a4e47 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 2 Jul 2024 13:42:27 +0200 Subject: [PATCH] Move lifetimes in front of type and const params but after self --- crates/hir-def/src/generics.rs | 99 +++++++++++++-------------- crates/hir-ty/src/generics.rs | 31 +++++---- crates/hir-ty/src/lower.rs | 118 +++++++++++++++------------------ 3 files changed, 122 insertions(+), 126 deletions(-) diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index 1d880c9eee..ebaaef66db 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -249,13 +249,62 @@ impl GenericParams { self.lifetimes.iter() } + pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option { + self.type_or_consts.iter().find_map(|(id, p)| { + if p.name().as_ref() == Some(&name) && p.type_param().is_some() { + Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent })) + } else { + None + } + }) + } + + pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option { + self.type_or_consts.iter().find_map(|(id, p)| { + if p.name().as_ref() == Some(&name) && p.const_param().is_some() { + Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent })) + } else { + None + } + }) + } + + #[inline] + pub fn trait_self_param(&self) -> Option { + if self.type_or_consts.is_empty() { + return None; + } + matches!( + self.type_or_consts[SELF_PARAM_ID_IN_SELF], + TypeOrConstParamData::TypeParamData(TypeParamData { + provenance: TypeParamProvenance::TraitSelf, + .. + }) + ) + .then(|| SELF_PARAM_ID_IN_SELF) + } + + pub fn find_lifetime_by_name( + &self, + name: &Name, + parent: GenericDefId, + ) -> Option { + self.lifetimes.iter().find_map(|(id, p)| { + if &p.name == name { + Some(LifetimeParamId { local_id: id, parent }) + } else { + None + } + }) + } + pub(crate) fn generic_params_query( db: &dyn DefDatabase, def: GenericDefId, ) -> Interned { let _p = tracing::info_span!("generic_params_query").entered(); - let krate = def.module(db).krate; + let krate = def.krate(db); let cfg_options = db.crate_graph(); let cfg_options = &cfg_options[krate].cfg_options; @@ -368,54 +417,6 @@ impl GenericParams { }), } } - - pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option { - self.type_or_consts.iter().find_map(|(id, p)| { - if p.name().as_ref() == Some(&name) && p.type_param().is_some() { - Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent })) - } else { - None - } - }) - } - - pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option { - self.type_or_consts.iter().find_map(|(id, p)| { - if p.name().as_ref() == Some(&name) && p.const_param().is_some() { - Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent })) - } else { - None - } - }) - } - - pub fn trait_self_param(&self) -> Option { - if self.type_or_consts.is_empty() { - return None; - } - matches!( - self.type_or_consts[SELF_PARAM_ID_IN_SELF], - TypeOrConstParamData::TypeParamData(TypeParamData { - provenance: TypeParamProvenance::TraitSelf, - .. - }) - ) - .then(|| SELF_PARAM_ID_IN_SELF) - } - - pub fn find_lifetime_by_name( - &self, - name: &Name, - parent: GenericDefId, - ) -> Option { - self.lifetimes.iter().find_map(|(id, p)| { - if &p.name == name { - Some(LifetimeParamId { local_id: id, parent }) - } else { - None - } - }) - } } #[derive(Clone, Default)] diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs index 7fc60c41d7..a96c101a38 100644 --- a/crates/hir-ty/src/generics.rs +++ b/crates/hir-ty/src/generics.rs @@ -2,8 +2,8 @@ //! //! The layout for generics as expected by chalk are as follows: //! - Optional Self parameter -//! - Type or Const parameters //! - Lifetime parameters +//! - Type or Const parameters //! - Parent parameters //! //! where parent follows the same scheme. @@ -20,19 +20,23 @@ use hir_def::{ LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, }; use intern::Interned; +use itertools::chain; use stdx::TupleExt; use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution}; pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); - Generics { def, params: db.generic_params(def), parent_generics } + let params = db.generic_params(def); + let has_trait_self_param = params.trait_self_param().is_some(); + Generics { def, params, parent_generics, has_trait_self_param } } #[derive(Clone, Debug)] pub(crate) struct Generics { def: GenericDefId, params: Interned, parent_generics: Option>, + has_trait_self_param: bool, } impl ops::Index for Generics @@ -74,10 +78,6 @@ impl Generics { self.params.iter_type_or_consts().map(from_toc_id(self)).map(TupleExt::head) } - pub(crate) fn iter_self_lt_id(&self) -> impl DoubleEndedIterator + '_ { - self.params.iter_lt().map(from_lt_id(self)).map(TupleExt::head) - } - /// Iterate over the params followed by the parent params. pub(crate) fn iter( &self, @@ -89,10 +89,9 @@ impl Generics { pub(crate) fn iter_self( &self, ) -> impl DoubleEndedIterator)> + '_ { - self.params - .iter_type_or_consts() - .map(from_toc_id(self)) - .chain(self.params.iter_lt().map(from_lt_id(self))) + let mut toc = self.params.iter_type_or_consts().map(from_toc_id(self)); + let trait_self_param = self.has_trait_self_param.then(|| toc.next()).flatten(); + chain!(trait_self_param, self.params.iter_lt().map(from_lt_id(self)), toc) } /// Iterator over types and const params of parent. @@ -100,8 +99,9 @@ impl Generics { &self, ) -> impl DoubleEndedIterator)> + '_ { self.parent_generics().into_iter().flat_map(|it| { - let lt_iter = it.params.iter_lt().map(from_lt_id(it)); - it.params.iter_type_or_consts().map(from_toc_id(it)).chain(lt_iter) + let mut toc = it.params.iter_type_or_consts().map(from_toc_id(it)); + let trait_self_param = it.has_trait_self_param.then(|| toc.next()).flatten(); + chain!(trait_self_param, it.params.iter_lt().map(from_lt_id(it)), toc) }) } @@ -146,7 +146,10 @@ impl Generics { if param.parent == self.def { let idx = param.local_id.into_raw().into_u32() as usize; debug_assert!(idx <= self.params.len_type_or_consts()); - Some(idx) + if self.params.trait_self_param() == Some(param.local_id) { + return Some(idx); + } + Some(self.params.len_lifetimes() + idx) } else { debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent)); self.parent_generics() @@ -164,7 +167,7 @@ impl Generics { if lifetime.parent == self.def { let idx = lifetime.local_id.into_raw().into_u32() as usize; debug_assert!(idx <= self.params.len_lifetimes()); - Some(self.params.len_type_or_consts() + idx) + Some(self.params.trait_self_param().is_some() as usize + idx) } else { debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent)); self.parent_generics() diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index a6dd41ae20..d421e72d36 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -384,14 +384,18 @@ impl<'a> TyLoweringContext<'a> { type_params, const_params, _impl_trait_params, - _lifetime_params, + lifetime_params, ) = self .generics() .expect("variable impl trait lowering must be in a generic def") .provenance_split(); TyKind::BoundVar(BoundVar::new( self.in_binders, - idx as usize + self_param as usize + type_params + const_params, + idx as usize + + self_param as usize + + type_params + + const_params + + lifetime_params, )) .intern(Interner) } @@ -816,8 +820,8 @@ impl<'a> TyLoweringContext<'a> { // Order is // - Optional Self parameter - // - Type or Const parameters // - Lifetime parameters + // - Type or Const parameters // - Parent parameters let def_generics = generics(self.db.upcast(), def); let ( @@ -839,7 +843,6 @@ impl<'a> TyLoweringContext<'a> { let ty_error = || TyKind::Error.intern(Interner).cast(Interner); let mut def_toc_iter = def_generics.iter_self_type_or_consts_id(); - let mut def_lt_iter = def_generics.iter_self_lt_id(); let fill_self_param = || { if self_param { let self_ty = explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(ty_error); @@ -852,56 +855,56 @@ impl<'a> TyLoweringContext<'a> { }; let mut had_explicit_args = false; - let mut lifetimes = SmallVec::<[_; 1]>::new(); if let Some(&GenericArgs { ref args, has_self_type, .. }) = args_and_bindings { - if !has_self_type { - fill_self_param(); - } - let expected_num = if has_self_type { - self_param as usize + type_params + const_params + // Fill in the self param first + if has_self_type && self_param { + had_explicit_args = true; + if let Some(id) = def_toc_iter.next() { + assert!(matches!(id, GenericParamId::TypeParamId(_))); + had_explicit_args = true; + if let GenericArg::Type(ty) = &args[0] { + substs.push(self.lower_ty(ty).cast(Interner)); + } + } } else { - type_params + const_params + fill_self_param() }; - let skip = if has_self_type && !self_param { 1 } else { 0 }; - // if non-lifetime args are provided, it should be all of them, but we can't rely on that + + // Then fill in the supplied lifetime args, or error lifetimes if there are too few + // (default lifetimes aren't a thing) for arg in args + .iter() + .filter_map(|arg| match arg { + GenericArg::Lifetime(arg) => Some(self.lower_lifetime(arg)), + _ => None, + }) + .chain(iter::repeat(error_lifetime())) + .take(lifetime_params) + { + substs.push(arg.cast(Interner)); + } + + let skip = if has_self_type { 1 } else { 0 }; + // Fill in supplied type and const args + // Note if non-lifetime args are provided, it should be all of them, but we can't rely on that + for (arg, id) in args .iter() .filter(|arg| !matches!(arg, GenericArg::Lifetime(_))) .skip(skip) - .take(expected_num) + .take(type_params + const_params) + .zip(def_toc_iter) { - if let Some(id) = def_toc_iter.next() { - had_explicit_args = true; - let arg = generic_arg_to_chalk( - self.db, - id, - arg, - &mut (), - |_, type_ref| self.lower_ty(type_ref), - |_, const_ref, ty| self.lower_const(const_ref, ty), - |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ); - substs.push(arg); - } - } - - for arg in args - .iter() - .filter(|arg| matches!(arg, GenericArg::Lifetime(_))) - .take(lifetime_params) - { - if let Some(id) = def_lt_iter.next() { - let arg = generic_arg_to_chalk( - self.db, - id, - arg, - &mut (), - |_, type_ref| self.lower_ty(type_ref), - |_, const_ref, ty| self.lower_const(const_ref, ty), - |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ); - lifetimes.push(arg); - } + had_explicit_args = true; + let arg = generic_arg_to_chalk( + self.db, + id, + arg, + &mut (), + |_, type_ref| self.lower_ty(type_ref), + |_, const_ref, ty| self.lower_const(const_ref, ty), + |_, lifetime_ref| self.lower_lifetime(lifetime_ref), + ); + substs.push(arg); } } else { fill_self_param(); @@ -923,16 +926,16 @@ impl<'a> TyLoweringContext<'a> { } _ => false, }; - if (!infer_args || had_explicit_args) && !is_assoc_ty() { + let fill_defaults = (!infer_args || had_explicit_args) && !is_assoc_ty(); + if fill_defaults { let defaults = &*self.db.generic_defaults(def); let (item, _parent) = defaults.split_at(item_len); - let (toc, lt) = item.split_at(item_len - lifetime_params); let parent_from = item_len - substs.len(); let mut rem = def_generics.iter_id().skip(substs.len()).map(param_to_err).collect::>(); // Fill in defaults for type/const params - for (idx, default_ty) in toc[substs.len()..].iter().enumerate() { + for (idx, default_ty) in item[substs.len()..].iter().enumerate() { // each default can depend on the previous parameters let substs_so_far = Substitution::from_iter( Interner, @@ -940,20 +943,9 @@ impl<'a> TyLoweringContext<'a> { ); substs.push(default_ty.clone().substitute(Interner, &substs_so_far)); } - let n_lifetimes = lifetimes.len(); - // Fill in deferred lifetimes - substs.extend(lifetimes); - // Fill in defaults for lifetime params - for default_ty in <[n_lifetimes..] { - // these are always errors so skipping is fine - substs.push(default_ty.skip_binders().clone()); - } - // Fill in remaining def params and parent params + // Fill in remaining parent params substs.extend(rem.drain(parent_from..)); } else { - substs.extend(def_toc_iter.map(param_to_err)); - // Fill in deferred lifetimes - substs.extend(lifetimes); // Fill in remaining def params and parent params substs.extend(def_generics.iter_id().skip(substs.len()).map(param_to_err)); } @@ -1725,8 +1717,8 @@ pub(crate) fn generic_predicates_query( }) .collect::>(); - let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - if !subst.is_empty(Interner) { + if generics.len() > 0 { + let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); let explicitly_unsized_tys = ctx.unsized_types.into_inner(); if let Some(implicitly_sized_predicates) = implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)