mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 07:04:22 +00:00
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;
0ae42bd425/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.
This commit is contained in:
commit
aefe34d876
4 changed files with 45 additions and 21 deletions
|
@ -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>;
|
||||
|
|
|
@ -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))
|
||||
})
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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![])],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue