Skip to content

feat[next]: Add support for tuple comprehensions#2487

Open
SF-N wants to merge 85 commits into
GridTools:mainfrom
SF-N:tracer_support
Open

feat[next]: Add support for tuple comprehensions#2487
SF-N wants to merge 85 commits into
GridTools:mainfrom
SF-N:tracer_support

Conversation

@SF-N

@SF-N SF-N commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

Adds support for tuple comprehensions, e.g. for usage on tracers.

@gtx.field_operator
def testee(
    tracers: tuple[cases.IField, cases.IField], factor: int32
) -> tuple[cases.IField, cases.IField]:
    return tuple(tracer * factor for tracer in tracers)

Comment thread tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py Outdated
@tehrengruber tehrengruber changed the title feat[next]: Add support for tracers feat[next]: Add support for tuple comprehensions May 11, 2026
new_type = types[index]
case ts.VarArgType(element_type=element_type):
new_type = (
element_type # TODO: we only temporarily allow any index for vararg types

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 is for direct access to tracers[0] * factor, tracers[1] * factor, which I personally think is an anti pattern. I left it here until we take a decision on this. We could also make it an optional feature. One of the disadvantages is that it is not possible to fully type check the field operator at definition time, since the tuple length is only known at call / compile time. The user will then get an error in unroll_map_tuple.

@tehrengruber
tehrengruber marked this pull request as ready for review May 11, 2026 09:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds frontend + lowering support for tuple comprehensions written as tuple(<genexpr>), enabling mapped operations over tuple-typed inputs (including variadic tuple annotations) and lowering them through a new iterator builtin (map_tuple) that is later unrolled into explicit tuple element operations.

Changes:

  • Parse tuple(<generator expression>) into a dedicated FOAST node and pretty-print it.
  • Type-deduce tuple comprehensions (incl. variadic tuple annotations via VarArgType) and lower them to iterator IR using a new map_tuple builtin.
  • Add an iterator transform to unroll map_tuple calls, plus integration/unit tests for supported and unsupported cases.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/next_tests/unit_tests/ffront_tests/test_func_to_foast.py Adds negative tests for invalid tuple-comprehension forms.
tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py Adds execution tests covering fixed/variadic/nested tuple comprehensions.
tests/next_tests/integration_tests/cases.py Adds temporary allocation/size handling for VarArgType (currently fixed to length 3).
src/gt4py/next/type_system/type_translation.py Adds variadic/generic tuple hint handling and tuple constructor typing.
src/gt4py/next/type_system/type_specifications.py Introduces VarArgType to represent variadic tuples.
src/gt4py/next/type_system/type_info.py Extends concretization logic to account for VarArgType.
src/gt4py/next/iterator/type_system/type_synthesizer.py Adds type synthesizer for new map_tuple builtin.
src/gt4py/next/iterator/transforms/unroll_map_tuple.py New transform to unroll map_tuple into explicit tuple construction.
src/gt4py/next/iterator/transforms/pass_manager.py Wires UnrollMapTuple into iterator transform pipelines.
src/gt4py/next/iterator/builtins.py Registers map_tuple as an iterator builtin.
src/gt4py/next/ffront/past_passes/type_deduction.py Relaxes out= typing check to compatible types.
src/gt4py/next/ffront/func_to_foast.py Parses tuple(genexpr) into FOAST TupleComprehension.
src/gt4py/next/ffront/foast_to_past.py Uses concretizability check for out return type validation.
src/gt4py/next/ffront/foast_to_gtir.py Lowers tuple comprehensions to map_tuple(lambda)(iterable) calls, incl. unpacking targets.
src/gt4py/next/ffront/foast_pretty_printer.py Adds pretty-print support for tuple comprehensions.
src/gt4py/next/ffront/foast_passes/type_deduction.py Adds typing rules for TupleComprehension and vararg tuple indexing behavior.
src/gt4py/next/ffront/field_operator_ast.py Adds FOAST node types for tuple comprehensions and mapper structure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/gt4py/next/type_system/type_translation.py Outdated
Comment thread src/gt4py/next/ffront/func_to_foast.py
Comment thread src/gt4py/next/ffront/func_to_foast.py Outdated
Comment thread src/gt4py/next/ffront/func_to_foast.py Outdated
Comment thread src/gt4py/next/ffront/foast_passes/type_deduction.py
Comment thread src/gt4py/next/ffront/foast_passes/type_deduction.py Outdated
Comment thread src/gt4py/next/ffront/foast_passes/type_deduction.py Outdated
Comment thread src/gt4py/next/ffront/field_operator_ast.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated 3 comments.

Comment on lines 497 to +500
def _verify_builtin_type_constructor(self, node: ast.Call) -> None:
if len(node.args) > 0:
arg = node.args[0]
if not (
isinstance(arg, ast.Constant)
or (isinstance(arg, ast.UnaryOp) and isinstance(arg.operand, ast.Constant))
):
raise errors.DSLError(
self.get_location(node),
f"'{self._func_name(node)}()' only takes literal arguments.",
)
assert isinstance(node.func, ast.Name)
(arg,) = node.args
if not (
Comment on lines +31 to +37
if cpm.is_call_to(node.fun, "map_tuple"):
# TODO: we have to duplicate the function as domain inference only supports direct calls
f = node.fun.args[0]
tup = node.args[0]
itir_inference.reinfer(tup)
assert isinstance(tup.type, ts.TupleType)
tup_ref = next(self.uids["_ump"])
Comment on lines +457 to +460
case ts.VarArgType(element_type=element_type):
new_type = (
element_type # TODO: we only temporarily allow any index for vararg types
)
@SF-N
SF-N requested a review from tehrengruber July 20, 2026 15:25
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.

3 participants