Description
What are our options?
- we teach name resolution (
rustc_resolve
) to hideenum
generic parameters from the discriminant expression- this effectively enshrines that we don't want the parameterization to happen
- I'm not sure this can be backwards-compatible with 2.
- we keep the current name resolution support but error if we can't evaluate to concrete values
- the concrete values are necessary to check, at the definition site, that discriminants don't overlap
- there are special-cases (only the first variant having an explicit discriminant, while the rest keep counting up) where we could check w/o knowing the values
- long-term we could let more examples compile via explicit
!=
bounds
- note that expressions that use generics can still evaluate to concrete values
- we could make this work w/o
#![feature(const_generics)]
(see examples below) by using the same approach as in typeck: always expose repeat countAnonConst
s' parent ingenerics_of
. #70452, asenum
s are in a similar situation that shouldn't cause query cycles - EDIT: opened typeck: always expose explicit enum discriminant
AnonConst
s' parent ingenerics_of
. #70825 for this
- the concrete values are necessary to check, at the definition site, that discriminants don't overlap
Examples of current behavior:
Note: #![feature(const_generics)]
is used below so that this special-case kicks in:
rust/src/librustc_typeck/collect.rs
Lines 1183 to 1185 in 62c6006
Also, note that the reason for the uniform current treatment (which doesn't consider enum
parameters as not in scope of discriminants), is because rustc_resolve
treats surrounding generics as being in scope of AnonConst
s, always - all the bugs later in compilation are due to the lack of lazy normalization (see #43408).
This ICEs currently (playground):
#![feature(const_generics)]
#[repr(usize)]
enum Foo<T> {
Zero = 0,
SizeOf = std::mem::size_of::<T>(),
}
with
error: internal compiler error: src/librustc/ty/mod.rs:2538: enum discriminant depends on generic arguments
--> src/lib.rs:6:14
|
6 | SizeOf = std::mem::size_of::<T>(),
| ^^^^^^^^^^^^^^^^^^^^^^^^
Same thing happens if a const
parameter is used instead of size_of::<T>()
.
If we choose option 2, this ICE will turn into a regular error.
EDIT: and this currently compiles on nightly (playground):
#![feature(const_generics, arbitrary_enum_discriminant)]
#[repr(usize)]
enum MyWeirdOption<T> {
None = 0,
Some(T) = std::mem::size_of::<*mut T>(),
}
And using *mut *mut T
instead of *mut T
would make it work even when T: Sized
isn't known.
(If not for the substitution failure, you could remove #![feature(const_generics)]
)
cc @rust-lang/compiler @rust-lang/lang