diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index acead9dc17c..a7ce69113fb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -11,7 +11,7 @@ use hir_expand::{ ExpandResult, }; use intern::Interned; -use la_arena::Arena; +use la_arena::{Arena, RawIdx}; use once_cell::unsync::Lazy; use stdx::impl_from; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; @@ -28,6 +28,9 @@ use crate::{ LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, }; +const SELF_PARAM_ID_IN_SELF: la_arena::Idx = + LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); + /// Data about a generic type parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeParamData { @@ -606,16 +609,17 @@ impl GenericParams { } pub fn find_trait_self_param(&self) -> Option { - self.type_or_consts.iter().find_map(|(id, p)| { - matches!( - p, - TypeOrConstParamData::TypeParamData(TypeParamData { - provenance: TypeParamProvenance::TraitSelf, - .. - }) - ) - .then(|| id) - }) + 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( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index d6a65db14f2..66b5398b88e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -989,7 +989,7 @@ impl HirDisplay for Ty { if parameters.len(Interner) > 0 { let generics = generics(db.upcast(), def.into()); - let (parent_len, self_, type_, const_, impl_, lifetime) = + let (parent_len, self_param, type_, const_, impl_, lifetime) = generics.provenance_split(); let parameters = parameters.as_slice(Interner); // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? @@ -997,7 +997,7 @@ impl HirDisplay for Ty { // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes // parent's params (those from enclosing impl or trait, if any). let (fn_params, other) = - parameters.split_at(self_ + type_ + const_ + lifetime); + parameters.split_at(self_param as usize + type_ + const_ + lifetime); let (_impl, parent_params) = other.split_at(impl_); debug_assert_eq!(parent_params.len(), parent_len); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index 8a421b262e2..21bed9d3dae 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -53,6 +53,10 @@ impl Generics { self.iter().map(|(id, _)| id) } + pub(crate) fn iter_self_id(&self) -> impl Iterator + '_ { + self.iter_self().map(|(id, _)| id) + } + pub(crate) fn iter_self_type_or_consts( &self, ) -> impl DoubleEndedIterator { @@ -99,8 +103,8 @@ impl Generics { } /// (parent total, self param, type params, const params, impl trait list, lifetimes) - pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize, usize) { - let mut self_params = 0; + pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) { + let mut self_param = false; let mut type_params = 0; let mut impl_trait_params = 0; let mut const_params = 0; @@ -108,7 +112,7 @@ impl Generics { self.params.iter_type_or_consts().for_each(|(_, data)| match data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList => type_params += 1, - TypeParamProvenance::TraitSelf => self_params += 1, + TypeParamProvenance::TraitSelf => self_param |= true, TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1, }, TypeOrConstParamData::ConstParamData(_) => const_params += 1, @@ -117,7 +121,7 @@ impl Generics { self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1); let parent_len = self.parent_generics().map_or(0, Generics::len); - (parent_len, self_params, type_params, const_params, impl_trait_params, lifetime_params) + (parent_len, self_param, type_params, const_params, impl_trait_params, lifetime_params) } pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 5786d4d3821..95f28531acf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -1830,13 +1830,13 @@ impl InferenceContext<'_> { ) -> Substitution { let ( parent_params, - self_params, + has_self_param, type_params, const_params, impl_trait_params, lifetime_params, ) = def_generics.provenance_split(); - assert_eq!(self_params, 0); // method shouldn't have another Self param + assert!(!has_self_param); // method shouldn't have another Self param let total_len = parent_params + type_params + const_params + impl_trait_params + lifetime_params; let mut substs = Vec::with_capacity(total_len); @@ -1844,13 +1844,11 @@ impl InferenceContext<'_> { // handle provided arguments if let Some(generic_args) = generic_args { // if args are provided, it should be all of them, but we can't rely on that - for (arg, kind_id) in generic_args - .args - .iter() - .take(type_params + const_params + lifetime_params) - .zip(def_generics.iter_id()) + let self_params = type_params + const_params + lifetime_params; + for (arg, kind_id) in + generic_args.args.iter().zip(def_generics.iter_self_id()).take(self_params) { - if let Some(g) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, kind_id, arg, @@ -1869,9 +1867,8 @@ impl InferenceContext<'_> { ) }, |this, lt_ref| this.make_lifetime(lt_ref), - ) { - substs.push(g); - } + ); + substs.push(arg); } }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index ae92b8b8966..00b1f53857b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -375,7 +375,7 @@ impl<'a> TyLoweringContext<'a> { counter.set(idx + count_impl_traits(type_ref) as u16); let ( _parent_params, - self_params, + self_param, type_params, const_params, _impl_trait_params, @@ -386,7 +386,7 @@ impl<'a> TyLoweringContext<'a> { .provenance_split(); TyKind::BoundVar(BoundVar::new( self.in_binders, - idx as usize + self_params + type_params + const_params, + idx as usize + self_param as usize + type_params + const_params, )) .intern(Interner) } @@ -817,14 +817,14 @@ impl<'a> TyLoweringContext<'a> { let def_generics = generics(self.db.upcast(), def); let ( parent_params, - self_params, + self_param, type_params, const_params, impl_trait_params, lifetime_params, ) = def_generics.provenance_split(); let item_len = - self_params + type_params + const_params + impl_trait_params + lifetime_params; + self_param as usize + type_params + const_params + impl_trait_params + lifetime_params; let total_len = parent_params + item_len; let ty_error = TyKind::Error.intern(Interner).cast(Interner); @@ -832,18 +832,16 @@ impl<'a> TyLoweringContext<'a> { let mut def_generic_iter = def_generics.iter_id(); let fill_self_params = || { - for x in explicit_self_ty - .into_iter() - .map(|x| x.cast(Interner)) - .chain(iter::repeat(ty_error.clone())) - .take(self_params) - { + if self_param { + let self_ty = + explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone()); + if let Some(id) = def_generic_iter.next() { assert!(matches!( id, GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_) )); - substs.push(x); + substs.push(self_ty); } } }; @@ -854,11 +852,11 @@ impl<'a> TyLoweringContext<'a> { fill_self_params(); } let expected_num = if generic_args.has_self_type { - self_params + type_params + const_params + self_param as usize + type_params + const_params } else { type_params + const_params }; - let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 }; + let skip = if generic_args.has_self_type && !self_param { 1 } else { 0 }; // if args are provided, it should be all of them, but we can't rely on that for arg in generic_args .args @@ -868,7 +866,7 @@ impl<'a> TyLoweringContext<'a> { .take(expected_num) { if let Some(id) = def_generic_iter.next() { - if let Some(x) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, id, arg, @@ -876,13 +874,9 @@ impl<'a> TyLoweringContext<'a> { |_, type_ref| self.lower_ty(type_ref), |_, const_ref, ty| self.lower_const(const_ref, ty), |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ) { - had_explicit_args = true; - substs.push(x); - } else { - // we just filtered them out - never!("Unexpected lifetime argument"); - } + ); + had_explicit_args = true; + substs.push(arg); } } @@ -895,7 +889,7 @@ impl<'a> TyLoweringContext<'a> { // Taking into the fact that def_generic_iter will always have lifetimes at the end // Should have some test cases tho to test this behaviour more properly if let Some(id) = def_generic_iter.next() { - if let Some(x) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, id, arg, @@ -903,13 +897,9 @@ impl<'a> TyLoweringContext<'a> { |_, type_ref| self.lower_ty(type_ref), |_, const_ref, ty| self.lower_const(const_ref, ty), |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ) { - had_explicit_args = true; - substs.push(x); - } else { - // Never return a None explicitly - never!("Unexpected None by generic_arg_to_chalk"); - } + ); + had_explicit_args = true; + substs.push(arg); } } } else { @@ -2170,7 +2160,6 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut /// Checks if the provided generic arg matches its expected kind, then lower them via /// provided closures. Use unknown if there was kind mismatch. /// -/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime. pub(crate) fn generic_arg_to_chalk<'a, T>( db: &dyn HirDatabase, kind_id: GenericParamId, @@ -2179,7 +2168,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a, -) -> Option { +) -> crate::GenericArg { let kind = match kind_id { GenericParamId::TypeParamId(_) => ParamKind::Type, GenericParamId::ConstParamId(id) => { @@ -2188,7 +2177,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( } GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, }; - Some(match (arg, kind) { + match (arg, kind) { (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner), (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner), (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => { @@ -2201,11 +2190,12 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( // as types. Maybe here is not the best place to do it, but // it works. if let TypeRef::Path(p) = t { - let p = p.mod_path()?; - if p.kind == PathKind::Plain { - if let [n] = p.segments() { - let c = ConstRef::Path(n.clone()); - return Some(for_const(this, &c, c_ty).cast(Interner)); + if let Some(p) = p.mod_path() { + if p.kind == PathKind::Plain { + if let [n] = p.segments() { + let c = ConstRef::Path(n.clone()); + return for_const(this, &c, c_ty).cast(Interner); + } } } } @@ -2214,7 +2204,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty), (GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), (GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), - }) + } } pub(crate) fn const_or_path_to_chalk(