Unnamed repository; edit this file 'description' to name the repository.
There can only be one self param
Lukas Wirth 2024-06-21
parent cf2b757 · commit 480bfd5
-rw-r--r--crates/hir-def/src/generics.rs26
-rw-r--r--crates/hir-ty/src/display.rs4
-rw-r--r--crates/hir-ty/src/generics.rs12
-rw-r--r--crates/hir-ty/src/infer/expr.rs19
-rw-r--r--crates/hir-ty/src/lower.rs66
5 files changed, 61 insertions, 66 deletions
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index acead9dc17..a7ce69113f 100644
--- a/crates/hir-def/src/generics.rs
+++ b/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<TypeOrConstParamData> =
+ 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<LocalTypeOrConstParamId> {
- 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/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index d6a65db14f..66b5398b88 100644
--- a/crates/hir-ty/src/display.rs
+++ b/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/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs
index 8a421b262e..21bed9d3da 100644
--- a/crates/hir-ty/src/generics.rs
+++ b/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<Item = GenericParamId> + '_ {
+ self.iter_self().map(|(id, _)| id)
+ }
+
pub(crate) fn iter_self_type_or_consts(
&self,
) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
@@ -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<usize> {
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 5786d4d382..95f28531ac 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/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/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index ae92b8b896..00b1f53857 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/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> {
+) -> 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(