Unnamed repository; edit this file 'description' to name the repository.
fix: `std::error::Error` is object unsafe
Shoyu Vanilla 2024-08-30
parent 0ae42bd · commit 2310839
-rw-r--r--crates/hir-ty/src/db.rs3
-rw-r--r--crates/hir-ty/src/lower.rs23
-rw-r--r--crates/hir-ty/src/object_safety.rs23
-rw-r--r--crates/hir-ty/src/object_safety/tests.rs17
4 files changed, 45 insertions, 21 deletions
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index ebbe8a448c..ce5a821ea2 100644
--- a/crates/hir-ty/src/db.rs
+++ b/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/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 841e0216ae..213400d04a 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/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/crates/hir-ty/src/object_safety.rs b/crates/hir-ty/src/object_safety.rs
index f3bbb6b04f..89bf3619a0 100644
--- a/crates/hir-ty/src/object_safety.rs
+++ b/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/crates/hir-ty/src/object_safety/tests.rs b/crates/hir-ty/src/object_safety/tests.rs
index 585313e5b9..3dc08c4619 100644
--- a/crates/hir-ty/src/object_safety/tests.rs
+++ b/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![])],
+ );
+}