Just driving by to say that I've been exposed to something like this in the wild (though they had done it unsoundly abusing monomorphization behavior that we'll hopefully close up to some extent).
It was frankly confusing as framed in their system, but the trick is that a type with no "lifetime positions" (in its monomorphic fully-normalized form that is a tree of type constructor applications) can be known to meet a : 'static
without having to specify that bound statically (so a bit like needs_drop
).
In a sense, this can be seen as a version of T: 'static
that can be used during trait impl specialization, in that it only matches when the bound holds across all possible choices of lifetimes in T
(which gets back to "T
has no lifetime positions" almost by definition, since any of them would invalidate 'static
).
I agree about integrating with TypeId
(and Any
, in their case), but I'm not fond on having a separate all_types_with_this_id_are_static
intrinsic (my suggestion was TypeId::of_lifetimeless
, which would have its own intrinsic returning Option
).
Also, the problem with not labeling it specially ("lifetimeless" was my bikeshed) is that it can fail for types that are in fact : 'static
.
To complete your example:
assert_eq!(TypeId::of::<&'static str>(), TypeId::of::<&'static str>());
assert!(! TypeId::of::<&'static str>().same_as::<&'static str>());
So by that measure, same_as
is too misleading of a name.
Whereas if we added suffixed methods to TypeId
/Any
, this would make sense IMO:
let any_str = &"foo" as &dyn Any;
// Successes:
assert_eq!(any_str.type_id(), TypeId::of::<&'static str>());
assert_eq!(any_str.downcast_ref::<&'static str>(), Some("foo"));
// Failures:
assert_eq!(TypeId::of_lifetimeless::<&'static str>(), None);
assert_eq!(any_str.downcast_lifetimeless_ref::<&'static str>(), None);
Maybe "lifetimeless" is a poor name for the concept, but regardless we should come up with one that's distinguishing enough to not be mistaken as being a helpful shorthand, and thoroughly document it.