-
Notifications
You must be signed in to change notification settings - Fork 199
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
Add enumerations (tagged unions) #988
Comments
@jfecher This seems like a good addition, along with the match syntax. The match syntax desugaring to if conditions could also be another separate issue that is orthogonal to this (it will be limited without enums) |
Something else to note about this proposal is that it still wouldn't allow us to write recursive types. For example we wouldn't be able to define a List: enum List<T> {
Empty,
Cons(T, List<T>),
}
// Translated as:
struct List<T> {
tag: Field, // 0 = Empty, 1 = Cons
empty_data: (),
cons_data: (T, List<T>), // oh, no infinite recursion in types is not allowed
} |
Lowering this to |
Proposed approach:
// T: IsDiscriminatable
#[repr(T)]
enum Foo {
// T0: ToFrom<T>
Case0(T0),
// T1: ToFrom<T>
Case1(T1),
..
}
trait IsDiscriminatable {
fn discriminant(&self) -> u8;
}
trait ToFrom<T> {
fn to_repr(self) -> T;
fn from_repr(x: T) -> Self;
} Summary:
Runtime match: match x {
Case0(y) => f(y),
..
} Becomes: if x.discriminant() == discriminant_of(Case0) {
f(ToFrom::from_repr(x)) // with some Case0 annotation
} else {
..
} Runtime construction: let y = Case0(x); Becomes: let y = x.to_repr(); // with some Case0 annotation |
I think the one thing we're missing is how to determine
We should probably go with a name more specific than |
It would be more accurate to say
Sounds good to me |
This is the part I think we're still missing. How should users specify this on their struct for example? |
Similarly to how they're specified in Rust here. In short: #[repr(u8)]
enum Enum {
Unit = 3,
// overlap is an error:
// Overlapping = 3,
Tuple(u16), // implicitly 4
Struct {
a: u8,
b: u16,
} = 10,
Large = 255,
TooBig, // implicitly 256, which overflows u8 and so is an error
} |
@michaeljklein ok, I think I misunderstood us wanting to allow this on structs as those structs wouldn't also have a separate |
Problem
It would be useful in Noir to support types like
Option
andResult
which hold different values based upon a tag value. Optional values in particular would be useful for future Noir contracts.Proposed solution
Add rust-style enumerations into noir, pattern matching and all.
The main concern is how to represent enumerations given we cannot reinterpret-cast data into another type. I propose representing an arbitrary enumeration:
As a struct:
Now, given a constructor call such as
Foo::B(my_b_data)
, the compiler can translate this into a struct initialization. There is the question of what to do for the fields of other variants like (), CData, and Other. Since these values would be guaranteed to be inaccessible by the compiler when the tag value is B, and since all values in Noir are comprised of Fields, we can initialize all these values to 0 without changing behavior:A concrete example
Option
in this scheme could be typed as:Which would be translated internally as:
Alternatives considered
As a slight variant of the above translation of
match
, we could consider an alternate translation that explicitly checks each tag and fails if an impossible case is somehow reached:Where
panic
would be defined as:Additional context
The actual translation of enums into structs could occur during monomorphisation since this would be the point all generic types become known and we could thus fill in default values for them. This would also be strictly after completeness checking for
match
expressions which would likely occur during type checking.The text was updated successfully, but these errors were encountered: