Stream: compiler development

Topic: nominal type declaration statements - how to represent?


view this post on Zulip Luke Boswell (Jul 04 2025 at 00:36):

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;

  1. Nominal Type Declaration becomes "that's a Type declaration"
  2. Alias Type Declaration becomes "that's a Alias declaration"

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?

view this post on Zulip Richard Feldman (Jul 04 2025 at 00:47):

that's how we do it in the Rust version of the compiler but I'm not thrilled with how it has worked out

view this post on Zulip Richard Feldman (Jul 04 2025 at 00:47):

I'd rather we just had .s_alias_decl and .s_nominal_decl or something like that

view this post on Zulip Jared Ramirez (Jul 05 2025 at 22:49):

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

view this post on Zulip Luke Boswell (Jul 05 2025 at 23:39):

I didn't think that was permitted

view this post on Zulip Luke Boswell (Jul 05 2025 at 23:39):

Maybe it would be useful though. I really dont know

view this post on Zulip Brendan Hansknecht (Jul 05 2025 at 23:44):

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

view this post on Zulip Jared Ramirez (Jul 05 2025 at 23:44):

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)

view this post on Zulip Brendan Hansknecht (Jul 05 2025 at 23:45):

This on the other hand:

Color := [Red, Green, Blue]*

Would just be equivalent to:

Color := [Red, Green, Blue]

view this post on Zulip Richard Feldman (Jul 06 2025 at 01:07):

no, nominal tag unions can't be extended

view this post on Zulip Richard Feldman (Jul 06 2025 at 01:07):

this is actually very important!

view this post on Zulip Richard Feldman (Jul 06 2025 at 01:07):

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

view this post on Zulip Jared Ramirez (Jul 06 2025 at 01:11):

Ooo okay, good to know.

view this post on Zulip Richard Feldman (Jul 06 2025 at 01:11):

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]

view this post on Zulip Jared Ramirez (Jul 06 2025 at 01:11):

That will make validating nominal tags easier then!

view this post on Zulip Richard Feldman (Jul 06 2025 at 01:11):

but ..a would need to be disallowed

view this post on Zulip Richard Feldman (Jul 06 2025 at 01:12):

extension variables in nominal tag unions must be compile errors

view this post on Zulip Jared Ramirez (Jul 06 2025 at 01:14):

Cool. Can nominal records be extensible?

view this post on Zulip Richard Feldman (Jul 06 2025 at 01:16):

also no

view this post on Zulip Brendan Hansknecht (Jul 06 2025 at 01:59):

How is

OtherColor : [Purple]
Color := [Red, Green, Blue, ..OtherColor]

Different from:

OtherColor : [Purple]
AbstractColor(a) := [Red, Green, Blue, ..a]

Color : AbstractColor(OtherColor)

view this post on Zulip Richard Feldman (Jul 06 2025 at 02:00):

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

view this post on Zulip Luke Boswell (Jul 06 2025 at 03:56):

Are we permitting nominal records? I thought the intent was just Tags for now

view this post on Zulip Luke Boswell (Jul 06 2025 at 04:02):

Or maybe that was only specifically recursive types must be tags.

view this post on Zulip Brendan Hansknecht (Jul 06 2025 at 04:51):

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