Skip to content

variance for parameter specification and type variable tuples#1771

Draft
KotlinIsland wants to merge 1 commit into
mainfrom
paramspec-variance
Draft

variance for parameter specification and type variable tuples#1771
KotlinIsland wants to merge 1 commit into
mainfrom
paramspec-variance

Conversation

@KotlinIsland
Copy link
Copy Markdown
Collaborator

@KotlinIsland KotlinIsland commented Apr 8, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

Diff from mypy_primer, showing the effect of this PR on open source code:

core (https://github.com/home-assistant/core)
-         Type parameter "_P@HassJob" is invariant, but "(_: datetime | None = None)" is not the same as "(datetime)"
+   .../projects/core/homeassistant/components/google_assistant/report_state.py:196:37 - warning: Argument type is partially unknown
+     Argument corresponds to parameter "action" in function "async_call_later"
+     Argument type is "HassJob[(_now: Unknown), Coroutine[Any, Any, None] | None]" (reportUnknownArgumentType)
-         Type parameter "_P@HassJob" is invariant, but "(_: datetime | None = None)" is not the same as "(datetime)"
-         Type parameter "_P@HassJob" is invariant, but "(_now: datetime | None = None)" is not the same as "(datetime)"
-         Type parameter "_P@HassJob" is invariant, but "(_: Exception | None = None)" is not the same as "(datetime)"
+         Type parameter "_P@HassJob" is covariant, but "(_: Exception | None = None)" is not a subtype of "(datetime)"
+           Type "(_: Exception | None = None)" is not assignable to type "(datetime)"
+             Parameter 1: type "datetime" is incompatible with type "Exception | None"
-   .../projects/core/homeassistant/components/wemo/__init__.py:289:17 - error: Argument of type "HassJob[(datetime), None]" cannot be assigned to parameter "action" of type "HassJob[(datetime), Coroutine[Any, Any, None] | None] | ((datetime) -> (Coroutine[Any, Any, None] | None))" in function "async_call_later"
+   .../projects/core/homeassistant/components/wemo/__init__.py:289:17 - error: Argument of type "HassJob[(event_time: datetime), None] | HassJob[(datetime), None]" cannot be assigned to parameter "action" of type "HassJob[(datetime), Coroutine[Any, Any, None] | None] | ((datetime) -> (Coroutine[Any, Any, None] | None))" in function "async_call_later"
+     Type "HassJob[(event_time: datetime), None] | HassJob[(datetime), None]" is not assignable to type "HassJob[(datetime), Coroutine[Any, Any, None] | None] | ((datetime) -> (Coroutine[Any, Any, None] | None))"
-     Type "HassJob[(datetime), None]" is not assignable to type "HassJob[(datetime), Coroutine[Any, Any, None] | None] | ((datetime) -> (Coroutine[Any, Any, None] | None))"
+       Type "HassJob[(datetime), None]" is not assignable to type "HassJob[(datetime), Coroutine[Any, Any, None] | None] | ((datetime) -> (Coroutine[Any, Any, None] | None))"
-       "HassJob[(datetime), None]" is not assignable to "HassJob[(datetime), Coroutine[Any, Any, None] | None]"
+         "HassJob[(datetime), None]" is not assignable to "HassJob[(datetime), Coroutine[Any, Any, None] | None]"
-         Type parameter "_R_co@HassJob" is invariant, but "None" is not the same as "Coroutine[Any, Any, None] | None"
+           Type parameter "_R_co@HassJob" is invariant, but "None" is not the same as "Coroutine[Any, Any, None] | None"
-       Type "HassJob[(datetime), None]" is not assignable to type "(datetime) -> (Coroutine[Any, Any, None] | None)" (reportArgumentType)
+         Type "HassJob[(datetime), None]" is not assignable to type "(datetime) -> (Coroutine[Any, Any, None] | None)" (reportArgumentType)
+   .../projects/core/homeassistant/components/yeelight/scanner.py:186:28 - warning: Argument type is partially unknown
+     Argument corresponds to parameter "action" in function "async_call_later"
+     Argument type is "HassJob[(*_: Unknown), Coroutine[Any, Any, None] | None]" (reportUnknownArgumentType)
-   .../projects/core/homeassistant/helpers/event.py:1819:13 - error: Argument of type "HassJob[(datetime), None]" cannot be assigned to parameter "action" of type "HassJob[(datetime), Coroutine[Any, Any, None] | None] | ((datetime) -> (Coroutine[Any, Any, None] | None))" in function "async_track_point_in_utc_time"
+   .../projects/core/homeassistant/helpers/event.py:1819:13 - error: Argument of type "HassJob[(_: datetime), None]" cannot be assigned to parameter "action" of type "HassJob[(datetime), Coroutine[Any, Any, None] | None] | ((datetime) -> (Coroutine[Any, Any, None] | None))" in function "async_track_point_in_utc_time"
-     Type "HassJob[(datetime), None]" is not assignable to type "HassJob[(datetime), Coroutine[Any, Any, None] | None] | ((datetime) -> (Coroutine[Any, Any, None] | None))"
+     Type "HassJob[(_: datetime), None]" is not assignable to type "HassJob[(datetime), Coroutine[Any, Any, None] | None] | ((datetime) -> (Coroutine[Any, Any, None] | None))"
-       "HassJob[(datetime), None]" is not assignable to "HassJob[(datetime), Coroutine[Any, Any, None] | None]"
+       "HassJob[(_: datetime), None]" is not assignable to "HassJob[(datetime), Coroutine[Any, Any, None] | None]"
-       Type "HassJob[(datetime), None]" is not assignable to type "(datetime) -> (Coroutine[Any, Any, None] | None)" (reportArgumentType)
+       Type "HassJob[(_: datetime), None]" is not assignable to type "(datetime) -> (Coroutine[Any, Any, None] | None)" (reportArgumentType)
- 33917 errors, 397968 warnings, 0 notes
+ 33917 errors, 397970 warnings, 0 notes

@KotlinIsland KotlinIsland requested a review from DetachHead April 23, 2026 05:28
@DetachHead
Copy link
Copy Markdown
Owner

what issue is this fixing?

@KotlinIsland
Copy link
Copy Markdown
Collaborator Author

what issue is this fixing?

the issue that tvt/param spec variance isn't supported

Comment on lines +13641 to +13686
if (paramName === 'covariant') {
if (argList[i].valueExpression && getBooleanValue(argList[i].valueExpression!)) {
if (
paramSpec.shared.declaredVariance === Variance.Contravariant ||
paramSpec.shared.declaredVariance === Variance.Auto
) {
addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocMessage.typeVarVariance(),
argList[i].valueExpression!
);
} else {
paramSpec.shared.declaredVariance = Variance.Covariant;
}
}
} else if (paramName === 'contravariant') {
if (argList[i].valueExpression && getBooleanValue(argList[i].valueExpression!)) {
if (
paramSpec.shared.declaredVariance === Variance.Covariant ||
paramSpec.shared.declaredVariance === Variance.Auto
) {
addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocMessage.typeVarVariance(),
argList[i].valueExpression!
);
} else {
paramSpec.shared.declaredVariance = Variance.Contravariant;
}
}
} else if (paramName === 'infer_variance') {
if (argList[i].valueExpression && getBooleanValue(argList[i].valueExpression!)) {
if (
paramSpec.shared.declaredVariance === Variance.Covariant ||
paramSpec.shared.declaredVariance === Variance.Contravariant
) {
addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocMessage.typeVarVariance(),
argList[i].valueExpression!
);
} else {
paramSpec.shared.declaredVariance = Variance.Auto;
}
}
} else if (paramName === 'default') {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

duplicated code

Comment on lines +10 to +11
class ShouldBeContravariant1[**OutP]:
def f(self) -> Callable[OutP, None]: ...
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

should also have a test for the most common usage:

class ShouldBeContravariant2[**OutP]:
    def f(self, *args: P.args, **kwargs: P.kwargs): ...

Comment on lines +5 to +7
P_co = ParamSpec("P_co", covariant=True)
P_contra = ParamSpec("P_contra", contravariant=True)
P_infer = ParamSpec("P_infer", infer_variance=True)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

how come these are unused

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

is it just to make sure theres no error on the arguments? if so should add a comment

Comment on lines +5 to +7
Ts_co = TypeVarTuple("Ts_co", covariant=True)
Ts_contra = TypeVarTuple("Ts_contra", contravariant=True)
Ts_infer = TypeVarTuple("Ts_infer", infer_variance=True)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

comment saying why these unused typevar variables are here

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

honestly i have never encountered a single situation where a typevartuple has been useful. could you please provide a realistic example of when anyone would ever use one, and how it could benefit from supporting variance? otherwise i dont see why we should even bother to add variance support to them or touch them in any way.

it sounds like it was just scope creeped in your discourse thread about ParamSpecs for no reason

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.

2 participants