(There was a previous discussion about this, but it was locked for inactivity without any comments.)
Is there a reason why MaybeUninit<T> needs to require T: Sized? It seems meaningful to be able to do it on unsized T, and doing so would also be useful. (My usecase involves a wrapper type that asserts that a MaybeUninit<T> is in fact initialised and thus allows safe assume_init_ref and assume_init_mut operations โ it's both meaningful and useful to do an unsized coercion on this wrapper type, e.g. from Wrapper<T> to Wrapper<dyn Trait>, but this would require coercing the underlying MaybeUninit<T> to MaybeUninit<dyn Trait>. The best available alternative would involve recreating &MaybeUninit and &mut MaybeUninit using raw pointers, but this would make the code much harder to read and write and much fuller of unsafe, so it would significantly raise the chance of a soundness error โ it also makes type-generic code much harder to write because most existing traits think in terms of references rather than pointers.)
As far as I can tell, this restriction occurs because unions don't support unsized fields, and that restriction occurs for unknown reasons: it isn't specified in the Rust reference, and the Rust compiler produces a confusing error message when you try (it states that T needs to be sized due to appearing in ManuallyDrop<T>, but ManuallyDrop can wrap unsized types โ there's a separate help message stating that unions don't allow unsized fields, but that's in addition to the incorrect explanation rather than instead of it).
As such, I'd like to suggest either a) allowing unsized fields in unions, or b) special-casing MaybeUninit so that it can have an unsized field despite being a union. The semantics would be that the appropriate metadata is always present and is used to determine the size/alignment of the union, but is otherwise used only when accessing the unsized union field and ignored when accessing the other fields. For example, you could coerce a MaybeUninit<String> to a MaybeUninit<dyn Debug>, and the resulting type would be an unsized type whose runtime size and alignment were the same as those of String, and would use String's vtable when accessing the type as though it were initialized. For simplicity, it is probably best to limit this to one unsized field per union, to avoid needing to juggle two different sets of metadata (Rust already has a rule like this for other unsized types, e.g. you can't coerce Box<[u32]> to Box<dyn Debug> because the resulting type would have two different sets of unsized metadata).
Not all the methods of MaybeUninit work on unsized types (e.g. you couldn't use the by-value assume_init), but enough of them do to still be able to use it meaningfully.
Is there a reason why this wouldn't work? Or is it just the fact that it hasn't been implemented yet, or that it would require an exception to usual language design rules? (I can't think of any other use cases for unsized unions, but then there aren't many use cases for unions in Rust in general.)