-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Any old type of constant can be used in a pattern #20489
Comments
Surely if you wanted the comparison to use #[deriving(PartialEq)]
struct Foo<T> {
value: T
}
const F: Foo<int> = Foo { value: 2 };
fn main() {
let x = Foo { value: 2 };
match x {
_ if x == F => { println!("Hi"); }
_ => { println!("Ho"); }
}
} Why remove the possibly useful behaviour of using constants as a pattern? |
I was under the impression that |
So, all I'd like to do for this bug is to ensure that we limit the types of such constants to scalars (and maybe tuples of scalars), which I'm sure we can all agree ought to work. We can hash out our disagreements about what the correct semantics ought to be over an RFC, I imagine. But for the record:
|
I really can't agree on this. I don't expect pattern matching to run arbitrary code (which is what running the |
It appears this bug was closed accidentally. I still think this is something we'll have to resolve -- right now, you can match on types that don't implement |
I'll note that in the MIR desugaring branch this becomes much easier to handle. |
triage: P-medium |
Pattern matching is always structural (as I know it from both Rust and other languages), this bug report is very surprising to me. |
+1
+1 @nikomatsakis
as
Given that interpretation, in the next example
Should this matching involve |
I have a hard time imagining how one would even implement |
@petrochenkov yeah, but I no longer stand by that idea. I think it's a good guiding principle, but there is a definite distinction between an enum variant and a constant like: struct Foo { x: i32 }
const fn make_foo(x: i32) -> Foo { Foo { x: x } }
...
const EXAMPLE: Foo = make_foo(22);
...
match something {
EXAMPLE => ...
} what we currently do now in cases like these is to treat that final match as if you wrote: match something {
Foo { x: 22 } => ...
} This effectively introduces two forms of equality: normal equality ( In particular, there is something about taking a constant that is computed through an arbitrary complex compile-time expression and "boiling it down" to the particular result that feels like a violation of abstraction boundaries. Let me give you another example. Imagine I wrote: mod foo {
pub struct Foo { b: bool }
pub const V1: Foo = Foo { b: true };
pub const V2: Foo = Foo { b: false };
} Note that there is an abstraction boundary here: fn bar(f: x::Foo) {
// rustc knows this is exhaustive because if expanded `V1` into equivalent
// patterns; patterns you could not write by hand!
match f {
x::V1 => { }
x::V2 => { }
}
} This seems bad to me. Now if I add new fields to (On play: http://is.gd/exTrhs) Anyway, it seems clear that this topic is controversial enough that it merits a wider audience. I've been planning for some time (months now!) to write an RFC. Things are coming to a head with the MIR rewrite, which requires us to reimplement pattern matching anyhow, and thus makes a good chance to make sure it is doing what we want it to. |
@nikomatsakis |
+1 for "ban constants that assign a value to a private field". Maybe even make matching against |
I opened a discussion thread here: https://internals.rust-lang.org/t/how-to-handle-pattern-matching-on-constants/2846 I also tried to lay out the pros/cons as I see them. Please add additional considerations I forgot about! |
Closing in favor of #31434 |
Example:
I feel pretty sure that we would want matching to use a
PartialEq
impl. For now constant patterns should be limited to uint/int/&str. I'll throw it into a patch I'm working on.The text was updated successfully, but these errors were encountered: