ctor: Extend Ctor blanket impl to !Unpin types.
#336
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
ctor: Extend
Ctorblanket impl to!Unpintypes.Instead, we use a
SelfCtorauto trait. This is implemented for all types by default, except those that are designed to be a Ctor for something else (that is, after all, the point of this crate). Especially FnCtor. Since it's an auto trait, it also would fail to be implemented for types that contain a FnCtor or the like, but "just don't do that" applies. Ultimately, specialization would be much better, but specialization is also much more fraught.This still requires trait bounds on the part of the caller. For example:
This function does not work:
Even though
xalmost certainly implementsCtor<Output=Self, Error=Infallible>, the implementation strategy chosen here doesn't guarantee it. Things can construct things other than themselves.Instead, you need to write
passes_fooas follows:Or, less preferably:
Ultimately, you need to propagate the
Ctorrequirement, like any trait bound, all the way up until it reaches the user with the concrete type. However, once that happens, this CL now ensures that the obviousCtorimplementation will exist.This should mean we don't ever need users to pass in
RustMoveCtor(x)or have a separate function takingxby value: theCtor-based version is a near-strict superset for concrete types, and only requires an extra trait bound for non-concrete types.Why not
auto trait RustMovable?The linked bug suggested we use
RustMovableas a trait (notSelfCtor). I tried that, actually. It is very complex, and does more than we need to.The (ab)use of the
Unpintrait here was almost solely to decide if Rust moves are a valid form of initialization. The fact of the matter is, Rust moves are always a valid form of initialization, if you have a value. If there is a non-Rust-movable type, it should never exist by value, so the topic will not come up.So we don't need a separate trait here for non-Rust-movable values, we just need to ensure that they don't exist. Which we did anyway.
But aside from being overkill, it was very hard. Once you're in the game of a non-Rust-movable trait, you need to deal with all the corner cases. For example:
There are a gazillion special cases where rust-movability doesn't follow the same rules as auto traits do.
Unpinhas to implement each of these separately, and many depend on unstable features. So we'd be in a constant game of catch-up withUnpinto accurately describe the cases that are Rust-movable.And we can't just lean on
Unpin-- you could imagine writing it as so:In fact, I tried this. The problem is coherence: while every type is either Unpin or not, Rust does not always advertise this fact. For example, perhaps you'd want to do:
Is this valid?
No! Rust will complain of a semver problem: PhantomPinned does not promise for eternity that it will always be non-Unpin, and so there is a potential overlapping impl problem where this might conflict with the earlier blanket impl.
So... it's a lot of work to get this right, and requires copy-pasting the
Unpintrait impls and keeping them up to date. Yet it gives no actual benefits, here, compared to aSelfCtortrait, as the actual concrete use case is much more limited than Rust-movability.Therefore I'm not implementing the bug as written, but implementing this instead.