Skip to content

[next]: Length consistency of variable-length tuple arguments and 'out' is not checked #2903

Description

@tehrengruber

Problem

With variable-length tuple parameters (#2833), no toolchain stage validates that the concrete lengths of the arguments and the out argument are mutually consistent, so mismatches surface as internal errors instead of diagnostics.

The PAST-level out check uses type_info.is_compatible_type / is_concretizable, and is_concretizable(VarArg[T], TupleType) deliberately ignores length; the operator's VarArg[...] return type is also never specialized against the concrete call-site argument lengths.

Examples

Calling a tuple[IField, ...] -> tuple[IField, ...] operator with a 3-element input and a 2-element out passes type checking; embedded execution then dies with a bare AssertionError inside utils.tree_map, and the roundtrip backend with the opaque ValueError: 'target_domain' cannot be 'NEVER' unless allow_uninferred=True from domain inference.

A fundamentally ambiguous variant — the return length depends on a runtime value, so no single length can be consistent with out:

@gtx.field_operator
def testee(a: tuple[IField, ...], b: tuple[IField, ...], c: bool) -> tuple[IField, ...]:
    return a if c else b

testee(two_fields, three_fields, c, out=two_fields_out)  # accepted, crashes later

Direction

Proper error handling means specializing the VarArg return type against the concrete argument lengths when they become known (e.g. in with_args), yielding a located diagnostic for the plain mismatch. The ambiguous conditional-return case above should then be disallowed outright — the two branch lengths cannot be unified. The workaround for users is a dedicated field operator per branch, each with a single consistent length.

Note foast_to_past.py uses a different predicate (is_concretizable) than the PAST type deduction (is_compatible_type) for the same conceptual check; the fix should unify them.

Current state

test_var_len_tuple_length_mismatch_rejected in test_tuples.py (on the #2833 branch) pins the ambiguous example as xfail(strict=True), asserting the desired DSLError; it starts passing once the check exists.


Disclaimer: This issue was written largely with the help of AI.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions