In our CIR we currently have this... which I think isn't quite right.
/// A declaration of a new type - whether an alias or a new nominal nominal type
///
/// Only valid at the top level of a module
s_type_decl: struct {
header: CIR.TypeHeader.Idx,
anno: CIR.TypeAnno.Idx,
where: ?CIR.WhereClause.Span,
region: Region,
},
In my understanding both Foo : ...
and Foo := ...
are statements. They are both type declarations. One is an Alias Type delcaration, and the other is a Nominal Type declaration.
I could imagine a future where people default to refer to these as;
I'm wondering, how should we represent the nominal types in our CIR? Currently I think the s_type_decl
is being used for Aliases because that is all we have implemented so far. Should we make another separate variant to distinguish between these two, or maybe a flag is_alias
or similar in this variant?
that's how we do it in the Rust version of the compiler but I'm not thrilled with how it has worked out
I'd rather we just had .s_alias_decl
and .s_nominal_decl
or something like that
This is somewhat related, but can nominal tag union be open/extensible? In particular, are these allowed?
Color := [Red, Green, Blue]*
Color other := [Red, Green, Blue]other
OtherColor : [Purple]
Color := [Red, Green, Blue]OtherColor
I didn't think that was permitted
Maybe it would be useful though. I really dont know
I think this would be allowed:
Color other := [Red, Green, Blue]other
OtherColor : [Purple]
MixedColor : Color(OtherColor)
At least I see no reason it wouldn't be allowed off the top of my head....but I may be missing something
I'm not arguing for or against!
When checking types of nominal tag unions, if the above examples are not allowed, then we can really easily check if a tag (eg Blue
or Yellow
) is a member of the closed tag set and raise a diagnostic in Can if not. But if the above is allowed, then we have to check the tag membership in type-checking (so we can fully expand any extensible types)
This on the other hand:
Color := [Red, Green, Blue]*
Would just be equivalent to:
Color := [Red, Green, Blue]
no, nominal tag unions can't be extended
this is actually very important!
if we allow them to be extensible, then they don't solve https://github.com/roc-lang/rfcs/pull/1 and we have that problem again
Ooo okay, good to know.
we could allow some special syntax sugar for them, that's just sort of like "let me copy and paste that for you" e.g.
Color := [Red, Green, Blue, ..OtherColor]
OtherColor : [Purple]
That will make validating nominal tags easier then!
but ..a
would need to be disallowed
extension variables in nominal tag unions must be compile errors
Cool. Can nominal records be extensible?
also no
How is
OtherColor : [Purple]
Color := [Red, Green, Blue, ..OtherColor]
Different from:
OtherColor : [Purple]
AbstractColor(a) := [Red, Green, Blue, ..a]
Color : AbstractColor(OtherColor)
the problem is allowing the type variable:
AbstractColor(a) := [Red, Green, Blue, ..a]
now you can write functions where the type's layout at runtime varies based on the arguments you pass to that function
Are we permitting nominal records? I thought the intent was just Tags for now
Or maybe that was only specifically recursive types must be tags.
Richard Feldman said:
the problem is allowing the type variable:
AbstractColor(a) := [Red, Green, Blue, ..a]
now you can write functions where the type's layout at runtime varies based on the arguments you pass to that function
Ah yeah, I guess it essential makes the extension types not nominal which kinda defeats the whole point of making the type nominal in the first place.
Last updated: Jul 06 2025 at 12:14 UTC