-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
We shouldn't even try to resolve irrefutable patterns as constants #49680
Comments
Really given this and #33118 (comment) I'm half convinced we should just epoch-break const patterns to have an explicit |
Note the difference between unhygienic old macros and hygienic new macros. |
See #45050 and linked threads/issues. The proper solution is to
Fixing #33118 (comment) is in my queue, but I didn't consider it high-priority because derives successfully worked for years with their little underscore mangling tricks. |
One horrible workaround that arguably relies on bug #33118 (comment) (please don' t use it) const bar: u8 = 10;
fn main() {
fn bar() {} // fn bar shadows const bar
let bar = (); // OK, bar resolves to fn, fns can't be patterns
} |
@petrochenkov Are you commenting on the correct issue? This one doesn't have to do with macros; it was found by attempting to fix a macro issue but really it's its own thing. The question is, macros aside, should irrefutable patterns allow binding on constants at all? |
Yes.
The previous decision was "Yes". |
That ... seems to be deciding something else, that happened to impact this situation as well -- do we have reasoning for why this should be the case for constants? |
Ah, now I see what is the source of confusion. |
We could remodel it such that when you use such a variant or struct in a pattern it's matched as a variant, not a constant, and then disallow constants in irrefutable patterns. Sounds like it may require not insignificant refactoring. IOW, this seems to be a limitation imposed by the current implementation of pattern matching, and not a limitation of language design. |
Yes, but why discern between them? |
Because there the ambiguity makes sense -- you may indeed want to match on OTOH here there's no reason to do so, because it's going to error at a later stage anyway. The fact that the compiler errors early prevents it from falling back to a binding. There's no real ambiguity here, whereas there is in the |
From the point of view of how this is implemented the behavior seems logical, but from the typical pattern mental model the current behavior seems very surprising. |
Sounds great. There are so many traps with const-like things in patterns. bikeshed: const generics uses |
Nope! #[derive(PartialEq, Eq)]
struct S;
const C: S = S;
fn main() {
let C = S; // OK
} I thought about this issue more than once when (re)writing the pattern resolution code and in the end my position was that 1) in cases when it really matters and you can have conflicts with code you don't control (macros) the proper solution is macro hygiene 2) in all other cases it doesn't really matter so let's use the most simple and consistent possible rules (aka always disambiguate in favor of patterns everywhere). @scottmcm struct Array<U, const N> { ... }
type A = Array<U, N>; // OK without braces if N resolves to a value |
I'll note that in the example you give it makes no difference whatesoever if C resolved to the constant or a new binding, and it will continue to work the same way if this change is made 😄 |
@Manishearth
|
oh god
…On Thu, Apr 5, 2018, 11:27 AM Vadim Petrochenkov ***@***.***> wrote:
@Manishearth <https://github.com/Manishearth>
That's until S doesn't have a destructor 😄
#[derive(PartialEq, Eq)]
struct S;
const C: S = S;
impl Drop for S {
fn drop(&mut self) {
println!("BOOM");
}
}
fn main() {
println!("barrier 1");
let C = S;
println!("barrier 2");
let fresh = S;
println!("barrier 3");
}
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#49680 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABivSK0mrftSfHYH3yFq5QVshQ1XMjjlks5tlmIpgaJpZM4TH16v>
.
|
One more reason to keep the status quo rules is that refutability can potentially change in the future. |
Some points to consider:
That said, could somebody back up for a second and summarize the background here? That is, what are the issues I should be reading into? :) |
I'm not suggesting this -- variants and struct ctors are never ambiguous. The only things that are actually ambiguous are
I actually have a queued up blog post about this interesting rabbit-hole, otherwise I think #45050, #45050 (comment) , and #33118 (comment) affect this. |
I'm curious how many people regularly encounter this construct, that in Still, under what circumstances does it make sense to use a constant in such a pattern? As far as I can tell, any time you do that, you'll either get an error (in which case this just becomes "how do we give a clearer error?"), or you have a parameter whose type is an enum with one variant with no arguments, a name that matches that one variant or a constant containing it, and a non-Rustic naming convention for either the variant or the function parameter (in which case, why pass it around at all?). So, rather than trying to come up with a completely general solution like "let's ban constants in irrefutable patterns", could we just treat this as "in cases where we know we'll error out anyway, can we give a better error message for the common case"? Help people realize that they have a name conflict, and that that turns out to matter because of a language feature (patterns in function parameters) that they might not even know about (so the error message shouldn't assume they do). |
Right, that's my point -- constants are useless in irrefutable patterns because they will always error (except for when you have a unit typed constant as petrochenkov mentioned, though in this case it's basically irrelevant unless you care about destruction order).
We already ban constants in irrefutable patterns, it's just that the way we ban them also ends up blocking some useful syntax. Instead of banning them outright, we should treat these things as bindings. A better error message would be nice too, but I feel like we can reduce the number of error cases entirely here. |
To be clear: What I'm suggesting here is to make more things compile, not less -- it's not a breaking change except for the unit typed destructor case petrochenkov mentioned (and it's questionable if that's a breaking change at all) |
Oh, also, it occurred to me: even if we go through with this; we still have to deal with the fact that bindings can't shadow consts anyway (#33118 (comment)). This fix is akin to using const foo: u8 = 1;
let foo @ _ = 2; doesn't compile anyway because the binding shadows a constant. If we fix #33118 we have some chance of fixing this, but till then, closing. |
gives me a type error, because it resolves
bar
to the constant and then realizes it's the wrong type.Resolving
bar
to a constant isn't something that will ever work anyway, because if you write something likeit will move on to the "refutable pattern in function argument" error.
We should just not attempt constant resolution for irrefutable patterns.
This is technically a language change -- code that would previously not compile will now compile. cc @rust-lang/lang
The text was updated successfully, but these errors were encountered: