Rollup merge of #136246 - hkBst:patch-29, r=ibraheemdev
include note on variance and example Fixes #89150
This commit is contained in:
commit
052ebc65b2
1 changed files with 96 additions and 2 deletions
|
@ -610,6 +610,101 @@ impl dyn Any + Send + Sync {
|
||||||
/// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth
|
/// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth
|
||||||
/// noting that the hashes and ordering will vary between Rust releases. Beware
|
/// noting that the hashes and ordering will vary between Rust releases. Beware
|
||||||
/// of relying on them inside of your code!
|
/// of relying on them inside of your code!
|
||||||
|
///
|
||||||
|
/// # Danger of Improper Variance
|
||||||
|
///
|
||||||
|
/// You might think that subtyping is impossible between two static types,
|
||||||
|
/// but this is false; there exists a static type with a static subtype.
|
||||||
|
/// To wit, `fn(&str)`, which is short for `for<'any> fn(&'any str)`, and
|
||||||
|
/// `fn(&'static str)`, are two distinct, static types, and yet,
|
||||||
|
/// `fn(&str)` is a subtype of `fn(&'static str)`, since any value of type
|
||||||
|
/// `fn(&str)` can be used where a value of type `fn(&'static str)` is needed.
|
||||||
|
///
|
||||||
|
/// This means that abstractions around `TypeId`, despite its
|
||||||
|
/// `'static` bound on arguments, still need to worry about unnecessary
|
||||||
|
/// and improper variance: it is advisable to strive for invariance
|
||||||
|
/// first. The usability impact will be negligible, while the reduction
|
||||||
|
/// in the risk of unsoundness will be most welcome.
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
///
|
||||||
|
/// Suppose `SubType` is a subtype of `SuperType`, that is,
|
||||||
|
/// a value of type `SubType` can be used wherever
|
||||||
|
/// a value of type `SuperType` is expected.
|
||||||
|
/// Suppose also that `CoVar<T>` is a generic type, which is covariant over `T`
|
||||||
|
/// (like many other types, including `PhantomData<T>` and `Vec<T>`).
|
||||||
|
///
|
||||||
|
/// Then, by covariance, `CoVar<SubType>` is a subtype of `CoVar<SuperType>`,
|
||||||
|
/// that is, a value of type `CoVar<SubType>` can be used wherever
|
||||||
|
/// a value of type `CoVar<SuperType>` is expected.
|
||||||
|
///
|
||||||
|
/// Then if `CoVar<SuperType>` relies on `TypeId::of::<SuperType>()` to uphold any invariants,
|
||||||
|
/// those invariants may be broken because a value of type `CoVar<SuperType>` can be created
|
||||||
|
/// without going through any of its methods, like so:
|
||||||
|
/// ```
|
||||||
|
/// type SubType = fn(&());
|
||||||
|
/// type SuperType = fn(&'static ());
|
||||||
|
/// type CoVar<T> = Vec<T>; // imagine something more complicated
|
||||||
|
///
|
||||||
|
/// let sub: CoVar<SubType> = CoVar::new();
|
||||||
|
/// // we have a `CoVar<SuperType>` instance without
|
||||||
|
/// // *ever* having called `CoVar::<SuperType>::new()`!
|
||||||
|
/// let fake_super: CoVar<SuperType> = sub;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The following is an example program that tries to use `TypeId::of` to
|
||||||
|
/// implement a generic type `Unique<T>` that guarantees unique instances for each `Unique<T>`,
|
||||||
|
/// that is, and for each type `T` there can be at most one value of type `Unique<T>` at any time.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// mod unique {
|
||||||
|
/// use std::any::TypeId;
|
||||||
|
/// use std::collections::BTreeSet;
|
||||||
|
/// use std::marker::PhantomData;
|
||||||
|
/// use std::sync::Mutex;
|
||||||
|
///
|
||||||
|
/// static ID_SET: Mutex<BTreeSet<TypeId>> = Mutex::new(BTreeSet::new());
|
||||||
|
///
|
||||||
|
/// // TypeId has only covariant uses, which makes Unique covariant over TypeAsId 🚨
|
||||||
|
/// #[derive(Debug, PartialEq)]
|
||||||
|
/// pub struct Unique<TypeAsId: 'static>(
|
||||||
|
/// // private field prevents creation without `new` outside this module
|
||||||
|
/// PhantomData<TypeAsId>,
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// impl<TypeAsId: 'static> Unique<TypeAsId> {
|
||||||
|
/// pub fn new() -> Option<Self> {
|
||||||
|
/// let mut set = ID_SET.lock().unwrap();
|
||||||
|
/// (set.insert(TypeId::of::<TypeAsId>())).then(|| Self(PhantomData))
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl<TypeAsId: 'static> Drop for Unique<TypeAsId> {
|
||||||
|
/// fn drop(&mut self) {
|
||||||
|
/// let mut set = ID_SET.lock().unwrap();
|
||||||
|
/// (!set.remove(&TypeId::of::<TypeAsId>())).then(|| panic!("duplicity detected"));
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// use unique::Unique;
|
||||||
|
///
|
||||||
|
/// // `OtherRing` is a subtype of `TheOneRing`. Both are 'static, and thus have a TypeId.
|
||||||
|
/// type TheOneRing = fn(&'static ());
|
||||||
|
/// type OtherRing = fn(&());
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let the_one_ring: Unique<TheOneRing> = Unique::new().unwrap();
|
||||||
|
/// assert_eq!(Unique::<TheOneRing>::new(), None);
|
||||||
|
///
|
||||||
|
/// let other_ring: Unique<OtherRing> = Unique::new().unwrap();
|
||||||
|
/// // Use that `Unique<OtherRing>` is a subtype of `Unique<TheOneRing>` 🚨
|
||||||
|
/// let fake_one_ring: Unique<TheOneRing> = other_ring;
|
||||||
|
/// assert_eq!(fake_one_ring, the_one_ring);
|
||||||
|
///
|
||||||
|
/// std::mem::forget(fake_one_ring);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[derive(Clone, Copy, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Eq, PartialOrd, Ord)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct TypeId {
|
pub struct TypeId {
|
||||||
|
@ -627,8 +722,7 @@ impl PartialEq for TypeId {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeId {
|
impl TypeId {
|
||||||
/// Returns the `TypeId` of the type this generic function has been
|
/// Returns the `TypeId` of the generic type parameter.
|
||||||
/// instantiated with.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue