Skip to content

Commit aefe34d

Browse files
committed
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.
2 parents 1b48c76 + 2310839 commit aefe34d

File tree

4 files changed

+45
-21
lines changed

4 files changed

+45
-21
lines changed

crates/hir-ty/src/db.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
154154
#[salsa::invoke(crate::lower::generic_predicates_query)]
155155
fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
156156

157+
#[salsa::invoke(crate::lower::generic_predicates_without_parent_query)]
158+
fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates;
159+
157160
#[salsa::invoke(crate::lower::trait_environment_for_body_query)]
158161
#[salsa::transparent]
159162
fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc<TraitEnvironment>;

crates/hir-ty/src/lower.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,28 @@ pub(crate) fn generic_predicates_query(
17001700
db: &dyn HirDatabase,
17011701
def: GenericDefId,
17021702
) -> GenericPredicates {
1703+
generic_predicates_filtered_by(db, def, |_, _| true)
1704+
}
1705+
1706+
/// Resolve the where clause(s) of an item with generics,
1707+
/// except the ones inherited from the parent
1708+
pub(crate) fn generic_predicates_without_parent_query(
1709+
db: &dyn HirDatabase,
1710+
def: GenericDefId,
1711+
) -> GenericPredicates {
1712+
generic_predicates_filtered_by(db, def, |_, d| *d == def)
1713+
}
1714+
1715+
/// Resolve the where clause(s) of an item with generics,
1716+
/// except the ones inherited from the parent
1717+
fn generic_predicates_filtered_by<F>(
1718+
db: &dyn HirDatabase,
1719+
def: GenericDefId,
1720+
filter: F,
1721+
) -> GenericPredicates
1722+
where
1723+
F: Fn(&WherePredicate, &GenericDefId) -> bool,
1724+
{
17031725
let resolver = def.resolver(db.upcast());
17041726
let (impl_trait_lowering, param_lowering) = match def {
17051727
GenericDefId::FunctionId(_) => {
@@ -1714,6 +1736,7 @@ pub(crate) fn generic_predicates_query(
17141736

17151737
let mut predicates = resolver
17161738
.where_predicates_in_scope()
1739+
.filter(|(pred, def)| filter(pred, def))
17171740
.flat_map(|(pred, def)| {
17181741
ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
17191742
})

crates/hir-ty/src/object_safety.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use hir_def::{
1212
lang_item::LangItem, AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId,
1313
TypeAliasId,
1414
};
15-
use rustc_hash::{FxHashMap, FxHashSet};
15+
use rustc_hash::FxHashSet;
1616
use smallvec::SmallVec;
1717

1818
use crate::{
@@ -417,30 +417,11 @@ where
417417
cb(MethodViolationCode::UndispatchableReceiver)?;
418418
}
419419

420-
let predicates = &*db.generic_predicates(func.into());
421-
let mut parent_predicates = (*db.generic_predicates(trait_.into()))
422-
.iter()
423-
.map(|b| b.skip_binders().skip_binders().clone())
424-
.fold(FxHashMap::default(), |mut acc, item| {
425-
acc.entry(item)
426-
.and_modify(|cnt| {
427-
*cnt += 1;
428-
})
429-
.or_insert(1);
430-
acc
431-
});
420+
let predicates = &*db.generic_predicates_without_parent(func.into());
432421
let trait_self_idx = trait_self_param_idx(db.upcast(), func.into());
433422
for pred in predicates {
434423
let pred = pred.skip_binders().skip_binders();
435424

436-
// Skip predicates from parent, i.e. the trait that contains this method
437-
if let Some(cnt) = parent_predicates.get_mut(pred) {
438-
if *cnt > 0 {
439-
*cnt -= 1;
440-
continue;
441-
}
442-
}
443-
444425
if matches!(pred, WhereClause::TypeOutlives(_)) {
445426
continue;
446427
}

crates/hir-ty/src/object_safety/tests.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,20 @@ pub trait Trait {
361361
[("Trait", vec![])],
362362
);
363363
}
364+
365+
#[test]
366+
fn std_error_is_object_safe() {
367+
check_object_safety(
368+
r#"
369+
//- minicore: fmt, dispatch_from_dyn
370+
trait Erased<'a>: 'a {}
371+
372+
pub struct Request<'a>(dyn Erased<'a> + 'a);
373+
374+
pub trait Error: core::fmt::Debug + core::fmt::Display {
375+
fn provide<'a>(&'a self, request: &mut Request<'a>);
376+
}
377+
"#,
378+
[("Error", vec![])],
379+
);
380+
}

0 commit comments

Comments
 (0)