Skip to content

pyrefly has deficiencies in parsing functions with *args: *tuple[*Ts, Suffix] annotation. #4482

Description

@randolf-scholz

Describe the Bug

pyrefly could improve its *argsparsing when suffix elements are present. I want to donate a test case I created for python/mypy#20472 (though I think this PR is forever stuck in limbo due to its excessive size).

The test tries to call a function expecting a fixed positional prefix, a variable size tuple, and a fixed positional suffix. Currently only ty and pyright succeed on this test.

class P: ...
class V: ...
class S: ...

def f(
    a1: P, a2: P, /,                      # prefix
    *args: *tuple[*tuple[V, ...], S, S],  # unbounded + suffix
) -> None: pass

def test_good_cases1(
    p: P,
    v: tuple[V, ...],
    s: S,
) -> None:
    # check all possible bracketing combinations
    # there are 45 possible ways to parenthesize the arguments
    # (little Schroeder number, see https://oeis.org/A001003)
    f(p, p, *v, s, s)
    f(p, p, *v, *(s, s))
    f(p, p, *(*v, s), s)
    f(p, p, *(*v, s, s))
    f(p, p, *(*v, *(s, s)))
    f(p, p, *(*(*v, s), s))
    f(p, *(p, *v), s, s)
    f(p, *(p, *v), *(s, s))
    f(p, *(p, *v, s), s)
    f(p, *(p, *(*v, s)), s)
    f(p, *(*(p, *v), s), s)
    f(p, *(p, *v, s, s))
    f(p, *(p, *v, *(s, s)))
    f(p, *(p, *(*v, s), s))
    f(p, *(p, *(*v, s, s)))
    f(p, *(p, *(*v, *(s, s))))
    f(p, *(p, *(*(*v, s), s)))
    f(p, *(*(p, *v), s, s))
    f(p, *(*(p, *v), *(s, s)))
    f(p, *(*(p, *v, s), s))
    f(p, *(*(p, *(*v, s)), s))
    f(p, *(*(*(p, *v), s), s))
    f(*(p, p), *v, s, s)
    f(*(p, p), *v, *(s, s))
    f(*(p, p), *(*v, s), s)
    f(*(p, p), *(*v, s, s))
    f(*(p, p), *(*v, *(s, s)))
    f(*(p, p), *(*(*v, s), s))
    f(*(p, p, *v), s, s)
    f(*(p, *(p, *v)), s, s)
    f(*(*(p, p), *v), s, s)
    f(*(p, p, *v), *(s, s))
    f(*(p, *(p, *v)), *(s, s))
    f(*(*(p, p), *v), *(s, s))
    f(*(p, p, *v, s), s)
    f(*(p, p, *(*v, s)), s)
    f(*(p, *(p, *v), s), s)
    f(*(p, *(p, *v, s)), s)
    f(*(p, *(p, *(*v, s))), s)
    f(*(p, *(*(p, *v), s)), s)
    f(*(*(p, p), *v, s), s)
    f(*(*(p, p), *(*v, s)), s)
    f(*(*(p, p, *v), s), s)
    f(*(*(p, *(p, *v)), s), s)
    f(*(*(*(p, p), *v), s), s)

The trick to solving this is to always normalize all positional args given to a function into a "standard tuple" of the form

tuple[prefix_1, ...., prefix_n, *tuple[*Ts], suffix_1, ..., suffix_k]

and treat that as if only *args of this type were given.

Sandbox Link

https://pyrefly.org/sandbox/?project=v2.fVZdb5swFP0r1nhhLArJ1r3wtj8wRYrWl22qCHES1CZG2KRpq_73Hn8Atrk0IiH4cO69tq_vPXMl0x6VTcGWy2V_cO6Dp617ckmbuh1eF2yDtP9ubvmiz5Xwk2Cv-KG-WU6G5MdRzVSHY_nX3e4X2vx_FCNcuIHTXXaig7c9-8ZkdzD8McPcftpw9OwfjkLsH1AtuVy76BodlasXBQsd2WHEscXfOHETVp149ciQA6wRUtYonciosnrkSneVSpx3yBBX4yxDnXjLcbA5u_s5kp7LF8mUQLQtv-AVWb9y_aquAN0ZQwM_faqVAmNbnVrB97xll-680-1Acs5OSjWyyHPBa7kU7TH_tVqtV6sfSH1NP6TNguHKrngdFzGcpQaIkdRQvhIci8xyentT0DPpg5n5uerxyNuIEEE6kAjSIs7bFPT80UxqegNCTS9wSDO9RZsBB8MU7tuenc3U83QBSZwOe7qMMR6v5IAboNFu47wLkHhXR5DIvhj8jDmZrY9T-2RxKg3dKlhsCnrzIZlzCRybneKhZXqpqAMwINQBCNySTC8l5sDeMIX7tiM8TIpZkA473CAK9PdogkfbZL7ojp2qn6TtdAn7g4davQzCa-giEBrnEiLclN30VkBwWBUHpdTLAyuSDv--_DZvFezt9u4adCQPEraxA8x1WnQN6IpjB_kNr2ilCZT3WNl7ui7u_JLvRSXzgJHrAFl5LWsj6kNzTBg5I2GW1iV3JsrPtMEH

(Only applicable for extension issues) IDE Information

No response

Metadata

Metadata

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions