mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 01:17:27 +00:00
fix: Fix panics on GATs involving const generics
This workaround avoids constant crashing of rust analyzer when using GATs with const generics, even when the const generics are only on the `impl` block. The workaround treats GATs as non-existing if either itself or the parent has const generics and removes relevant panicking code-paths.
This commit is contained in:
parent
b6d59f2bb4
commit
ad7a1ed8cc
3 changed files with 39 additions and 9 deletions
|
@ -509,7 +509,14 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
|
TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
|
||||||
}
|
}
|
||||||
ParamLoweringMode::Variable => {
|
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))
|
TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1526,6 +1526,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]
|
#[test]
|
||||||
fn cfgd_out_self_param() {
|
fn cfgd_out_self_param() {
|
||||||
cov_mark::check!(cfgd_out_self_param);
|
cov_mark::check!(cfgd_out_self_param);
|
||||||
|
|
|
@ -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)));
|
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
|
||||||
if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
|
if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
|
||||||
let params = db.generic_params(def);
|
let params = db.generic_params(def);
|
||||||
|
let parent_params = &parent_generics.as_ref().unwrap().params;
|
||||||
let has_consts =
|
let has_consts =
|
||||||
params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
|
params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
|
||||||
return if has_consts {
|
let parent_has_consts =
|
||||||
// XXX: treat const generic associated types as not existing to avoid crashes (#11769)
|
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
|
// Chalk expects the inner associated type's parameters to come
|
||||||
// *before*, not after the trait's generics as we've always done it.
|
// *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)> {
|
fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> {
|
||||||
if param.parent == self.def {
|
if param.parent == self.def {
|
||||||
let (idx, (_local_id, data)) = self
|
let (idx, (_local_id, data)) =
|
||||||
.params
|
self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.find(|(_, (idx, _))| *idx == param.local_id)
|
|
||||||
.unwrap();
|
|
||||||
let parent_len = self.parent_generics().map_or(0, Generics::len);
|
let parent_len = self.parent_generics().map_or(0, Generics::len);
|
||||||
Some((parent_len + idx, data))
|
Some((parent_len + idx, data))
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue