Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/lower.rs9
-rw-r--r--crates/hir-ty/src/tests/regression.rs21
-rw-r--r--crates/hir-ty/src/utils.rs18
3 files changed, 39 insertions, 9 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 239f66bcb7..3ec321ad37 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -509,7 +509,14 @@ impl<'a> TyLoweringContext<'a> {
TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
}
ParamLoweringMode::Variable => {
- let idx = generics.param_idx(param_id.into()).expect("matching generics");
+ let idx = match generics.param_idx(param_id.into()) {
+ None => {
+ never!("no matching generics");
+ return (TyKind::Error.intern(Interner), None);
+ }
+ Some(idx) => idx,
+ };
+
TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
}
}
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 93a88ab58e..9b64fccccd 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -1527,6 +1527,27 @@ unsafe impl Storage for InlineStorage {
}
#[test]
+fn gat_crash_3() {
+ cov_mark::check!(ignore_gats);
+ check_no_mismatches(
+ r#"
+trait Collection {
+ type Item;
+ type Member<T>: Collection<Item = T>;
+ fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
+}
+struct ConstGen<T, const N: usize> {
+ data: [T; N],
+}
+impl<T, const N: usize> Collection for ConstGen<T, N> {
+ type Item = T;
+ type Member<U> = ConstGen<U, N>;
+}
+ "#,
+ );
+}
+
+#[test]
fn cfgd_out_self_param() {
cov_mark::check!(cfgd_out_self_param);
check_no_mismatches(
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 83319755da..bdb9ade9c8 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -176,10 +176,16 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
let params = db.generic_params(def);
+ let parent_params = &parent_generics.as_ref().unwrap().params;
let has_consts =
params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
- return if has_consts {
- // XXX: treat const generic associated types as not existing to avoid crashes (#11769)
+ let parent_has_consts =
+ parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
+ return if has_consts || parent_has_consts {
+ // XXX: treat const generic associated types as not existing to avoid crashes
+ // (#11769, #12193)
+ // Note: also crashes when the parent has const generics (also even if the GAT
+ // doesn't use them), see `tests::regression::gat_crash_3` for an example.
//
// Chalk expects the inner associated type's parameters to come
// *before*, not after the trait's generics as we've always done it.
@@ -264,12 +270,8 @@ impl Generics {
fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> {
if param.parent == self.def {
- let (idx, (_local_id, data)) = self
- .params
- .iter()
- .enumerate()
- .find(|(_, (idx, _))| *idx == param.local_id)
- .unwrap();
+ let (idx, (_local_id, data)) =
+ self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
let parent_len = self.parent_generics().map_or(0, Generics::len);
Some((parent_len + idx, data))
} else {