Conversation
DMD perf check
Breakdown — compile hello.d
Breakdown — compile Phobos+30.9 M instructions: frontend +27.1 M (+0.78%), codegen +3.8 M (+0.27%)
All measurements
6fb3305 vs merge-base fb655c9 · about these metrics |
| from.isFunction_Delegate_PtrToFunction() | ||
| ? MATCH.convert : MATCH.exact; | ||
| const isNullUnitVariant = from.toBasetype().ty == Tnull && | ||
| variant.payload.length == 0 && variant.ident == Identifier.idPool("None"); |
There was a problem hiding this comment.
Try to avoid comparing identifiers by string, chuck None into the table and do a pointer comparison instead.
| alias Parameters = Array!(Parameter); | ||
| alias Statements = Array!(Statement); | ||
| alias Catches = Array!(Catch); | ||
| inout(SwitchExp) isSwitchExp() { return op == EXP.switchExpression ? cast(typeof(return))this : null; } |
There was a problem hiding this comment.
That doesn't look like the right place for it.
|
Some of the implementation is certainly cleaner. It doesn't handle integer confusion, which is why I banned that. No handling of alias sequences and expansion into variants. Kinda important use case both in literature and in D code. You did not solve for the overlapped error. You support multiple values per variant, I assume that tuples will exist to define that into existance. It does not support by-ref, vs by-value this is a killer feature over library. It does not support chaining like it would via UFCS, this is a downgrade over library. It requires a lot of redundent tokens, you don't need case inside of the declaration, nor in switch expression. The extra combination of enum and union I very much dislike it. As we've learned from DIP1000 that is not a good thing. |
It's just vibe-coded LLM slop I banged out to show my vision for how such a feature would work.
I'm not completely sure what you're referring to. It will reject cases like: enum union Num
{
int,
long,
}
Num n = 0;Unless you disambiguate with a cast or literal syntax.
Ya, too complicated to implement for a POC, but it should be supported through .tupleof or something similar.
What's that?
The variants are "tuple-like", but currently don't have any relation to tuples. I don't think that's a necessity, but may be nice to have. The struct variants are really useful though.
Ya I'm not sure what to do about that because of the safety issues. Maybe with your fast DFA it'd be safe to support.
That feature is maybe a nice to have, but it's very easy to emulate with a switch expression inside a UFCS function and IMO doesn't add a whole lot.
Those are for readability/comprehensibility more than anything. It makes it more clear to the people reading and writing the code what's going on semantically, and I think that the case token before each variant might be necessary for disambiguation if you also wanna have member functions inside the body, but I may be misremembering. The case tokens in switch expressions are to match how you declare cases in the enum union body, and to make it more familiar for programmers who are used to the regular switch. But yeah they're unnecessary in terms of parsing.
I think it's good for signalling to the programmer what this construct does and how it works. It's like a union, but with an enumerated list of cases (and enums are traditionally used for the tag in a tagged union). Also note that Rust, Swift, C#, Zig and Odin all use the keywords enum and/or union (in Zig it's literally You could just as easily use |
Its an error for
I've got to go do that on my PR.
Booo functions, not analyzable! Not clean chaining of input ranges.
|
9a0a2c7 to
ff2d631
Compare
Add language-level tagged enum unions and switch-expression matching.\n\nFeatures:\n- Parse enum union declarations with named, tuple, record, alias, and bare-type variants.\n- Synthesize tagged storage, payload structs, variant factories, and destruction support.\n- Support implicit construction for unambiguous bare-type variants and reject duplicate or ambiguous cases.\n- Expand static foreach and static if enum-union cases in their correct semantic scope.\n- Add tuple and record pattern bindings, named/literal field checks, rest patterns, and guarded arms.\n- Diagnose non-union patterns, unmatched variants, invalid positional patterns, duplicate defaults, and the 256-variant limit.\n- Add frontend matrix-based usefulness checks for redundant arms, redundant defaults, guarded coverage, and exhaustiveness witnesses.\n- Add specification, runnable, compilable, and fail-compilation regression coverage.
Replace the obsolete record discard spelling with the supported syntax in the NetworkEvent example.
- add parser and AST support for enum union declarations, named/unit/record/bare variants, templates, static foreach, variant UDAs, and struct-equivalent declaration attributes - synthesize tagged storage, named factories, bare-variant constructors, and lifecycle support for payloads - add implicit bare-variant conversion with ambiguity diagnostics and preserve enum-union non-callability - implement enum-union switch expressions with positional, record, type, rest, guard, default, redundancy, and exhaustiveness handling - diagnose malformed switch patterns, duplicate cases, unknown bare types, oversized unions, and invalid variant declarations - prevent user constructors from reading this before whole-value initialization, with branch-aware constructor flow tracking - eliminate duplicate complex and imaginary transition deprecations from generated constructor parameters - document enum union grammar, construction, pattern matching, member declarations, and limitations - add runnable, compilable, and fail-compilation coverage for syntax, conversion, constructors, UDAs, attributes, diagnostics, patterns, and lifecycle behavior
Add enum-union pattern matching and construction refinements: - resolve bare and qualified type patterns, including identifier bindings - support payload bindings for named variants and share unit payload storage - diagnose self aliases, unknown bare types, no-argument constructors, and ambiguous bare conversions - resolve property-valued switch conditions and improve switch-expression formatting - allow arrow-arm switch expressions in statement position and diagnose discarded no-effect switches - preserve parser recovery for malformed switch expressions - add focused compile, fail, and runnable regression coverage
Add compile-time reflection support for enum unions: - recognize is(T == enum union) - add allVariants, getTag, and variantConstructorParams traits - preserve identifiers and UDAs for reflected variants Model record and named alias variants as real nested declarations: - synthesize nested struct declarations for record variants - synthesize nested aliases for named type variants - preserve explicit alias variant construction and record conversion Improve conversion behavior and coverage: - rank implicit candidates by MATCH quality - prefer exact bool and other payload matches over weaker numeric conversions - retain diagnostics for genuinely ambiguous conversions - cover unit-variant separation from unrelated empty structs Add enum union attribute, deprecation, conversion, reflection, and alias tests, and document the nested declaration lowering.
Add __traits(variantKind, V) for elements returned by allVariants. Classify variants by declaration form: - unit for zero-parameter named variants - tuple for positional named variants - struct for inline record variants - alias for named type aliases - bare for bare payload types, including externally declared structs Document the reflection API and add positive coverage for every kind plus invalid input.
- decisiontree: format witness pattern correctly for unnamed/bare variants (e.g. typeof(null)) - expressionsem: disallow direct struct literal construction of enum union types, requiring a variant instead - expressionsem: support unqualified enum union alias variant lookup inside with-statement scopes - parse: improve error recovery in parseDeclDefs and enum union variant parsing to avoid cascading errors - tests: update runnable/testenumunion.d and add test cases for direct construction, alias variant with-scopes, null variant witnesses, and parse recovery
…, and test updates - parse: implement balanced curly brace tracking in parseDeclDefs error recovery so top-level declarations don't trigger spurious 'unmatched closing brace' - parse: properly consume tokens up to matching closing brace upon switch expression arm error - expressionsem: avoid speculative gagged expressionSemantic on dot.e1 in visit(CallExp) which swallowed diagnostics and caused ICE in test19790 / duplicate symbols in test11 - dsymbolsem: do not synthesize duplicate nested declarations for duplicate enum union variants to avoid cascading conflict errors - unit tests: add enumUnion to ignoreTokens in location_offset.d - runnable tests: replace deprecated cdouble and idouble in testenumunion.d with float and real - fail tests: update TEST_OUTPUT for enum_union_const_mutation, enum_union_legacy_template_payload, enum_union_switch_expression_statement, and enum_union_unit_pattern_post_call_binding
e740f3d to
1621ba8
Compare
…ery, and test outputs - expressionsem: implement findEnumUnionFromExp to resolve template instances, scope exps, and qualified identifiers during alias variant construction - parse: restrict Lerror curly recovery to inEnumUnion bodies so standard top-level and struct declarations retain upstream error recovery - parse: only bypass token advance on missing semicolon when expression statement is a switch expression - runnable: remove obsolete cdouble/idouble deprecation TEST_OUTPUT block from testenumunion.d - fail tests: align expected error line numbers in enum_union_legacy_template_payload, enum_union_switch_expression_statement, and enum_union_unit_pattern_post_call_binding
Stop enum union member synthesis after duplicate case diagnostics to avoid duplicate-symbol cascades. Refresh stale diagnostics and deprecation locations in the feature tests, and add the reviewed correctness and switch-lowering implementation plans.
Lower source-level __tag reads to discriminant rvalues while retaining direct backing-storage access for generated compiler code. Exclude the backing tag from tupleof and preserve the public reflection surface. Cover qualified reads, rejected mutation and address-taking, member reflection, tuple filtering, and generated interface round trips.
Centralize factory and implicit-conversion initialization around a staged payload construction. Keep incomplete union temporaries non-destructible and commit the discriminant only after the payload is fully constructed. Exercise payload copy construction, enum union copies, and throwing construction for named and bare variants.
Treat positional and record payload identifiers as fresh bindings and reject literal, call, operator, and other value expressions with a guard-oriented diagnostic. Remove synthesized payload equality checks from switch lowering and usefulness rows. Make generated bindings CTFE-capable, cache manifest switch conditions, and cover guard-based tests across scalar, aggregate, reference, and custom equality payloads.
Keep the usefulness and literal-pattern machinery available for future full pattern matching while current binding-only enum union patterns contribute wildcard payload columns. Insert source default arms as wildcard matrix rows so every later arm is diagnosed as unreachable, and document the retained architecture in the hardening plan.
Parse nested positional and record tuple bindings as UnpackDeclaration nodes without coupling switch patterns to the tuples preview flag. Feed selected payload fields through ordinary unpack semantic lowering and preserve binding order for guards and actions. Print recursive tuple shapes in generated interfaces and cover nested bindings, qualifiers, single condition evaluation, alias-this tuples, arity diagnostics, value-pattern rejection, and header round trips.
Inspect arguments to generated enum union factories instead of treating the entire call as effect-free. Retain the source switch condition across semantic caching and include guard, action, and binding initializer sources in discarded-value checks. Ignore trivial generated declaration and construction scaffolding while preserving real calls and copy-constructor effects, with once-only runtime coverage.
This PR adds language-level support for Rust/Swift-style tagged unions (called
enum union), and dedicated syntax for matching on their variants in the form of switch expressions.I wasn't satisfied with @rikkimax's approach in #23540, which is more in line with the structural approach taken by ML/Haskell, so I decided to implement it myself. And by myself, I mean an LLM - I wrote the spec, but it wrote all of the code and tests, and it was pretty quick and dirty. Consequently and unsurprisingly, most of the test runners are failing.
See enum_union_guide.md for an explanation of how the features work.
Included
@xoxorwr @limepoutine @Herringway