pyrefly icon indicating copy to clipboard operation
pyrefly copied to clipboard

Unpacked TypeVarTuple in callable doesn't consider optional arguments

Open yangdanny97 opened this issue 4 months ago • 2 comments

Describe the Bug

from typing import *

def test[*Ts, T](f: Callable[[*Ts], T], *args: *Ts): pass
def callback(x: int, y: int = 1): pass

test(callback, 1) # error?
test(callback, 1, 1) # ok

It seems like *Ts gets eagerly resolved to tuple[int, int] as if every argument was required. But I think we should only do that if it's un-solved by the end of the call. In this case, the args provided in the first call is valid when considering optional params.

Sandbox Link

https://pyrefly.org/sandbox/?project=N4IgZglgNgpgziAXKOBDAdgEwEYHsAeAdAA4CeS4ATrgLYAEALqcROgOZ0Q3G6UN0AqADroRmGGEbwGAbQEAVOABo68gLoAKMIjoBhVFCipssGXMVqV6lQNSU2cHQrgBKHcVRw4YiXQDGBlDYqH4A1hr4OqwMKqRR6PwAvHQAjG50Hl4iIgzSGgGGwWEqaXQAxHQwlNSUAPw5eQVBIaElJS7ldLihIEogZJQSUKSEDLRQFBUACqSDYMN0aFh4%2BP646JBsAK6UqAwQ64QiFQDKMDB0ABYMDMSOAPT3A0MjvGz3MOj3mLh%2BcPd%2BdabHZ7A5fOhgXh0VAAN1Q0GMsDWGwg212%2B3WXWIGPQcCO6DIDEu6wAtDCqnAwXRkkIQABmQgpABMtJEIAAvn0QvtyQAxaAwChLHAEEjkdlAA

(Only applicable for extension issues) IDE Information

No response

yangdanny97 avatar Oct 08 '25 22:10 yangdanny97

https://github.com/facebook/pyrefly/issues/1469 is a similar issue for ParamSpecs

I think the representation of TypeVarTuple somehow needs to encode a requiredness, otherwise we'll have to make a union of each possible length of tuple.

yangdanny97 avatar Nov 21 '25 22:11 yangdanny97

Pyright seems to consider the argument requiredness if the function and arguments are passed in together, which successfully handles the original example

https://pyright-play.net/?strict=true&code=GYJw9gtgBALgngBwJYDsDmUkQWEMoBUAUEQCYCmws5AzjANoEAqNANFEwLoAUwAXFADCAQwA2o4QCNR5eoxad2XdgWEg0NAcxoBKKAFoAfLACuCGfJqc%2BRKHaghhSGuSgBRAB4BjcghhIwFG49MkooLzFRSWEvAGtuDwFUGHY4JJR8AF4oAEYdAQRhGhoSEHIAN3IxAH14BHJuGFoYbgjxaLj2PL0AYihyEHAQAH4iMsqauoamulbIjtiurp1eqDBYoA

but if just the function is passed in, it also makes the optional params required

https://pyright-play.net/?strict=true&code=GYJw9gtgBALgngBwJYDsDmUkQWEMoBUAUEQCYCmwmpA2gQCoDOAugBQAeAXFAMICGAGwF8ARgPI06TZgBooAOTApyzAJRQAtAD5%2BQ0eMkMWcxcuaciUK1BDkYAVxAoo7EhSrAwYDt1Qw5cL4o%2BAC8UABM6toKSuQW1lAIfIyMJMAo4VBhSKSsnmCqROnhrACMhcVlcpFAA

So maybe this is just another case of #105

yangdanny97 avatar Nov 26 '25 20:11 yangdanny97