Skip to content

Add tuple unpacking syntax#23368

Merged
rikkimax merged 37 commits into
dlang:masterfrom
tgehr:unpacking
Jul 19, 2026
Merged

Add tuple unpacking syntax#23368
rikkimax merged 37 commits into
dlang:masterfrom
tgehr:unpacking

Conversation

@tgehr

@tgehr tgehr commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Implements DIP 1053, "Tuple Unpacking Syntax".
https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1053.md

Many thanks to @MetaLang and @ntrel for their essential help with pushing this over the finish line.

The PR includes a changelog entry and a spec update.

Note that the features in this PR are still gated behind the -preview=tuples flag. This is because of:
tgehr#18 (comment) (comment by @ntrel )

BTW if we remove -preview=tuples some existing tests will need fixing. I think I made the fixes in one PR before closing that and deciding to go with the flag instead. I'd say it might be worth merging it with the flag, and then make a separate PR to remove the flag, possibly after a release to get wider testing. Or we could see what upstream maintainers think.

I.e., enabling the parser changes causes error messages in some of the existing fail_compilation tests to change. If preferred, I think we can get the test suite to pass even when enabling unpacking syntax unconditionally, but it will require updating error messages in some of the tests. A more conservative approach would be to release with the flag first, to avoid disruption in case there is an undetected bug and it unexpectedly does break something in the wild. As a middle ground, we could also release with the flag on by default but still support -revert=tuples. (Which would still require updating the tests.)

I think assuming that the intention is to support either -preview=tuples or -revert=tuples in any release, this PR can be merged as-is, otherwise it might make sense to remove the flag first. (Though I would be happy to finally see this upstreamed in either case.)

@tgehr
tgehr requested a review from ibuclaw as a code owner July 6, 2026 01:15
Comment thread compiler/src/dmd/globals.d
@tgehr
tgehr force-pushed the unpacking branch 3 times, most recently from d4fbee2 to f9a0430 Compare July 6, 2026 01:51

@dkorpel dkorpel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad to see this progress!

but it will require updating error messages in some of the tests

Have you tried running ./run.d fail_compilation AUTO_UPDATE=1 to see how much changes?

Comment on lines +1019 to +1020
if (e && de.type && de.type.toBasetype().ty == Tvoid)
e.Ety = TYvoid;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes an ICE that happened in the backend when tuple unpacking operated on types with copy and move constructors.

See: tgehr#18

Comment thread compiler/src/dmd/attrib.d
return fail();
}

import dmd.expressionsem;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is not supposed to import semantic. I'm fine with merging it like this and refactoring later though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC some imports became necessary during rebase because a function we had already been using was moved during upstream refactorings.

Comment thread compiler/src/dmd/attrib.d Outdated
Comment thread compiler/src/dmd/lexer.d
Comment thread compiler/src/dmd/parse.d Outdated
@tgehr

tgehr commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Not sure why FreeBSD tests are suddenly failing.

  Test 'runnable/testfixups.c' failed. The logged output:
  /home/runner/work/dmd/dmd/generated/freebsd/release/64/dmd -conf= -m64 -Irunnable  -fPIC  -od/home/runner/work/dmd/dmd/compiler/test/test_results/runnable/c -of/home/runner/work/dmd/dmd/compiler/test/test_results/runnable/c/testfixups_0  runnable/testfixups.c 
  /home/runner/work/dmd/dmd/compiler/test/test_results/runnable/c/testfixups_0  --DRT-testmode=run-main
  Assertion failed: (tlsstatic == 6), function main, file runnable/testfixups.c, line 25.
  
  ==============================
  Test 'runnable/testfixups.c' failed: caught signal: -6

@Herringway

Copy link
Copy Markdown
Contributor

Not sure why FreeBSD tests are suddenly failing.

Not sure why either, but it seems to have started with #23374, which introduced that file.

tgehr and others added 22 commits July 13, 2026 19:07
…#7)

* Fix parsing tuple notation without `-preview=tuples`

After #5, without `-preview=tuples`, the parser would cause an assert
error when finding tokens that satisfy `isTupleNotation`.

* Fix parsing malformed auto declaration starting with `(`

Change preview check to an assert after last commit.
Handle a tuple declaration that doesn't have `=` after the last `)`. The
`peekPastParen(&token).value == TOK.assign` check is not needed because
the `parseInitializer` parameter is true so `check(TOK.assign)` does the
job and provides a good error message if missing.
Add test for malformed auto and non-auto tuple declarations.

* Remove unnecessary preview check
Add error for `out` parameters.
Ignore `auto ref` after parameter error to avoid unpack error.
Avoid lowering to `auto Type x =`, which causes a redundant `auto` error.
This uses the opening `(` position rather than the first component's.
Require semi-colon after TuplePattern = Initializer.
Although we could allow a list of multiple tuple pattern/init pairs,
let's simplify the grammar to:

```
VarDeclarations:
    ...
    TuplePattern = Initializer;

TuplePattern:
    `(` TuplePatternComponents `)`
```
Note AutoDeclaration will still support commas, e.g. `auto (x,) = tup, i
= 1;`.
Grammar changes since approved DIP:
AutoDeclaration allows interleaved tuple and non-tuple declarators.
VarDeclarations now only takes one TuplePattern.
Also change Initializer to AssignExpression (`= void` is not allowed).
@ibuclaw

ibuclaw commented Jul 14, 2026

Copy link
Copy Markdown
Member

@tgehr maybe I'm misremembering, wouldn't editions mean no more preview/revert flags?

In the compiler, the gate would be something like

FeatureState tupleUnpackingSyntax()
  => hasEdition(v2026) ? FeatureState.enabled : FeatureState.disabled;

See dscope.d for examples.

@rikkimax

Copy link
Copy Markdown
Contributor

@tgehr maybe I'm misremembering, wouldn't editions mean no more preview/revert flags?

You are.

Preview flags come first, then things get promoted to an edition or turned on by default, idk about revert that hasn't come up.

@tgehr

tgehr commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Indeed, I think ideally this will go into the default edition within one or two releases. It is not intended to break any existing code, though my understanding is that it does makes sense, as a rule, to be somewhat cautious as this is a completely new feature that does come with somewhat nontrivial parser changes. However, as one data point, OpenD has pulled tuple unpacking from my branch almost two years ago, in September 2024, and no problems of this kind have been reported since then. (It avoided the ICE related to move constructors because it did not pull move constructors, though that would not have been a regression.)

@rikkimax

rikkimax commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Are we good to merge?

@rikkimax

rikkimax commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Oh yeah FreeBSD 13.2 CI runner is gone, needs a rebase?

EDIT: branch protection needed to be removed for the dead CI runner. It is now removed.

@rikkimax
rikkimax merged commit e340322 into dlang:master Jul 19, 2026
41 checks passed
@nordlow

nordlow commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Awesome. Are there follow-up plans to add Python-style syntax for specifying tuples? Both as run-time values and compile-time AliasSeq values?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants