mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
Rename object_safety to dyn_compatibility
Up to a trait implemented by another package, linking to $CARGO_HOME/registry/cache/index.crates.io-6f17d22bba15001f/
This commit is contained in:
parent
01aaa53ef2
commit
4255cae1bb
12 changed files with 112 additions and 106 deletions
395
crates/hir-ty/src/dyn_compatibility/tests.rs
Normal file
395
crates/hir-ty/src/dyn_compatibility/tests.rs
Normal file
|
@ -0,0 +1,395 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use hir_def::db::DefDatabase;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use syntax::ToSmolStr;
|
||||
use test_fixture::WithFixture;
|
||||
|
||||
use crate::{dyn_compatibility::dyn_compatibility_with_callback, test_db::TestDB};
|
||||
|
||||
use super::{
|
||||
DynCompatibilityViolation,
|
||||
MethodViolationCode::{self, *},
|
||||
};
|
||||
|
||||
use DynCompatibilityViolationKind::*;
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
enum DynCompatibilityViolationKind {
|
||||
SizedSelf,
|
||||
SelfReferential,
|
||||
Method(MethodViolationCode),
|
||||
AssocConst,
|
||||
GAT,
|
||||
HasNonCompatibleSuperTrait,
|
||||
}
|
||||
|
||||
fn check_dyn_compatibility<'a>(
|
||||
ra_fixture: &str,
|
||||
expected: impl IntoIterator<Item = (&'a str, Vec<DynCompatibilityViolationKind>)>,
|
||||
) {
|
||||
let mut expected: FxHashMap<_, _> =
|
||||
expected.into_iter().map(|(id, osvs)| (id, FxHashSet::from_iter(osvs))).collect();
|
||||
let (db, file_ids) = TestDB::with_many_files(ra_fixture);
|
||||
for (trait_id, name) in file_ids.into_iter().flat_map(|file_id| {
|
||||
let module_id = db.module_for_file(file_id);
|
||||
let def_map = module_id.def_map(&db);
|
||||
let scope = &def_map[module_id.local_id].scope;
|
||||
scope
|
||||
.declarations()
|
||||
.filter_map(|def| {
|
||||
if let hir_def::ModuleDefId::TraitId(trait_id) = def {
|
||||
let name =
|
||||
db.trait_data(trait_id).name.display_no_db(file_id.edition()).to_smolstr();
|
||||
Some((trait_id, name))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}) {
|
||||
let Some(expected) = expected.remove(name.as_str()) else {
|
||||
continue;
|
||||
};
|
||||
let mut osvs = FxHashSet::default();
|
||||
dyn_compatibility_with_callback(&db, trait_id, &mut |osv| {
|
||||
osvs.insert(match osv {
|
||||
DynCompatibilityViolation::SizedSelf => SizedSelf,
|
||||
DynCompatibilityViolation::SelfReferential => SelfReferential,
|
||||
DynCompatibilityViolation::Method(_, mvc) => Method(mvc),
|
||||
DynCompatibilityViolation::AssocConst(_) => AssocConst,
|
||||
DynCompatibilityViolation::GAT(_) => GAT,
|
||||
DynCompatibilityViolation::HasNonCompatibleSuperTrait(_) => {
|
||||
HasNonCompatibleSuperTrait
|
||||
}
|
||||
});
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
assert_eq!(osvs, expected, "Dyn Compatibility violations for `{name}` do not match;");
|
||||
}
|
||||
|
||||
let remains: Vec<_> = expected.keys().collect();
|
||||
assert!(remains.is_empty(), "Following traits do not exist in the test fixture; {remains:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn item_bounds_can_reference_self() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: eq
|
||||
pub trait Foo {
|
||||
type X: PartialEq;
|
||||
type Y: PartialEq<Self::Y>;
|
||||
type Z: PartialEq<Self::Y>;
|
||||
}
|
||||
"#,
|
||||
[("Foo", vec![])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn associated_consts() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
trait Bar {
|
||||
const X: usize;
|
||||
}
|
||||
"#,
|
||||
[("Bar", vec![AssocConst])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bounds_reference_self() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: eq
|
||||
trait X {
|
||||
type U: PartialEq<Self>;
|
||||
}
|
||||
"#,
|
||||
[("X", vec![SelfReferential])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn by_value_self() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait Bar {
|
||||
fn bar(self);
|
||||
}
|
||||
|
||||
trait Baz {
|
||||
fn baz(self: Self);
|
||||
}
|
||||
|
||||
trait Quux {
|
||||
// Legal because of the where clause:
|
||||
fn baz(self: Self) where Self : Sized;
|
||||
}
|
||||
"#,
|
||||
[("Bar", vec![]), ("Baz", vec![]), ("Quux", vec![])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generic_methods() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait Bar {
|
||||
fn bar<T>(&self, t: T);
|
||||
}
|
||||
|
||||
trait Quux {
|
||||
fn bar<T>(&self, t: T)
|
||||
where Self : Sized;
|
||||
}
|
||||
|
||||
trait Qax {
|
||||
fn bar<'a>(&self, t: &'a ());
|
||||
}
|
||||
"#,
|
||||
[("Bar", vec![Method(Generic)]), ("Quux", vec![]), ("Qax", vec![])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mentions_self() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait Bar {
|
||||
fn bar(&self, x: &Self);
|
||||
}
|
||||
|
||||
trait Baz {
|
||||
fn baz(&self) -> Self;
|
||||
}
|
||||
|
||||
trait Quux {
|
||||
fn quux(&self, s: &Self) -> Self where Self : Sized;
|
||||
}
|
||||
"#,
|
||||
[
|
||||
("Bar", vec![Method(ReferencesSelfInput)]),
|
||||
("Baz", vec![Method(ReferencesSelfOutput)]),
|
||||
("Quux", vec![]),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_static() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait Foo {
|
||||
fn foo() {}
|
||||
}
|
||||
"#,
|
||||
[("Foo", vec![Method(StaticMethod)])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sized_self() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait Bar: Sized {
|
||||
fn bar<T>(&self, t: T);
|
||||
}
|
||||
"#,
|
||||
[("Bar", vec![SizedSelf])],
|
||||
);
|
||||
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait Bar
|
||||
where Self : Sized
|
||||
{
|
||||
fn bar<T>(&self, t: T);
|
||||
}
|
||||
"#,
|
||||
[("Bar", vec![SizedSelf])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supertrait_gat() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait GatTrait {
|
||||
type Gat<T>;
|
||||
}
|
||||
|
||||
trait SuperTrait<T>: GatTrait {}
|
||||
"#,
|
||||
[("GatTrait", vec![GAT]), ("SuperTrait", vec![HasNonCompatibleSuperTrait])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supertrait_mentions_self() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait Bar<T> {
|
||||
fn bar(&self, x: &T);
|
||||
}
|
||||
|
||||
trait Baz : Bar<Self> {
|
||||
}
|
||||
"#,
|
||||
[("Bar", vec![]), ("Baz", vec![SizedSelf, SelfReferential])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rustc_issue_19538() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait Foo {
|
||||
fn foo<T>(&self, val: T);
|
||||
}
|
||||
|
||||
trait Bar: Foo {}
|
||||
"#,
|
||||
[("Foo", vec![Method(Generic)]), ("Bar", vec![HasNonCompatibleSuperTrait])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rustc_issue_22040() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: fmt, eq, dispatch_from_dyn
|
||||
use core::fmt::Debug;
|
||||
|
||||
trait Expr: Debug + PartialEq {
|
||||
fn print_element_count(&self);
|
||||
}
|
||||
"#,
|
||||
[("Expr", vec![SelfReferential])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rustc_issue_102762() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: future, send, sync, dispatch_from_dyn, deref
|
||||
use core::pin::Pin;
|
||||
|
||||
struct Box<T: ?Sized> {}
|
||||
impl<T: ?Sized> core::ops::Deref for Box<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
|
||||
|
||||
struct Vec<T> {}
|
||||
|
||||
pub trait Fetcher: Send + Sync {
|
||||
fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
|
||||
where
|
||||
Self: Sync,
|
||||
{
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
[("Fetcher", vec![Method(UndispatchableReceiver)])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rustc_issue_102933() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: future, dispatch_from_dyn, deref
|
||||
use core::future::Future;
|
||||
|
||||
struct Box<T: ?Sized> {}
|
||||
impl<T: ?Sized> core::ops::Deref for Box<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
|
||||
|
||||
pub trait Service {
|
||||
type Response;
|
||||
type Future: Future<Output = Self::Response>;
|
||||
}
|
||||
|
||||
pub trait A1: Service<Response = i32> {}
|
||||
|
||||
pub trait A2: Service<Future = Box<dyn Future<Output = i32>>> + A1 {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
pub trait B1: Service<Future = Box<dyn Future<Output = i32>>> {}
|
||||
|
||||
pub trait B2: Service<Response = i32> + B1 {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
"#,
|
||||
[("A2", vec![]), ("B2", vec![])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rustc_issue_106247() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: sync, dispatch_from_dyn
|
||||
pub trait Trait {
|
||||
fn method(&self) where Self: Sync;
|
||||
}
|
||||
"#,
|
||||
[("Trait", vec![])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn std_error_is_dyn_compatible() {
|
||||
check_dyn_compatibility(
|
||||
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![])],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lifetime_gat_is_dyn_incompatible() {
|
||||
check_dyn_compatibility(
|
||||
r#"
|
||||
//- minicore: dispatch_from_dyn
|
||||
trait Foo {
|
||||
type Bar<'a>;
|
||||
}
|
||||
"#,
|
||||
[("Foo", vec![DynCompatibilityViolationKind::GAT])],
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue