Description
When polymorphization is enabled (-Zpolymorphization=on
), then this can currently be observed by TypeId
. For example, the following code when built with a polymorphization-enabled compiler will fail the asserts (and succeeds normally; playground):
fn nop<T>() {}
fn test_the_waters<A: 'static, B: 'static>(a: A, _: B) {
let any: Box<dyn std::any::Any> = Box::new(a);
assert!(any.downcast_ref::<A>().is_some());
assert!(any.downcast_ref::<B>().is_none());
assert!(any.downcast_ref::<fn()>().is_none());
}
fn main() {
test_the_waters(nop::<u32>, nop::<u64>);
}
This issue was discovered while investigating an earlier regression. After #74538 landed, the example shown below, where a polymorphized closure is indirectly passed to TypeId
, would result in an ICE (discussion from that investigation):
use std::any::TypeId;
pub fn foo<T: 'static>(_: T) -> TypeId {
TypeId::of::<T>()
}
fn outer<T: 'static>() -> TypeId {
foo(|| ())
}
fn main() {
assert!(outer::<u8>() != outer::<u16>());
}
In #74717, the check introduced in #74538 was modified so that this case (and another unrelated case) would no longer ICE for polymorphized functions (discussion regarding that PR). There have been more recent discussion regarding this in a dedicated Zulip topic.
Unresolved questions:
- What is the appropriate behaviour here w/r/t polymorphization?
- Current consensus appears to be that functions involving reflection cannot be polymorphized.
- How do we fix this?
- Without triggering cycle errors, detecting when polymorphization is not appropriate due to later use of
TypeId
seems very challenging.
- Without triggering cycle errors, detecting when polymorphization is not appropriate due to later use of