fix: std::error::Error is object unsafe

This commit is contained in:
Shoyu Vanilla 2024-08-30 02:00:38 +09:00
parent 0ae42bd425
commit 231083958a
4 changed files with 45 additions and 21 deletions

View file

@ -154,6 +154,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::lower::generic_predicates_query)] #[salsa::invoke(crate::lower::generic_predicates_query)]
fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; 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::invoke(crate::lower::trait_environment_for_body_query)]
#[salsa::transparent] #[salsa::transparent]
fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc<TraitEnvironment>; fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc<TraitEnvironment>;

View file

@ -1700,6 +1700,28 @@ pub(crate) fn generic_predicates_query(
db: &dyn HirDatabase, db: &dyn HirDatabase,
def: GenericDefId, def: GenericDefId,
) -> GenericPredicates { ) -> 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 resolver = def.resolver(db.upcast());
let (impl_trait_lowering, param_lowering) = match def { let (impl_trait_lowering, param_lowering) = match def {
GenericDefId::FunctionId(_) => { GenericDefId::FunctionId(_) => {
@ -1714,6 +1736,7 @@ pub(crate) fn generic_predicates_query(
let mut predicates = resolver let mut predicates = resolver
.where_predicates_in_scope() .where_predicates_in_scope()
.filter(|(pred, def)| filter(pred, def))
.flat_map(|(pred, def)| { .flat_map(|(pred, def)| {
ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p)) ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
}) })

View file

@ -12,7 +12,7 @@ use hir_def::{
lang_item::LangItem, AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, lang_item::LangItem, AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId,
TypeAliasId, TypeAliasId,
}; };
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::FxHashSet;
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::{ use crate::{
@ -417,30 +417,11 @@ where
cb(MethodViolationCode::UndispatchableReceiver)?; cb(MethodViolationCode::UndispatchableReceiver)?;
} }
let predicates = &*db.generic_predicates(func.into()); let predicates = &*db.generic_predicates_without_parent(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 trait_self_idx = trait_self_param_idx(db.upcast(), func.into()); let trait_self_idx = trait_self_param_idx(db.upcast(), func.into());
for pred in predicates { for pred in predicates {
let pred = pred.skip_binders().skip_binders(); 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(_)) { if matches!(pred, WhereClause::TypeOutlives(_)) {
continue; continue;
} }

View file

@ -361,3 +361,20 @@ pub trait Trait {
[("Trait", vec![])], [("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![])],
);
}