-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
coercion: use a generalization of the target to specialize the source to coerce instead of propagating the wrong type. #27292
Conversation
r? @arielb1 (rust_highfive has picked a reviewer for you, use r? to override) |
r? @pnkfelix |
… to coerce instead of propagating the wrong type.
07ffd64
to
7e888f0
Compare
@eddyb I'm confused by the description you have in this issue. When you write "That workaround is implemented in this PR", I now infer that you mean: "This PR makes it unnecessary to explicitly write such workarounds in one's code, because the compiler will now effectively do the work for you." So, before I jump into the review itself, is that a correct inference ? (And if so, maybe rephrase the description so that the commit of the code to the repo will have a somewhat clearer statement of its purpose?) update: (maybe part of my issue is that I jumped straight to reading the description of this PR without reading its title. This is a common "mistake" I make, though I'm not really sure its a mistake since bors still does not include the titles of PR's in its merge commit messages. I.e. you should not assume that people can see the title; the PR's description should be able to stand on its own. I often deal with this by just cut-and-pasting my title into my description's first line, to be honest.) |
@eddyb oh, no, wait, my inference above was incorrect, I guess? That is, you do still need to employ the described workaround in the user's code. (I only realized this reading the comments and then skipping ahead to the test case.) So now I'm back to trying to work out what this patch is accomplishing in practice. |
@pnkfelix I did expect to need changes to the explanations, as the feature itself is a bit convoluted. |
@eddyb yes, that sounds better. I still need to read the test case more carefully, I'll have more feedback shortly. |
It may be even nicer to have a test that shows the kind of case that we really expect to come up, namely where no type annotation is present at all on any of the local variables, and instead the constraints like Having said that, at least I grok the test at this point. |
} | ||
_ => {} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so, in the code before this PR, the control flow that reached this point (line 159) corresponds to the comment above "Otherwise, just use subtyping rules."
Clearly you are no longer "just using the subtyping rules" in the code that follows that point in the control flow here. :)
Still, for some reason I wish there was a comment line or two here of the same pithy nature as "Otherwise just use subtyping rules" before jumping straight into the discussion of "generalization in hopes of an unsizing coercion" ... something that helped the reader re-establish what case we are in in the coercion analysis? Or is that just a pipe dream?
Update: I might be thinking of a comment along the lines of:
"Attempt to select all
CoerceUnsized
andUnsized
obligations (as well as applying subtyping rules). Other obligations will be gathered and applied later."
(Basically restating/summarizing the comment above CoerceUnsizedResult
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something along the lines of "All attempts at coercion have failed, must use subtyping (or try harder)."?
I have found a relatively simple example that will be mishandled by the current implementation: impl CoerceUnsized<Pointer<Trait>> for Pointer<Trait> {}
impl<T: Trait> CoerceUnsized<Pointer<Trait>> for Pointer<T> {} Selecting |
I've skimmed this but I really want @nikomatsakis to look at it too, since I think has expressed concern over the growing complexity of the coercion logic. |
Sorry, I'm being slow again. I plan to examine this this week. I have to admit I am pretty wary here, though, I sort of want to tread lightly on inference until we have a feeling for the full set of use cases that we aim to support. Modifying the unsizing coercion seems like an interesting approach but not clearly the right one -- and these sorts of changes are very hard to "contain" in terms of stabilization. |
☔ The latest upstream changes (presumably #28138) made this pull request unmergeable. Please resolve the merge conflicts. |
ping? needs a review? |
Yes, I've been very overwhelmed. I'm working on clearing my backlog right now, including this PR. |
/// If successful, all `CoerceUnsized` and `Unsized` obligations were selected. | ||
/// Other obligations, such as `T: Trait` for `&T -> &Trait`, are provided | ||
/// alongside the adjustment, to be enforced later. | ||
type CoerceUnsizedResult<'tcx> = Result<(AutoDerefRef<'tcx>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this type is getting complex enough that adding a struct to represent the Ok case might be a good idea, or else using a different enum altogether.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe I had tried that at some point and it got unwieldy, but maybe just a struct
would work.
/me starts reading this PR. Sorry for the delay. |
(OK, still reading, sorry, this is dense code I'm having to bring it back into cache) |
@nikomatsakis Any progress on this? I almost feel like we should move to https://reviewable.io/ so we can keep track of reviews. |
A meta-comment: I think that changes like this ought to be feature-gated in some way, like any other. This one seems particularly amenable to such treatment. |
@eddyb not sure if you saw my comments on this; sorry it took me so amazingly long to read it. The main reason for the delay is that I feel like we need to get a better handle on coercions before we go and expand them, it's hard for me to tell if this approach is good or is something that will box us into a corner. A feature gate would make me feel a lot better about that. All that said, there is only so long we need to stall here-- I admit this patch is a lot cleaner and more elegant than I initially anticipated, and this may well be a part of the way forward. Perhaps a good idea would be to schedule a time to brainstorm and chat about this as a video chat. I'd also like to sketch out how this affects other scenarios that seem strongly related; I have a few in mind but have to go scouring logs to find the specific examples. |
(ping) Should this be rebased? Closed? (just clearing out the queue) |
@alexcrichton Heh. This is an old PR by now. @eddyb and I still have not caught up as I described in my comment -- but maybe we can make time for it. I've forgotten the details of this PR now but I remember it was nicer than I feared. :) This part of the codebase hasn't really changed much in the meantime though, I imagine rebasing would not be so hard. |
@nikomatsakis Actually, I've abandoned this PR as there are other issues, and there is a much more principled approach to the whole thing. |
No worries, I'll take a look now:) |
The issue solved here involved generic "constructor" traits and unsizing coercions.
A real usecase is
box
desugaring, which is being demonstrated as a test-case.Given such a trait with more than one implementation, e.g. for
Box<T>
andRc<T>
:An direct call would be too unconstrained for a coercion, so the expected type ends up propagated:
The workaround was to manually specify enough about the produced type to allow resolving it:
That workaround is implemented in this PR, for all coercions where unsizing was ambiguous.
A generalized type is picked based on the
CoerceUnsize
impl that could be used for coercing.For example,
CoerceUnsized<Box<Error>>
is implemented byBox<T> forall T
, so the generalizedtype is
Box<_>
, which matches bothBox<E>
andBox<Error>
.Such generalization allows constraining the source of the potential coercion while still allowing
it to be any type that could coerce to the target, or the target type itself.