Add a rule that enum discriminants may not use generic parameters#2206
Add a rule that enum discriminants may not use generic parameters#2206traviscross merged 3 commits intorust-lang:masterfrom
Conversation
This is implemented in the compiler with the diagnostic [`ParamInEnumDiscriminant`](https://github.com/rust-lang/rust/blob/3b1b0ef4d80d3117924d91352c8b6ca528708b3c/compiler/rustc_resolve/src/errors.rs#L651-L661) and [`NoConstantGenericsReason::IsEnumDiscriminant`](https://github.com/rust-lang/rust/blob/3b1b0ef4d80d3117924d91352c8b6ca528708b3c/compiler/rustc_resolve/src/late.rs#L160-L168).
src/items/enumerations.md
Outdated
| ``` | ||
|
|
||
| r[items.enum.discriminant.restrictions.generics] | ||
| Explicit enum discriminants may not use generic parameters from the enclosing enum. |
There was a problem hiding this comment.
from the enclosing enum.
What about from anywhere else? Playground says that you also can't use from an enclosing item either
fn demo<const N: u32>() {
enum Foo {
Bar = N,
}
}though it does also have an unhelpful suggestion to
help: try introducing a local generic parameter here
|
2 | enum Foo<N> {
| +++
which then leads to
- same "can't use generic parameters from outer item" error
- with a new suggestion
help: try introducing a local generic parameter here
|
2 | enum Foo<N, N> {
| ++
- and also an error
type parameter `N` is never used
I suggest
| Explicit enum discriminants may not use generic parameters from the enclosing enum. | |
| Explicit enum discriminants may not use generic parameters. |
There was a problem hiding this comment.
The restriction that generic parameters are not in scope within items in a function body is covered by items.generics.syntax.scope.
The reason it uses the "enclosing enum" terminology is because generic parameters defined within the enum discriminant initializer may be used, as in:
enum E {
V1 = {
const fn f<T>(x: T) -> T { x }
f::<isize>(123)
}
}I didn't want to risk potential confusion around that.
There was a problem hiding this comment.
But the actual discriminant of f::<isize>(123) is not based on any generic parameter, just the invocation of a constant function that happens to be generic, same as
const fn f<T>(x: T) -> T { x }
enum E {
V1 = {
f::<isize>(123)
}
}what about
Explicit enum discriminants may not use generic parameters. Note that they may still invoke generic functions.
or something like that?
The rule we've been following is that we don't use example admonitions for examples that directly demonstrate the operation of a normative rule; we use them for examples that are more general or conceptual, e.g., "here are some ways that this construct might appear", generally as part of the introduction. So let's move the example that demonstrates this new rule out of an admonition. Let's also adjust the `ERROR` comments. We don't generally need to match what the compiler emits for these. When we have something interesting to point out, we can use the space for that. Here, there's probably not much to say that isn't already said in the rule, so let's just say `ERROR`.
The interesting thing about the example in the `items.enum...generics` rule is that it shows that the generic parameters from the enclosing enum can't appear anywhere within the initializer of the enum discriminant. We don't use "initializer" anywhere on this page yet, but it is the correct word to use here, so let's use it.
|
Looks good to me. Thanks. |
This is implemented in the compiler with the diagnostic
ParamInEnumDiscriminantandNoConstantGenericsReason::IsEnumDiscriminant.