diff options
| author | bors <bors@rust-lang.org> | 2022-08-22 14:00:23 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-08-22 14:00:23 +0000 |
| commit | fdc28b4333c7fccafbb85af7ccddbbf6f96df9a0 (patch) | |
| tree | bb2d3bec515d35de3ee5c21d9a3e58f8b895c806 | |
| parent | c2310a0af606791248a2d6a6ce98212b1e809179 (diff) | |
| parent | ac8cb8ce3b81b4f4559809a3aec50cb0799c126f (diff) | |
| download | rust-fdc28b4333c7fccafbb85af7ccddbbf6f96df9a0.tar.gz rust-fdc28b4333c7fccafbb85af7ccddbbf6f96df9a0.zip | |
Auto merge of #13021 - N3xed:fix-gat-panics, r=flodiebold
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. Fixes #11989, fixes #12193
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 9 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/regression.rs | 28 | ||||
| -rw-r--r-- | crates/hir-ty/src/utils.rs | 21 |
3 files changed, 49 insertions, 9 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index ae115c8c0da..8b360337a82 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -479,7 +479,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 1b5ed0603bf..c7895db1afb 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1527,6 +1527,34 @@ unsafe impl Storage for InlineStorage { } #[test] +fn gat_crash_3() { + // FIXME: This test currently crashes rust analyzer in a debug build but not in a + // release build (i.e. for the user). With the assumption that tests will always be run + // in debug mode, we catch the unwind and expect that it panicked. See the + // [`crate::utils::generics`] function for more information. + cov_mark::check!(ignore_gats); + std::panic::catch_unwind(|| { + 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>; +} + "#, + ); + }) + .expect_err("must panic"); +} + +#[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 83319755da7..d6638db0285 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -176,10 +176,19 @@ 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) + // + // 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. + // Avoids that by disabling GATs when the parent (i.e. `impl` block) has + // const generics (#12193). // // 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 +273,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 { |
