diff options
| author | bors <bors@rust-lang.org> | 2024-08-30 05:53:23 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-08-30 05:53:23 +0000 |
| commit | a729229a217a623ecd9bcb4ed08e07ad40ac5a71 (patch) | |
| tree | 2f1eb3e211b1ec7e93a4f2ece5575a8067ca7400 | |
| parent | 16a29ced1575e47559e2e46d28c0183e576113c9 (diff) | |
| parent | 92f27dc57df1e01186a2ab515ced9125a8ba2673 (diff) | |
| download | rust-a729229a217a623ecd9bcb4ed08e07ad40ac5a71.tar.gz rust-a729229a217a623ecd9bcb4ed08e07ad40ac5a71.zip | |
Auto merge of #17999 - ShoyuVanilla:issue-17998, r=Veykril
fix: `std::error::Error` is object unsafe
Fixes #17998
I tried to get generic predicates of assoc function itself, not inherited from the parent here;
https://github.com/rust-lang/rust-analyzer/blob/0ae42bd42576566540a84c62e118aa823edcf2ec/crates/hir-ty/src/object_safety.rs#L420-L442
But this naive equality check approach doesn't work when the assoc function has one or more generic paramters like;
```rust
trait Foo {}
trait Bar: Foo {
fn bar(&self);
}
```
because the generic predicates of the parent, `Bar` is `[^1.0 implements Foo]` and the generic predicates of `fn bar` is `[^1.1 implements Foo]`, which are different.
This PR implements a correct logic for filtering out parent generic predicates for this.
4 files changed, 45 insertions, 21 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index ebbe8a448cc..ce5a821ea2b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -154,6 +154,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { #[salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; + #[salsa::invoke(crate::lower::generic_predicates_without_parent_query)] + fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates; + #[salsa::invoke(crate::lower::trait_environment_for_body_query)] #[salsa::transparent] fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc<TraitEnvironment>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 841e0216ae2..213400d04a0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1700,6 +1700,28 @@ pub(crate) fn generic_predicates_query( db: &dyn HirDatabase, def: GenericDefId, ) -> GenericPredicates { + generic_predicates_filtered_by(db, def, |_, _| true) +} + +/// Resolve the where clause(s) of an item with generics, +/// except the ones inherited from the parent +pub(crate) fn generic_predicates_without_parent_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> GenericPredicates { + generic_predicates_filtered_by(db, def, |_, d| *d == def) +} + +/// Resolve the where clause(s) of an item with generics, +/// except the ones inherited from the parent +fn generic_predicates_filtered_by<F>( + db: &dyn HirDatabase, + def: GenericDefId, + filter: F, +) -> GenericPredicates +where + F: Fn(&WherePredicate, &GenericDefId) -> bool, +{ let resolver = def.resolver(db.upcast()); let (impl_trait_lowering, param_lowering) = match def { GenericDefId::FunctionId(_) => { @@ -1714,6 +1736,7 @@ pub(crate) fn generic_predicates_query( let mut predicates = resolver .where_predicates_in_scope() + .filter(|(pred, def)| filter(pred, def)) .flat_map(|(pred, def)| { ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p)) }) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs b/src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs index f3bbb6b04f9..89bf3619a0c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/object_safety.rs @@ -12,7 +12,7 @@ use hir_def::{ lang_item::LangItem, AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId, }; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashSet; use smallvec::SmallVec; use crate::{ @@ -417,30 +417,11 @@ where cb(MethodViolationCode::UndispatchableReceiver)?; } - let predicates = &*db.generic_predicates(func.into()); - let mut parent_predicates = (*db.generic_predicates(trait_.into())) - .iter() - .map(|b| b.skip_binders().skip_binders().clone()) - .fold(FxHashMap::default(), |mut acc, item| { - acc.entry(item) - .and_modify(|cnt| { - *cnt += 1; - }) - .or_insert(1); - acc - }); + let predicates = &*db.generic_predicates_without_parent(func.into()); let trait_self_idx = trait_self_param_idx(db.upcast(), func.into()); for pred in predicates { let pred = pred.skip_binders().skip_binders(); - // Skip predicates from parent, i.e. the trait that contains this method - if let Some(cnt) = parent_predicates.get_mut(pred) { - if *cnt > 0 { - *cnt -= 1; - continue; - } - } - if matches!(pred, WhereClause::TypeOutlives(_)) { continue; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs index 585313e5b9b..3dc08c4619e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/object_safety/tests.rs @@ -361,3 +361,20 @@ pub trait Trait { [("Trait", vec![])], ); } + +#[test] +fn std_error_is_object_safe() { + check_object_safety( + r#" +//- minicore: fmt, dispatch_from_dyn +trait Erased<'a>: 'a {} + +pub struct Request<'a>(dyn Erased<'a> + 'a); + +pub trait Error: core::fmt::Debug + core::fmt::Display { + fn provide<'a>(&'a self, request: &mut Request<'a>); +} +"#, + [("Error", vec![])], + ); +} |
