There can only be one self param

This commit is contained in:
Lukas Wirth 2024-06-21 17:55:16 +02:00
parent c133c649a0
commit 3a66230a44
5 changed files with 61 additions and 66 deletions

View File

@ -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(

View File

@ -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);

View File

@ -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> {

View File

@ -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);
}
};

View File

@ -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(