type_id_eq seems should always be true, but that situation is limited to the type T not changed. We can do type coercion to change the type forcedly, then the conflict appears.
fn main() {
let origin = Box::new(MyData::new("aaa".to_string()));
let new_type = origin as Box<MyData<dyn AsRef<str>>>;
assert!(!new_type.type_id_eq());
}
Can I both prevent the outside code from coerce the type and reserve a method to change the type in my specified way?
error[E0308]: mismatched types
--> src/main.rs:28:46
|
28 | let new_type: MyData<fn(&'static str)> = origin;
| ^^^^^^ one type is more general than the other
|
= note: expected struct `MyData<fn(&_)>`
found struct `MyData<for<'a> fn(&'a _)>`
Uh, but this limitation makes T never be unsized though...
Then the new_type you tried before will be rejected as a non-primitive cast.
You can write a helper method that coerces the inner Box and resets id, at least for specific types, but I don't think you can do that generically until Unsize is stable (or you use that on nightly).
Thanks, I think it is close to the best workaround. I think the rejection may be because the size of the pointer inside Box will grow when casting a sized type to unsized type (But I don't know why it can coerce when not surrounded by Box). But @quinedot 's subtyping example doesn't require size growth, so that unsound code can still pass the compilation.
let origin: MyData<fn(&str)> = MyData::new(|_| {});
let new_type: MyData<fn(&'static str)> = origin;
assert!(! new_type.type_id_eq());
Adding the phantom fn item I mentioned above will solve this problem.
As far as I know, the language offers no guaranted way to opt out of type-changing coercions (etc); if one you haven't thought of is or becomes possible in safe code, and unsoundness results, that would be on you.