mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-07 17:18:32 +03:00
Relax T: Sized bound on try_as_dyn / try_as_dyn_mut
`trait_info_of` already returns `None` for unsized types, so allowing `T: ?Sized` is sound and lets callers in generic contexts use these functions without a separate `Sized` bound. For unsized `T`, the function always returns `None`.
This commit is contained in:
+14
-4
@@ -1007,18 +1007,23 @@ pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
|
||||
#[must_use]
|
||||
#[unstable(feature = "try_as_dyn", issue = "144361")]
|
||||
pub const fn try_as_dyn<
|
||||
T: Any + 'static,
|
||||
T: Any + ?Sized + 'static,
|
||||
U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized + 'static,
|
||||
>(
|
||||
t: &T,
|
||||
) -> Option<&U> {
|
||||
// For unsized `T`, `trait_info_of` always returns `None` (vtable lookup is
|
||||
// only supported for sized types). The function therefore unconditionally
|
||||
// returns `None` in that case.
|
||||
let vtable: Option<ptr::DynMetadata<U>> =
|
||||
const { TypeId::of::<T>().trait_info_of::<U>().as_ref().map(TraitImpl::get_vtable) };
|
||||
match vtable {
|
||||
Some(dyn_metadata) => {
|
||||
let pointer = ptr::from_raw_parts(t, dyn_metadata);
|
||||
let pointer = ptr::from_raw_parts(t as *const T as *const (), dyn_metadata);
|
||||
// SAFETY: `t` is a reference to a type, so we know it is valid.
|
||||
// `dyn_metadata` is a vtable for T, implementing the trait of `U`.
|
||||
// `T` is sized here because `trait_info_of` only returns `Some` for sized types,
|
||||
// so the thin data pointer fully describes the value.
|
||||
Some(unsafe { &*pointer })
|
||||
}
|
||||
None => None,
|
||||
@@ -1061,18 +1066,23 @@ pub const fn try_as_dyn<
|
||||
#[must_use]
|
||||
#[unstable(feature = "try_as_dyn", issue = "144361")]
|
||||
pub const fn try_as_dyn_mut<
|
||||
T: Any + 'static,
|
||||
T: Any + ?Sized + 'static,
|
||||
U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized + 'static,
|
||||
>(
|
||||
t: &mut T,
|
||||
) -> Option<&mut U> {
|
||||
// For unsized `T`, `trait_info_of` always returns `None` (vtable lookup is
|
||||
// only supported for sized types). The function therefore unconditionally
|
||||
// returns `None` in that case.
|
||||
let vtable: Option<ptr::DynMetadata<U>> =
|
||||
const { TypeId::of::<T>().trait_info_of::<U>().as_ref().map(TraitImpl::get_vtable) };
|
||||
match vtable {
|
||||
Some(dyn_metadata) => {
|
||||
let pointer = ptr::from_raw_parts_mut(t, dyn_metadata);
|
||||
let pointer = ptr::from_raw_parts_mut(t as *mut T as *mut (), dyn_metadata);
|
||||
// SAFETY: `t` is a reference to a type, so we know it is valid.
|
||||
// `dyn_metadata` is a vtable for T, implementing the trait of `U`.
|
||||
// `T` is sized here because `trait_info_of` only returns `Some` for sized types,
|
||||
// so the thin data pointer fully describes the value.
|
||||
Some(unsafe { &mut *pointer })
|
||||
}
|
||||
None => None,
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//@ run-pass
|
||||
#![feature(try_as_dyn)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
// Generic over `?Sized` T: relies on the relaxed bound on `try_as_dyn`.
|
||||
fn try_debug<T: ?Sized + 'static>(t: &T) -> Option<String> {
|
||||
std::any::try_as_dyn::<T, dyn Debug>(t).map(|d| format!("{d:?}"))
|
||||
}
|
||||
|
||||
fn try_debug_mut<T: ?Sized + 'static>(t: &mut T) -> Option<String> {
|
||||
std::any::try_as_dyn_mut::<T, dyn Debug>(t).map(|d| format!("{d:?}"))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Sized case still works through a `?Sized` generic context.
|
||||
let x: i32 = 7;
|
||||
assert_eq!(try_debug(&x).as_deref(), Some("7"));
|
||||
|
||||
let mut y: i32 = 8;
|
||||
assert_eq!(try_debug_mut(&mut y).as_deref(), Some("8"));
|
||||
|
||||
// Unsized `T` always returns `None`, even though `str: Debug` and
|
||||
// `[T]: Debug` hold — vtable lookup for unsized impl types is not
|
||||
// currently supported by `TypeId::trait_info_of`.
|
||||
let s: &str = "hello";
|
||||
assert!(try_debug::<str>(s).is_none());
|
||||
|
||||
let slice: &[i32] = &[1, 2, 3];
|
||||
assert!(try_debug::<[i32]>(slice).is_none());
|
||||
|
||||
let dyn_any: &dyn std::any::Any = &0i32;
|
||||
assert!(try_debug::<dyn std::any::Any>(dyn_any).is_none());
|
||||
}
|
||||
Reference in New Issue
Block a user