Second draft: Sum Type by Struct
Richard (Rikki) Andrew Cattermole
richard at cattermole.co.nz
Wed Sep 9 10:32:59 UTC 2026
On 09/09/2026 10:16 PM, Nick Treleaven wrote:
> On Saturday, 5 September 2026 at 16:51:20 UTC, Meta wrote:
>> On Saturday, 5 September 2026 at 16:02:08 UTC, Nick Treleaven wrote:
>>> Not being able to use `return` in a match *expression* is
>>> understandable. Not having a match *statement* which can use `return`
>>> seems like a big omission IMO.
>>
>> You can have arms with return, break, continue, throw, etc. if you
>> allow their type to resolve to noreturn, and they would refer to the
>> innermost enclosing control flow construct (or otherwise it's an error
>> - match/switch expressions themselves cannot break out early).
>
> When `match` is used as a statement it is fine to `break` out of the
> `match`. Also, supporting statement arm matching is important even when
> `match` is an expression, otherwise you can't conditionally return in an
> arm:
>
> ```d
> E3 foo()
> {
> E4 result = e1.match {
> (T v) {
> statements;
> if (e2)
> return e3; // return from `foo`
> else
> break e4; // e4 is the result of this arm
> }
> // more cases
> }
> statements;
> }
> ```
>
>> It's basically saying "execution will not continue past this point, so
>> this expression does not need to have a value". This isn't in Rikki's
>> proposal, but it's perfectly sound from a type theory perspective. I
>> imagine in DMD it'd require the creating of a "DivergeExpression" AST
>> node or something.
>
> But would that allow arbitrary statements in a match arm?
>
> Rikki's DIP lowers to a chain of conditional expressions to avoid
> complicating/rewriting the backend. Presumably that is so a `match`
> expression works anywhere a normal expression works. But is that
> overkill? Is it good practice to write a `match` expression as a
> subexpression? I think usually it is not. A DIP could just support match
> expressions for the common statement cases:
>
> ```d
> T v = e.match { ... };
> return e.match { ... };
> ```
> So the AST for those could be `class MatchExpInitializer :
> ExpInitializer` and `class ReturnMatchStatement : ReturnStatement`.
> Those could have AST lowerings without touching the backend, yet contain
> statements in the match arms.
Backend doesn't need changing.
Glue code, and CTFE, are the cases I identified off the top of my head,
but I guarantee there are others.
Originally I had MatchExp recognized by them and evaluating it.
But then I did something smart... and gave DotVarExp a safe overlapped
access field to disable the overlapped error check.
This allows the feature to be self contained and not touching a thousand
different files.
Same reason with lowering to a struct, no unique TypeInfo or worrying
about meta-programming code out there.
However I am unsure if you understand the core issue here.
All the cases you showed as suggestions are still expressions. We cannot
go from an expression to a statement in the AST. This can be fixed, its
just a lot of work, and outside the scope of this DIP and implementation.
More information about the dip.development
mailing list