1
Fork 0

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, ExpandResult,
}; };
use intern::Interned; use intern::Interned;
use la_arena::Arena; use la_arena::{Arena, RawIdx};
use once_cell::unsync::Lazy; use once_cell::unsync::Lazy;
use stdx::impl_from; use stdx::impl_from;
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
@ -28,6 +28,9 @@ use crate::{
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, 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, ...). /// Data about a generic type parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TypeParamData { pub struct TypeParamData {
@ -606,16 +609,17 @@ impl GenericParams {
} }
pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> { pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
self.type_or_consts.iter().find_map(|(id, p)| { if self.type_or_consts.is_empty() {
matches!( return None;
p, }
TypeOrConstParamData::TypeParamData(TypeParamData { matches!(
provenance: TypeParamProvenance::TraitSelf, self.type_or_consts[SELF_PARAM_ID_IN_SELF],
.. TypeOrConstParamData::TypeParamData(TypeParamData {
}) provenance: TypeParamProvenance::TraitSelf,
) ..
.then(|| id) })
}) )
.then(|| SELF_PARAM_ID_IN_SELF)
} }
pub fn find_lifetime_by_name( pub fn find_lifetime_by_name(

View file

@ -989,7 +989,7 @@ impl HirDisplay for Ty {
if parameters.len(Interner) > 0 { if parameters.len(Interner) > 0 {
let generics = generics(db.upcast(), def.into()); 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(); generics.provenance_split();
let parameters = parameters.as_slice(Interner); 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? // 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 // `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). // parent's params (those from enclosing impl or trait, if any).
let (fn_params, other) = 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_); let (_impl, parent_params) = other.split_at(impl_);
debug_assert_eq!(parent_params.len(), parent_len); debug_assert_eq!(parent_params.len(), parent_len);

View file

@ -53,6 +53,10 @@ impl Generics {
self.iter().map(|(id, _)| id) 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( pub(crate) fn iter_self_type_or_consts(
&self, &self,
) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> { ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
@ -99,8 +103,8 @@ impl Generics {
} }
/// (parent total, self param, type params, const params, impl trait list, lifetimes) /// (parent total, self param, type params, const params, impl trait list, lifetimes)
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize, usize) { pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) {
let mut self_params = 0; let mut self_param = false;
let mut type_params = 0; let mut type_params = 0;
let mut impl_trait_params = 0; let mut impl_trait_params = 0;
let mut const_params = 0; let mut const_params = 0;
@ -108,7 +112,7 @@ impl Generics {
self.params.iter_type_or_consts().for_each(|(_, data)| match data { self.params.iter_type_or_consts().for_each(|(_, data)| match data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeOrConstParamData::TypeParamData(p) => match p.provenance {
TypeParamProvenance::TypeParamList => type_params += 1, TypeParamProvenance::TypeParamList => type_params += 1,
TypeParamProvenance::TraitSelf => self_params += 1, TypeParamProvenance::TraitSelf => self_param |= true,
TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1, TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1,
}, },
TypeOrConstParamData::ConstParamData(_) => const_params += 1, TypeOrConstParamData::ConstParamData(_) => const_params += 1,
@ -117,7 +121,7 @@ impl Generics {
self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1); self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1);
let parent_len = self.parent_generics().map_or(0, Generics::len); 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> { pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {

View file

@ -1830,13 +1830,13 @@ impl InferenceContext<'_> {
) -> Substitution { ) -> Substitution {
let ( let (
parent_params, parent_params,
self_params, has_self_param,
type_params, type_params,
const_params, const_params,
impl_trait_params, impl_trait_params,
lifetime_params, lifetime_params,
) = def_generics.provenance_split(); ) = 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 = let total_len =
parent_params + type_params + const_params + impl_trait_params + lifetime_params; parent_params + type_params + const_params + impl_trait_params + lifetime_params;
let mut substs = Vec::with_capacity(total_len); let mut substs = Vec::with_capacity(total_len);
@ -1844,13 +1844,11 @@ impl InferenceContext<'_> {
// handle provided arguments // handle provided arguments
if let Some(generic_args) = generic_args { if let Some(generic_args) = generic_args {
// if args are provided, it should be all of them, but we can't rely on that // if args are provided, it should be all of them, but we can't rely on that
for (arg, kind_id) in generic_args let self_params = type_params + const_params + lifetime_params;
.args for (arg, kind_id) in
.iter() generic_args.args.iter().zip(def_generics.iter_self_id()).take(self_params)
.take(type_params + const_params + lifetime_params)
.zip(def_generics.iter_id())
{ {
if let Some(g) = generic_arg_to_chalk( let arg = generic_arg_to_chalk(
self.db, self.db,
kind_id, kind_id,
arg, arg,
@ -1869,9 +1867,8 @@ impl InferenceContext<'_> {
) )
}, },
|this, lt_ref| this.make_lifetime(lt_ref), |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); counter.set(idx + count_impl_traits(type_ref) as u16);
let ( let (
_parent_params, _parent_params,
self_params, self_param,
type_params, type_params,
const_params, const_params,
_impl_trait_params, _impl_trait_params,
@ -386,7 +386,7 @@ impl<'a> TyLoweringContext<'a> {
.provenance_split(); .provenance_split();
TyKind::BoundVar(BoundVar::new( TyKind::BoundVar(BoundVar::new(
self.in_binders, 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) .intern(Interner)
} }
@ -817,14 +817,14 @@ impl<'a> TyLoweringContext<'a> {
let def_generics = generics(self.db.upcast(), def); let def_generics = generics(self.db.upcast(), def);
let ( let (
parent_params, parent_params,
self_params, self_param,
type_params, type_params,
const_params, const_params,
impl_trait_params, impl_trait_params,
lifetime_params, lifetime_params,
) = def_generics.provenance_split(); ) = def_generics.provenance_split();
let item_len = 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 total_len = parent_params + item_len;
let ty_error = TyKind::Error.intern(Interner).cast(Interner); 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 mut def_generic_iter = def_generics.iter_id();
let fill_self_params = || { let fill_self_params = || {
for x in explicit_self_ty if self_param {
.into_iter() let self_ty =
.map(|x| x.cast(Interner)) explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone());
.chain(iter::repeat(ty_error.clone()))
.take(self_params)
{
if let Some(id) = def_generic_iter.next() { if let Some(id) = def_generic_iter.next() {
assert!(matches!( assert!(matches!(
id, id,
GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_) GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_)
)); ));
substs.push(x); substs.push(self_ty);
} }
} }
}; };
@ -854,11 +852,11 @@ impl<'a> TyLoweringContext<'a> {
fill_self_params(); fill_self_params();
} }
let expected_num = if generic_args.has_self_type { let expected_num = if generic_args.has_self_type {
self_params + type_params + const_params self_param as usize + type_params + const_params
} else { } else {
type_params + const_params 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 // if args are provided, it should be all of them, but we can't rely on that
for arg in generic_args for arg in generic_args
.args .args
@ -868,7 +866,7 @@ impl<'a> TyLoweringContext<'a> {
.take(expected_num) .take(expected_num)
{ {
if let Some(id) = def_generic_iter.next() { if let Some(id) = def_generic_iter.next() {
if let Some(x) = generic_arg_to_chalk( let arg = generic_arg_to_chalk(
self.db, self.db,
id, id,
arg, arg,
@ -876,13 +874,9 @@ impl<'a> TyLoweringContext<'a> {
|_, type_ref| self.lower_ty(type_ref), |_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty), |_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref), |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
) { );
had_explicit_args = true; had_explicit_args = true;
substs.push(x); substs.push(arg);
} else {
// we just filtered them out
never!("Unexpected lifetime argument");
}
} }
} }
@ -895,7 +889,7 @@ impl<'a> TyLoweringContext<'a> {
// Taking into the fact that def_generic_iter will always have lifetimes at the end // 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 // Should have some test cases tho to test this behaviour more properly
if let Some(id) = def_generic_iter.next() { if let Some(id) = def_generic_iter.next() {
if let Some(x) = generic_arg_to_chalk( let arg = generic_arg_to_chalk(
self.db, self.db,
id, id,
arg, arg,
@ -903,13 +897,9 @@ impl<'a> TyLoweringContext<'a> {
|_, type_ref| self.lower_ty(type_ref), |_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty), |_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref), |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
) { );
had_explicit_args = true; had_explicit_args = true;
substs.push(x); substs.push(arg);
} else {
// Never return a None explicitly
never!("Unexpected None by generic_arg_to_chalk");
}
} }
} }
} else { } 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 /// Checks if the provided generic arg matches its expected kind, then lower them via
/// provided closures. Use unknown if there was kind mismatch. /// 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>( pub(crate) fn generic_arg_to_chalk<'a, T>(
db: &dyn HirDatabase, db: &dyn HirDatabase,
kind_id: GenericParamId, 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_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a, for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
) -> Option<crate::GenericArg> { ) -> crate::GenericArg {
let kind = match kind_id { let kind = match kind_id {
GenericParamId::TypeParamId(_) => ParamKind::Type, GenericParamId::TypeParamId(_) => ParamKind::Type,
GenericParamId::ConstParamId(id) => { GenericParamId::ConstParamId(id) => {
@ -2188,7 +2177,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
} }
GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, 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::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::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
(GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => { (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 // as types. Maybe here is not the best place to do it, but
// it works. // it works.
if let TypeRef::Path(p) = t { if let TypeRef::Path(p) = t {
let p = p.mod_path()?; if let Some(p) = p.mod_path() {
if p.kind == PathKind::Plain { if p.kind == PathKind::Plain {
if let [n] = p.segments() { if let [n] = p.segments() {
let c = ConstRef::Path(n.clone()); let c = ConstRef::Path(n.clone());
return Some(for_const(this, &c, c_ty).cast(Interner)); 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::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty),
(GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), (GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
(GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), (GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
}) }
} }
pub(crate) fn const_or_path_to_chalk( pub(crate) fn const_or_path_to_chalk(