Change:
This compiles: But this doesn't: That error message doesn't seem to make sense, but that may be because it's just confused - I also get this error message in other circumstances, and I don't understand what the difference is:
It seems like the constant checker believes that is a constant, whereas the constant evaluator does not. They should agree. I'm not sure which behavior is right. Also, it seems counter-intuitive that you can't refer to a constant () in other constants. Nominating for milestone 1, welll-defined.
Works now. Fixed by (possibly; at the very least, it includes a testcase).
This doesn't seem to work now. $ x8664-apple-darwin/stage2/bin/rust run 10:52 error: expected constant expr for vector length: Non-constant path in constant expr let thecategories: [Category, ..NUMCATEGORIES] = [A, B, C];
I'm doubtful that the earlier testcase ever worked; explicitly calls out in the commit message that C style enums don't work in type signatures, only values.
Part of ; inherits its maturity milestone implicitly.
Just for the record, having integral enum constant support in type signatures is a complicated problem, since we end up needing to differentiate between types that can be checked without constant evaluation and types that require constant evaluation before they can be checked. Interleaving these two things looked exceedingly awkward when I attempted to tackle this before, hence why I punted on it.
triage bump. The original example seems to work now: This still fails, here's an updated example:
I don't think the latter example (that attempts to const-eval should work anyway; I believe our policy has been that we reserve the right to change enum encoding if not otherwise provided a la C-style enums, so it would be ... risky at best to support the code as written. (I do admit, it is a useful coding pattern. Though perhaps I might be able to whip up a macro that expands into the C-style enum. I will try to remember to try that tomorrow morning.)
I consider the last case to be an anti-pattern in Rust. It creates an entry in the enum that doesn't exist and fouls up match statements. If we want to support this (which perhaps we should), we ought to add some way to get the number of variants in an enum for a constant -- but not by adding a fictitious entry to the enum.
+1 for getting the number of variants in an enum
Visiting for triage Updated the example to compile with the latest Rust Can confirm it still doesn't compile
So, just to review the situation, and repeat what and I stated earlier: original bug from the description has been fixed. Namely, these two programs both run: First program: Second program: is another program from that does not work, but I do not think it was ever part of Rust's design that it would work as written: This is the case where you get the following error: Footnote 1: both and think the last program above is using an anti-pattern; that is, it is not idiomatic Rust to encode meta-information like "the number of enum variants" as a member itself of the enum. (We may extend the language in the future with some sort of associated constant that provides such information, but that is not part of the current design.) Footnote 2: there is a straight-forward workaround, if one wants to insist on using the anti-pattern: Put an explicit value in for the variant: Note also that the Rust compiler will catch if you put too low a value in for `NumCategories above, as long as you have not assigned "out-of-band" values to the earlier variants. In other words, this code will fail to compile: This yields the compile-time error: (I suspect there may even be a straight-forward macro one could write that creates a static array of all the values, to ensure that the provided number is also not too large. Demonstrated here: Though such a macro would benefit from extensions like for counting.)
I think we should close this ticket. Nominating for closure.
(closing)
Let me get this straight. Rust doesn't allow using c-like enum variants in compile-time evaluation contexts in general, unless the user opts-in to this workaround you've pointed out. Library writers don't know which ones of their public c-like enum variants might be needed to be used as compile-time constants, so they'd have to explicitly specify the values for each variant. To me this is clearly a compiler bug, and as far as I can tell, you refuse to fix it just because the person reporting it happened to be using an anti-pattern in .
It's backwards compatible to add implicit const ordinals, no? Likewise for a way to get const number of variants.
compiler bug != language feature At one point I had a further notes here trying to further explain the above, but I think the comment thread is essentially self-explanatory, apart from one detail: I believe the phrase "C-like enum variant" is meant to refer to variants that have been given an explicit value. The example that we have been calling an anti-pattern does not use any explicit values in the variants; therefore I do not think it qualifies as a C-like enum variant.
I might be wrong on this point; I will check more carefully when I am in front of a computer again
claims the following: From that quote I gather, that given the , Rust guarantees that and . If Rust can make those guarantees in its reference manual now, then why can't it make the same guarantees at compile-time? You say that it's a language feature that these unassigned nullary enum variants (which belong to an enum whose all variants are nullary) aren't compile-time constants. What is the language design reasoning behind this feature?
I was not attempting to claim that it was a language feature that these aren't compile-time constants. (I do concede that my earlier response can be interpreted that way.) I was trying to claim that changing the current language to treat them as compile-time constants would be a language feature, and thus should go through the RFC process. (After all, a ticket like this really isn't the appropriate venue to debate the value of such a change.) Here's the essence of what I was thinking when I wrote that response: I have been long under the impression that we were reserving the right to change how discriminant values are assigned by the compiler if not explicitly assigned by programmer. (Of course actually allowing such a change would probably require restricting the current language; i.e. when would need to be outlawed during dynamic execution in addition to it being disallowed at compile time. And I imagine we could not do that unless we simultaneously accepted and probably provided a stable API to that RFC as well.) Its quite possible that my mental model of what we were planning to permit in the future was simply over-aggressive; i.e. that no one else on the team was planning on ever changing the assignment of discriminant values, at least not for enum variants that do not have a data payload attached.
reopening and putting on agenda for next meeting; this deserves discussion at the team meeting, if only to get clarification about what guarantees we plan with respect to discriminant value assignment.
Thank you for getting this thing to get sorted out and for clearing up my earlier confusion.
Hmm, I tend to agree with that it should work for both explicitly assigned and unassigned values, if it works at all.
(I didn't fully appreciate when commenting before that it worked only in one case and not the other.)
So after discussing with i concluded that my mental model is simply wrong, and that there is not sufficient value in trying to future-proof our future discriminant value assignment. In particular pointed out to me multiple times that the chosen discriminant value need not be directly represented as the numeric value chosen; thus various tricks I was anticipating (usually revolving around ensuring that e.g. bit patterns are non-zero) should be able to be adopted in the future. Anyway, the bugs been reopened; we should fix this, for consistency's sake.
triage: P-high (In some sense this is a feature request, or at least a request for consistently deploying a particular feature. Fixing this may be important when/if comes, but its hard to tell right now.)
Decided to file a fresh issue, , to ease triage. (I.e. right now the main item left on this bug is hard to actually extract from the thread of conversation as presented.)

Discussion:
expr_cast(base, _) => { let ety = ty::expr_ty(tcx, e); let base = eval_const_expr_partial(tcx, base); <del> match ty::get(ety).sty { ty::ty_float(_) => { match base { Ok(const_uint(u)) => Ok(const_float(u as f64)), Ok(const_int(i)) => Ok(const_float(i as f64)), Ok(const_float(_)) => base, _ => Err(~"Can't cast float to str") } } ty::ty_uint(_) => { match base { Ok(const_uint(_)) => base, Ok(const_int(i)) => Ok(const_uint(i as u64)), Ok(const_float(f)) => Ok(const_uint(f as u64)), _ => Err(~"Can't cast str to uint") } } ty::ty_int(_) | ty::ty_bool => { match base { Ok(const_uint(u)) => Ok(const_int(u as i64)), Ok(const_int(_)) => base, Ok(const_float(f)) => Ok(const_int(f as i64)), _ => Err(~"Can't cast str to int") </del> <ins> match /*bad*/copy base { Err(_) => base, Ok(val) => { match ty::get(ety).sty { ty::ty_float(_) => match val { const_uint(u) => Ok(const_float(u as f64)), const_int(i) => Ok(const_float(i as f64)), const_float(_) => base, _ => Err(~"Can't cast float to str"), }, ty::ty_uint(_) => match val { const_uint(_) => base, const_int(i) => Ok(const_uint(i as u64)), const_float(f) => Ok(const_uint(f as u64)), _ => Err(~"Can't cast str to uint"), }, ty::ty_int(_) | ty::ty_bool => match val { const_uint(u) => Ok(const_int(u as i64)), const_int(_) => base, const_float(f) => Ok(const_int(f as i64)), _ => Err(~"Can't cast str to int"), }, _ => Err(~"Can't cast this type") } </ins> } <del> } _ => Err(~"Can't cast this type") </del> } } expr_path(_) => {