-
Notifications
You must be signed in to change notification settings - Fork 13.8k
Implement pin-project in pattern matching for &pin mut|const T
#139751
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
base: master
Are you sure you want to change the base?
Conversation
rustbot has assigned @compiler-errors. Use |
This comment has been minimized.
This comment has been minimized.
☔ The latest upstream changes (presumably #139996) made this pull request unmergeable. Please resolve the merge conflicts. |
0ad1543
to
e9c97df
Compare
This comment has been minimized.
This comment has been minimized.
24e0b14
to
aa27a06
Compare
&pin mut|const T
&pin mut|const T
This comment has been minimized.
This comment has been minimized.
aa27a06
to
c9ca4f8
Compare
This comment has been minimized.
This comment has been minimized.
Some changes occurred to the CTFE machinery Some changes occurred in match checking cc @Nadrieril Some changes occurred in compiler/rustc_codegen_ssa Some changes occurred in src/tools/clippy cc @rust-lang/clippy Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt The Miri subtree was changed cc @rust-lang/miri Some changes occurred in compiler/rustc_monomorphize/src/partitioning/autodiff.rs cc @ZuseZ4 rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead. cc @rust-lang/rust-analyzer Some changes occurred in exhaustiveness checking cc @Nadrieril Some changes occurred in match lowering cc @Nadrieril Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 |
It seems like you're implementing a sort of match ergonomics through I think pinnedness should be part of the binding mode instead of a separate notion. I haven't looked deeply yet but presumably this will raise questions similar to deref patterns and the recent match ergonomics changes. cc @dianne |
+1 to representing pinnedness as part of the binding mode. Regarding match ergonomics interactions, I think we'll either want explicit Regarding deref patterns interactions, we'll probably also want pin ergonomics for deref patterns eventually. I don't think that'll be a problem, if I understand what |
Another ergonomics question: is there a way to get a non-pinned by-shared-ref binding when matching through |
Does "match ergonomics" refer to rfcs#2005? I see it has been stabilized in 2018, and I'm not quite familiar with "ancient" Rust before (I started to learn Rust in 2021). My intuition is just based on the crate pin_project. Take an example from its doc: use std::pin::Pin;
use pin_project::pin_project;
#[pin_project(project = EnumProj)]
enum Enum<T, U> {
Pinned(#[pin] T),
Unpinned(U),
}
impl<T, U> Enum<T, U> {
fn method(self: Pin<&mut Self>) {
match self.project() {
EnumProj::Pinned(x) => {
let _: Pin<&mut T> = x;
}
EnumProj::Unpinned(y) = {
let _: &mut U = y;
}
}
}
} It uses the With #![feature(pin_ergonomics)]
enum Enum<T, U> {
// `#[pin]` is no longer needed, as we can infer from the trait bound whether `T` is `Unpin`.
Pinned(T),
Unpinned(U),
}
// `U: Unpin` is needed to inform the compiler that `U` can be projected to a normal reference.
impl<T, U: Unpin> Enum<T, U> {
fn method(&pin mut self) {
// `self.projection()` is no longer needed, as the compiler
// would understand how to project a `&pin mut Enum<T, U>`
match self {
// `EnumProj` is no longer needed
Enum::Pinned(x) => {
// for `T: ?Unpin`, it is projected to `&pin mut T`
let _: &pin mut T = x;
}
Enum::Unpinned(y) = {
// for `U: Unpin`, it is projected to `&mut U`
let _: &mut U = y;
}
}
}
} That's how I implemented this PR. |
That RFC is indeed pretty old, and isn't quite what's implemented in Rust 20241. I'm using "match ergonomics" loosely to mean a couple things (sorry for the jargon!):
From what I could tell, this PR supports the former of these but not the latter; for consistency with how matching on normal references works, I'd expect to be able to use explicit reference patterns to match on
It should indeed be possible to utilize the There might be additional subtleties/complications I'm not aware of, of course. I'm not deeply familiar with the trait solver, so I'm not totally sure how unambiguous you can guarantee its results to be. Hence my suggestion to raise an error when there's ambiguities. Footnotes
|
This comment was marked as duplicate.
This comment was marked as duplicate.
@rustbot ready |
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.
Ok, this looks good now, wtih three caveats:
- Please remove the
InheritedRefMatchRule::EatInner
bit I commented on, it does nothing on stable rust and we'll have to be more careful about how this interacts with match ergonomics 2.0 later; - I'm requesting some changes to the tests;
- I cannot review the part about negative impls. If at all possible split it to another PR so that we can merge this, otherwise we can ask for a second reviewer to look at it.
}; | ||
|
||
#[cfg(pin_ergonomics)] | ||
let Foo { x, y } = foo; |
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.
Could you test the type of the bindings like you do in the other tests? Could you also remove the cfg
so we can see what happens with just deref_patterns
(I think it should work, but seeing the error is good too).
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 uncommented this, but got an error of cannot move out of a shared reference
(under deref_patterns
feature only). Seems that x
and y
have by-value bindings. Do you know if this behaviour is expected?
compiler/rustc_hir_typeck/src/pat.rs
Outdated
if let ty::Ref(_, _, r_mutbl) = *expected.kind() | ||
&& pat_mutbl <= r_mutbl | ||
{ | ||
let expected_ref_or_pinned_ref = || { | ||
if self.tcx.features().pin_ergonomics() | ||
&& let Some(ty::Ref(_, _, r_mutbl)) = | ||
expected.pinned_ty().map(|ty| *ty.kind()) | ||
&& pat_mutbl <= r_mutbl | ||
{ | ||
return Some((Pinnedness::Pinned, r_mutbl)); | ||
} | ||
if let ty::Ref(_, _, r_mutbl) = *expected.kind() | ||
&& pat_mutbl <= r_mutbl | ||
{ | ||
return Some((Pinnedness::Not, r_mutbl)); | ||
} | ||
None | ||
}; | ||
if let Some((_, r_mutbl)) = expected_ref_or_pinned_ref() { |
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'm confused, this should be allowing let &mut foo: &pin mut T
, but you have a test that shows that this gives a type mismatch error. Do you understand why? If not that, what's the purpose of this change here?
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.
Oh it's that this applies only to InheritedRefMatchRule::EatInner
which is behavior gated under ref_pat_eat_one_layer_2024_structural
. You have to support EatBoth
for stable rust (you can probably ignore the other two variants for now, they're for feature gates). Anyway I think it's better not to allow &mut x
to eat a &pin mut T
for now, let's leave this to a future PR.
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.
Oh it's that this applies only to
InheritedRefMatchRule::EatInner
which is behavior gated underref_pat_eat_one_layer_2024_structural
.
Thanks. Actually, I don't understand InheritedRefMatchRule
very well, but it works now as your suggestion.
Anyway I think it's better not to allow
&mut x
to eat a&pin mut T
for now, let's leave this to a future PR.
I think it is reasonable to allow &mut x
to eat a &pin mut T
if T: Unpin
, but I agree that it can be resolved in a future PR.
This comment has been minimized.
This comment has been minimized.
c33c6d8
to
a4565b1
Compare
☔ The latest upstream changes (presumably #145043) made this pull request unmergeable. Please resolve the merge conflicts. |
a4565b1
to
646e905
Compare
@rustbot ready |
☔ The latest upstream changes (presumably #146728) made this pull request unmergeable. Please resolve the merge conflicts. |
646e905
to
e9cf302
Compare
Some changes occurred in compiler/rustc_passes/src/check_attr.rs Some changes occurred in compiler/rustc_hir/src/attrs Some changes occurred in compiler/rustc_attr_parsing |
This comment has been minimized.
This comment has been minimized.
e9cf302
to
b3924c7
Compare
This PR was rebased onto a different master 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. |
I reimplemented the projection rules according to the Alternative B part: using a Checks for manual implementation of |
This comment has been minimized.
This comment has been minimized.
b3924c7
to
b93969f
Compare
The job Click to see the possible cause of the failure (guessed by this bot)
|
This PR implements part of #130494. It supports pin-project in pattern matching for
&pin mut|const T
.Pin-projection by field access (i.e.
&pin mut|const place.field
) is not fully supported yet since pinned-borrow is not ready (#135731).CC @traviscross