Fix opaque generics

The parent generics were incorrectly not considered for TAIT.

I'm not convinced we should follow rustc here, also there are items (opaques) with more than 1 parent (opaque -> fn/type alias -> impl/trait) and I'm not sure we properly account for that in all places, but for now I left it as-is.

Also fix a bug where lifetimes' indices were incorrect when there is a self param (they started from 0 instead of 1).
This commit is contained in:
Chayim Refael Friedman 2025-08-24 08:49:40 +03:00
parent e6cd085099
commit 03173a7ec7
4 changed files with 54 additions and 43 deletions

View file

@ -12,7 +12,7 @@ use hir_def::{
},
};
use hir_expand::name::Name;
use intern::Symbol;
use intern::{Symbol, sym};
use la_arena::Arena;
use rustc_type_ir::inherent::Ty as _;
use triomphe::Arc;
@ -24,18 +24,13 @@ use super::{Const, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, Solver
use super::{DbInterner, GenericArg};
pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
let mk_lt = |(index, (_, lt)): (usize, (_, &LifetimeParamData))| {
let mk_lt = |index, lt: &LifetimeParamData| {
let name = lt.name.symbol().clone();
let index = index as u32;
let kind = GenericParamDefKind::Lifetime;
GenericParamDef { name, index, kind }
};
let mk_ty = |len_lt, (index, p): (usize, &TypeOrConstParamData)| {
let name = p
.name()
.map(|n| n.symbol().clone())
.unwrap_or_else(|| Name::missing().symbol().clone());
let index = (len_lt + index) as u32;
let mk_ty = |index, p: &TypeOrConstParamData| {
let name = p.name().map(|n| n.symbol().clone()).unwrap_or_else(|| sym::MISSING_NAME);
let kind = match p {
TypeOrConstParamData::TypeParamData(_) => GenericParamDefKind::Type,
TypeOrConstParamData::ConstParamData(_) => GenericParamDefKind::Const,
@ -43,33 +38,25 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
GenericParamDef { name, index, kind }
};
let own_params_for_generic_params = |params: &GenericParams| {
if params.trait_self_param().is_some() {
let len_lt = params.len_lifetimes() + 1;
params
.iter_type_or_consts()
.take(1)
.enumerate()
.map(|t| mk_ty(0, (t.0, t.1.1)))
.chain(params.iter_lt().enumerate().map(mk_lt))
.chain(
params
.iter_type_or_consts()
.skip(1)
.enumerate()
.map(|t| mk_ty(len_lt, (t.0, t.1.1))),
)
.collect()
} else {
let len_lt = params.len_lifetimes();
params
.iter_lt()
.enumerate()
.map(mk_lt)
.chain(
params.iter_type_or_consts().enumerate().map(|t| mk_ty(len_lt, (t.0, t.1.1))),
)
.collect()
let mut result = Vec::with_capacity(params.len());
let mut type_and_consts = params.iter_type_or_consts();
let mut index = 0;
if let Some(self_param) = params.trait_self_param() {
result.push(mk_ty(0, &params[self_param]));
type_and_consts.next();
index += 1;
}
result.extend(params.iter_lt().map(|(_, data)| {
let lt = mk_lt(index, data);
index += 1;
lt
}));
result.extend(type_and_consts.map(|(_, data)| {
let ty = mk_ty(index, data);
index += 1;
ty
}));
result
};
let (parent, own_params) = match (def.try_into(), def) {
@ -82,12 +69,9 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
// The opaque type itself does not have generics - only the parent function
(Some(GenericDefId::FunctionId(function_id)), vec![])
}
crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => (
None,
own_params_for_generic_params(
&db.generic_params(GenericDefId::TypeAliasId(type_alias_id)),
),
),
crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => {
(Some(type_alias_id.into()), Vec::new())
}
crate::ImplTraitId::AsyncBlockTypeImplTrait(def, _) => {
let param = TypeOrConstParamData::TypeParamData(TypeParamData {
name: None,
@ -95,7 +79,7 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
provenance: TypeParamProvenance::TypeParamList,
});
// Yes, there is a parent but we don't include it in the generics
(None, vec![mk_ty(0, (0, &param))])
(None, vec![mk_ty(0, &param)])
}
}
}

View file

@ -685,7 +685,6 @@ pub fn explicit_item_bounds<'db>(
LifetimeElisionKind::AnonymousReportError,
);
let trait_args = GenericArgs::identity_for_item(interner, trait_.into());
let item_args = GenericArgs::identity_for_item(interner, def_id);
let interner_ty = Ty::new_projection_from_args(interner, def_id, item_args);

View file

@ -1,3 +1,5 @@
mod new_solver;
use expect_test::expect;
use super::{check_infer, check_no_mismatches, check_types};

View file

@ -0,0 +1,26 @@
use expect_test::expect;
use super::check_infer;
#[test]
fn opaque_generics() {
check_infer(
r#"
//- minicore: iterator
pub struct Grid {}
impl<'a> IntoIterator for &'a Grid {
type Item = &'a ();
type IntoIter = impl Iterator<Item = &'a ()>;
fn into_iter(self) -> Self::IntoIter {
}
}
"#,
expect![[r#"
150..154 'self': &'a Grid
174..181 '{ }': impl Iterator<Item = &'a ()>
"#]],
);
}