Implement coercions between &pin (mut|const) T and &(mut) T when T: Unpin#149130
Implement coercions between &pin (mut|const) T and &(mut) T when T: Unpin#149130frank-king wants to merge 2 commits intorust-lang:mainfrom
&pin (mut|const) T and &(mut) T when T: Unpin#149130Conversation
This comment has been minimized.
This comment has been minimized.
29a89ae to
92596db
Compare
|
Some changes occurred in need_type_info.rs cc @lcnr Some changes occurred in src/tools/clippy cc @rust-lang/clippy Some changes occurred in exhaustiveness checking cc @Nadrieril |
|
r? @nnethercote rustbot has assigned @nnethercote. Use |
|
I am not a good person to review this. How about... r? @lcnr |
|
r? types |
|
r? types |
|
☔ The latest upstream changes (presumably #148602) made this pull request unmergeable. Please resolve the merge conflicts. |
92596db to
500d786
Compare
This comment has been minimized.
This comment has been minimized.
|
☔ The latest upstream changes (presumably #150115) made this pull request unmergeable. Please resolve the merge conflicts. |
There was a problem hiding this comment.
Incredibly sorry about the review latency here.
Overall, the changes look not bad. That being said, there are two very mechanical changes that would be useful to split into a separate PR (or really, a separate commit is fine, but I prefer a separate PR since they stand alone well).
|
Reminder, once the PR becomes ready for a review, use |
500d786 to
2ef4a8a
Compare
This comment has been minimized.
This comment has been minimized.
|
I've split the two refactors to separated PRs:
and a post-refactor PR #151932 (remove @rustbot ready |
…r=jackh726 refactor: remove `Ty::pinned_ref` in favor of `Ty::maybe_pinned_ref` Also returns the `Region` of the reference type in `Ty::maybe_pinned_Ref`. Part of rust-lang#149130. r? jackh726
…r=jackh726 refactor: add an `enum DerefAdjustKind` in favor of `Option<OverloadedDeref>` Part of rust-lang#149130. r? jackh726
This comment has been minimized.
This comment has been minimized.
2ef4a8a to
8dd903c
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
8dd903c to
0422097
Compare
| if self.tcx.features().pin_ergonomics() | ||
| && a.pinned_ty().is_some_and(|ty| ty.is_ref()) | ||
| && let Ok(coerce) = self.commit_if_ok(|_| self.coerce_maybe_pinned_ref(a, b)) | ||
| { | ||
| return Ok(coerce); | ||
| } |
There was a problem hiding this comment.
I am sort of thinking that this code (and the lines added under the ty::Adt arm, should go in coerce_to_ref and coerce_to_pin_ref respectively - keeping this function relatively clean.
There was a problem hiding this comment.
This also would help to eliminate some span_bugs from coerce_maybe_pinned_ref
| let Some((a_ty, a_pinnedness, a_mutbl, a_region)) = a.maybe_pinned_ref() else { | ||
| span_bug!(span, "expect pinned reference or reference, found {:?}", a); | ||
| }; | ||
| let Some((_b_ty, b_pinnedness, b_mutbl, _b_region)) = b.maybe_pinned_ref() else { | ||
| span_bug!(span, "expect pinned reference or reference, found {:?}", b); | ||
| }; |
There was a problem hiding this comment.
Something feels a bit off here to me...I like have one function that covers "all the pinned ref" coercions - but simultaneously all the span_bugs here scream this function being ripe for getting misused or logic changing elsewhere but not updated here.
I sort of wonder if everything before let mut coerce = self.unify_and needs to be done in the calling functions, and necessarily bits get passed in.
There was a problem hiding this comment.
I'm not sure if I fully get your ideas. I removed the coerce_maybe_pinned_ref and split it into coerce_to_pin_ref and coerce_pin_ref_to_ref.
Theoretically, coerce_pin_ref_to_ref can be merged into coerce_to_ref, but I have no idea how to add an autoref before the autoderef (I mean, the Autoderef iterator handles &mut Pin<&mut T> to &mut T and &Pin<&T> to &T well, but for Pin<&mut T> and Pin<&T>, there need to be an autoref at the beginning). I'm also not sure if doing that would mess up the existing code.
There was a problem hiding this comment.
Skimming over, I think your changes look better, but I'm noticing there are test changes, so there are semantic changes i need to think about. Will do a proper review this week.
Use `coerce_to_pin_ref` and `coerce_pin_ref_to_ref` instead.
bc088dd to
ae0c73c
Compare
| if self.tcx.features().pin_ergonomics() | ||
| && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => | ||
| _ if self.tcx.features().pin_ergonomics() | ||
| && let Some((_, ty::Pinnedness::Pinned, mut_b, _)) = b.maybe_pinned_ref() => |
There was a problem hiding this comment.
Should be able to replace this with something like let Ok(pin_coerce) = self.commit_if_ok(|_| self.coerce_to_pin_ref(a, b)) like above?
| && let Some((_, ty::Pinnedness::Pinned, mut_b, _)) = b.maybe_pinned_ref() => | ||
| { | ||
| if a.is_ref() && b.pinned_ty().is_some_and(|ty| ty.is_ref()) { | ||
| return self.coerce_maybe_pinned_ref(a, b); |
There was a problem hiding this comment.
Okay, so I think this is (one of the causes) of the test changes (but similar analysis for the above arm too). Basically, before we "committed" to this coercion, and returned whatever result that gave - and that could be mutability errors.
Now, we aren't committing to this coercion, but are actually falling back to other coercions if this ever encounters a type error (including mutability) - even though we'll never actually be able to fulfill that coercion.
I think keeping the types differ in mutability error is useful. So, we sort of need to separate the notion of "this was the right coercion to try, but failed" from "this wasn't the right coercion to try". Unfortunately, because we do want this to be wrapped in a snapshot, it's kind of not super clean. I think there are two options:
- Split the first part of
coerce_to_pin_refandcoerce_pin_ref_to_refinto separate functions that return anOption<XYZ>(where XYZ is going to be the data that you pass tocoerce_to_pin_refandcoerce_pin_ref_to_ref(either a tuple, or a new struct - probably a new struct would be better). - You make
coerce_to_pin_refandcoerce_pin_ref_to_refreturn notCoerceResult<'tcx>, but instead aInferResult<'tcx, Option<(Vec<Adjustment<'tcx>>, Ty<'tcx>)>>, thencoerce_to_pin_refandcoerce_pin_ref_to_refreturnOk(None)if the coercion path didn't make sense. Technically, this isn't quite perfect, because we actually commit a snapshot for a path that we didn't want - but there should be no vars or anything created, so nothing should actually be committed. But, it means that it's easier for somebody to mess up and reorder things in those functions that do.
I think option 1 is better.
This allows the following (mutual) coercions when
T: Unpin:&T<->Pin<&T>&mut T<->Pin<&mut T>&mut T->Pin<&T>Pin<&mut T>->&TPart of Pin Ergonomics.