Skip to content

parameter specification/type variable tuple variance#2215

Open
KotlinIsland wants to merge 3 commits intopython:mainfrom
KotlinIsland:paramspec-variance
Open

parameter specification/type variable tuple variance#2215
KotlinIsland wants to merge 3 commits intopython:mainfrom
KotlinIsland:paramspec-variance

Conversation

@KotlinIsland
Copy link
Copy Markdown
Contributor

@KotlinIsland KotlinIsland commented Mar 9, 2026

@KotlinIsland KotlinIsland force-pushed the paramspec-variance branch 3 times, most recently from 5f8e0cc to d9d82c9 Compare March 9, 2026 03:13
@srittau srittau added the topic: typing spec For improving the typing spec label Mar 9, 2026
@KotlinIsland KotlinIsland force-pushed the paramspec-variance branch 2 times, most recently from 81ba400 to 54ad5e1 Compare April 1, 2026 07:59
Copy link
Copy Markdown
Member

@JelleZijlstra JelleZijlstra left a comment

Choose a reason for hiding this comment

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

I like adding this if we can get it specified nicely, but this PR is not ready; the proposed test is incorrect.

Also, https://typing.python.org/en/latest/spec/generics.html#paramspec-variables still says variance on ParamSpec is unsupported; this should be updated.

I'd also like to see an implementation in at least one type checker, even if only as a draft PR, so we can be confident this is something that can be feasibly implemented.

Comment thread conformance/tests/generics_paramspec_semantics.py Outdated
Comment thread conformance/tests/generics_paramspec_semantics.py Outdated
@davidhalter
Copy link
Copy Markdown
Collaborator

I personally would also like to see tests added for param spec variance inference, since that would probably need to be supported as well.

@JelleZijlstra
Copy link
Copy Markdown
Member

The test cases do have variance inference, though as I noted some of the cases are wrong. But it would probably be useful to have a few more cases, and I'd recommend putting the tests for paramspec variance in their own file so we can track type checker support more precisely.

@KotlinIsland
Copy link
Copy Markdown
Contributor Author

KotlinIsland commented Apr 3, 2026

I'd also like to see an implementation in at least one type checker

I have wip support in PyCharm, but I could also add it to basedpyright

it was very straightforward to implement

@davidhalter
Copy link
Copy Markdown
Collaborator

davidhalter commented Apr 3, 2026

The test cases do have variance inference, though as I noted some of the cases are wrong. But it would probably be useful to have a few more cases, and I'd recommend putting the tests for paramspec variance in their own file so we can track type checker support more precisely.

Oh right, sorry I didn't see them, because I thought they would be in a different file. I'm also very much +1 on putting those tests into a different file (for example generics_paramspec_variance.py).

@KotlinIsland KotlinIsland force-pushed the paramspec-variance branch 2 times, most recently from 8f30004 to 117964e Compare April 7, 2026 01:29
@KotlinIsland KotlinIsland changed the title parameter specification variance parameter specification/type variable tuple variance Apr 7, 2026
@KotlinIsland
Copy link
Copy Markdown
Contributor Author

support has landed in pycharm and cpython

@JelleZijlstra
Copy link
Copy Markdown
Member

https://typing.python.org/en/latest/spec/generics.html#paramspec-variables stills says that we don't support variance in ParamSpec, that should be fixed in this PR.

@JelleZijlstra
Copy link
Copy Markdown
Member

Also can you open an issue on python/typing-council asking for a formal pronouncement?

@KotlinIsland
Copy link
Copy Markdown
Contributor Author

python/typing-council#59

@JelleZijlstra
Copy link
Copy Markdown
Member

Noticed some more issues:

  • generics_typevartuple_basic.py still has a line Ts1 = TypeVarTuple("Ts1", covariant=True) # E. But of course that's legal now. I'd delete the line and leave all variance testing to the new file generics_typevartuple_variance.py.
  • The description of the variance inference algorithm says "In the upper specialized class, specialize the target type parameter with an object instance". But that doesn't make sense for ParamSpec and TypeVarTuple. I think TypeVarTuple should instead be specialized with *tuple[object, ...]. For ParamSpec perhaps Callable[..., object] is right but not 100% sure.
  • The way the tests are written produces some incidental errors, like from ty generics_paramspec_variance.py:28:23: error[empty-body] Function always implicitly returns `None`, which is not assignable to return type `(...) -> Unknown` and mypy generics_typevartuple_variance.py:18: error: Missing return statement [empty-body]. Should add something like raise NotImplementedError.

@KotlinIsland
Copy link
Copy Markdown
Contributor Author

KotlinIsland commented Apr 23, 2026

Callable[..., object] is right but not 100% sure.

not Callable, and not ..., as this is the gradual form. but (*object, **object), which is a non-denotable psuedo representation of the widest value for a parameter specification

@JelleZijlstra
Copy link
Copy Markdown
Member

I don't think that's right. The form we want here should be a supertype of every other possible value, and something like a one-parameter callable is not a subtype of (*: object, **: object).

@AlexWaygood
Copy link
Copy Markdown
Member

In ty we have a type that we spell as Top[Callable[..., object]] in ty's type display (a fully static type describing the infinite union of all possible Callable types). It's not representable using standard Python notation currently.

@JelleZijlstra
Copy link
Copy Markdown
Member

We only need assignability not subtyping here, so I think ... is enough.

@carljm carljm self-requested a review April 23, 2026 23:35
Copy link
Copy Markdown
Member

@carljm carljm left a comment

Choose a reason for hiding this comment

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

Thanks! Definitely support this change.

# > TypeVarTuple does not yet support specification of variance, bounds, constraints.
# > TypeVarTuple does not yet support specification of bounds, constraints.

Ts1 = TypeVarTuple("Ts1", covariant=True) # E
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is is used by Array3 below, so line 107 is now failing for the wrong reason (name error) in all type checkers.

It might be better for the Array3 test to define its own TypeVarTuples right above that test, instead of relying on these TypeVarTuples doing double duty.

Comment thread docs/spec/generics.rst
Comment on lines +681 to +682
arguments in the declaration just as ``typing.TypeVar`` does, but for ``bound`` we
will defer the standardization of the semantics of this option to a later PEP.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
arguments in the declaration just as ``typing.TypeVar`` does, but for ``bound`` we
will defer the standardization of the semantics of this option to a later PEP.
arguments in the declaration just as ``typing.TypeVar`` does.
We defer the standardization of the semantics of the ``bound`` option to a later PEP.

Comment thread docs/spec/generics.rst
Comment on lines +2715 to +2716
``TypeVar``/``TypeVarTuple``/``ParamSpec`` declaration and is not specified
as ``infer_variance`` (see below), its variance is specified by the
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
``TypeVar``/``TypeVarTuple``/``ParamSpec`` declaration and is not specified
as ``infer_variance`` (see below), its variance is specified by the
``TypeVar``/``TypeVarTuple``/``ParamSpec`` declaration and is not constructed
with ``infer_variance=True`` (see below), its variance is specified by the

Comment thread docs/spec/generics.rst

an ``object`` instance for a type variable.
a ``*tuple[object, ...]`` value for a type variable tuple.
a ``...`` value for a parameter specification.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think using ... here is sound. Because it is both assignable-to and assignable-from any paramspec, it means that a case like the ContravariantParamSpec test will wrongly infer the paramspec as covariant (because lower is assignable to upper) before it even checks the contravariant direction.

I don't think there is any way to make the variance-inference algorithm described here correct and support inference of ParamSpec variance, without introducing the new concept of a "top signature".

(I'm also not sure how much value there is in including this particular variance-inference algorithm in the spec. I think it describes pyright's algorithm. I know that ty and pyrefly do not use this algorithm. I don't know about mypy or zuban.)

@@ -0,0 +1,50 @@
"""
Tests variance of ParamSpec.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also have tests for invariant paramspecs (would have to be used more than once in the class)

@@ -0,0 +1,53 @@
"""
Tests variance of TypeVarTuple.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Here too, I think we should have tests for invariant TypeVarTuple.

@carljm
Copy link
Copy Markdown
Member

carljm commented Apr 26, 2026

We only need assignability not subtyping here, so I think ... is enough.

But we also need assignability to fail in the "wrong" direction, and this workaround fails that requirement.

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

Labels

topic: typing spec For improving the typing spec

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants