You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Please feel free to edit bug title and/or description to clarify language. 🙏
Types are not properly resolved when a TypeVar from a Generic class is bound to a TypeVar from a generic function signature.
Types are properly resolved when a TypeVar from a generic function signature is bound to a TypeVar from another generic function signature.
Therefor I believe this resolution failure is an error, rather than expected behavior.
This repro case demonstrates the issue in pyright and fails in v1.1.351 and v1.1.355. wrap_fun binds T to Iterable[A@first] (specified as a TypeVar in the generic signature of wrap_fun),
and then properly resolves A@first to str on call.
generic_wrapped also binds T to Iterable[A@first] (now specified as a TypeVar in the Generic class declaration of Wrap),
but fails to resolve A@first to str on a method invocation.
This is reported as "Literal['foobar']" cannot be assigned to parameter of type "Iterable[A@first]".
This repro case includes a dataclass declaration for concision, but repros without dataclasses.
The repro case demonstrates the resolution failure with properties of the generic , a __call__ on the generic and an operator resolution failure on the generic (presumably due to the type resolution failure surfacing as an operator match failure).
Repro log from pyright CLI, which also functions in current Pylance:
$ pyright --version && pyright wrapped_generic_resolution_repro.py
WARNING: there is a new pyright version available (v1.1.351 -> v1.1.355).
Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest`
pyright 1.1.351
WARNING: there is a new pyright version available (v1.1.351 -> v1.1.355).
Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest`
/home/alexford/ab/main/wrapped_generic_resolution_repro.py
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:21:13 - information: Type of "first" is "(seq: Iterable[A@first]) -> A@first"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:29:13 - information: Type of "wrap_fun(first)" is "(Iterable[A@first]) -> A@first"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:30:13 - information: Type of "wrap_fun(first)("foobar")" is "str"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:47:13 - information: Type of "explicit_wrapped.func" is "(vals: Iterable[A@func]) -> A@func"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:50:13 - information: Type of "explicit_wrapped" is "ExplicitWrappedFirst"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:51:13 - information: Type of "explicit_wrapped.__call__" is "(vals: Iterable[A@__call__]) -> A@__call__"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:54:13 - information: Type of "explicit_wrapped.__ror__" is "(vals: Iterable[A@__ror__]) -> A@__ror__"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:71:24 - error: Argument of type "Literal['foobar']" cannot be assigned to parameter "__value" of type "Iterable[A@first]" in function "__call__"
"Literal['foobar']" is incompatible with "Iterable[A@first]"
Type parameter "_T_co@Iterable" is covariant, but "str" is not a subtype of "A@first"
Type "str" cannot be assigned to type "A@first" (reportArgumentType)
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:72:13 - information: Type of "generic_wrapped" is "Wrap[Iterable[A@first], A@first]"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:73:13 - information: Type of "generic_wrapped.func" is "(Iterable[A@first]) -> A@first"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:74:13 - error: "assert_type" mismatch: expected "str" but received "A@first" (reportAssertTypeFailure)
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:74:34 - error: Argument of type "Literal['foobar']" cannot be assigned to parameter of type "Iterable[A@first]"
"Literal['foobar']" is incompatible with "Iterable[A@first]"
Type parameter "_T_co@Iterable" is covariant, but "str" is not a subtype of "A@first"
Type "str" cannot be assigned to type "A@first" (reportArgumentType)
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:76:13 - information: Type of "generic_wrapped.__call__" is "(__value: Iterable[A@first], /) -> A@first"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:77:13 - error: "assert_type" mismatch: expected "str" but received "A@first" (reportAssertTypeFailure)
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:77:29 - error: Argument of type "Literal['foobar']" cannot be assigned to parameter "__value" of type "Iterable[A@first]" in function "__call__"
"Literal['foobar']" is incompatible with "Iterable[A@first]"
Type parameter "_T_co@Iterable" is covariant, but "str" is not a subtype of "A@first"
Type "str" cannot be assigned to type "A@first" (reportArgumentType)
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:79:13 - information: Type of "generic_wrapped.__ror__" is "(__value: Iterable[A@first], /) -> A@first"
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:80:13 - error: Operator "|" not supported for types "Literal['foobar']" and "Wrap[Iterable[A@first], A@first]" (reportOperatorIssue)
/home/alexford/ab/main/wrapped_generic_resolution_repro.py:80:13 - error: "assert_type" mismatch: expected "str" but received "Unknown" (reportAssertTypeFailure)
7 errors, 0 warnings, 11 informations
The text was updated successfully, but these errors were encountered:
asford
changed the title
Type resolution failure when Generic TypeVar references another TypeVar method signature.
Type resolution failure when Generic TypeVar references TypeVar from generic function signature.
Mar 23, 2024
asford
changed the title
Type resolution failure when Generic TypeVar references TypeVar from generic function signature.
Type resolution failure when Generic class TypeVar references TypeVar from generic function signature.
Mar 23, 2024
The behavior you're seeing is by design, so I don't consider this a bug.
The behavior for wrap_fun is relying on behavior that is currently unspecified in the Python typing spec related to Callable return types. If pyright (or mypy) sees a Callable return type for a function (as in the case of wrap_fun), and a call of that function results in unsolved type variables, even if those type variables come from some other function (such as first in your example), it effectively treats these unsolved type variables as though they are rescoped to the returned Callable. This unspecified and undocumented "hack" allows pyright and mypy to evaluate the expression wrap_fun(first)("foobar") in a manner consistent with what you're seeing in your code sample.
I'd like to see this behavior formally specified in the typing spec at some point, but we're a long way from that. Currently, there's nothing about TypeVar constraint solving in the typing spec, and we have many more fundamental concepts that need to be documented before we get to something like this.
In the case of Wrap, there is no simple Callable as a return type. In this case, it's not clear what should happen to the unsolved type variables that result when evaluating Wrap(first). Pyright evaluates this as Wrap[Iterable[A@first], A@first]. But the type variable A@first is now out of scope, so it can no longer be solved. Unlike the Callable example, it has not been (and really cannot be) rescoped. Mypy generates an error when evaluating Wrap(first) ("Need type annotation for 'generic_wrapped' [var-annotated]"), and it evaluates the expression's type as Wrap[Iterable[Any], Any].
I'm going to close this because pyright is working as designed here. I don't think your code sample will type check without some changes and clarifications to the type spec.
Please feel free to edit bug title and/or description to clarify language. 🙏
Types are not properly resolved when a TypeVar from a Generic class is bound to a TypeVar from a generic function signature.
Types are properly resolved when a TypeVar from a generic function signature is bound to a TypeVar from another generic function signature.
Therefor I believe this resolution failure is an error, rather than expected behavior.
This repro case demonstrates the issue in
pyright
and fails in v1.1.351 and v1.1.355.wrap_fun
bindsT
toIterable[A@first]
(specified as a TypeVar in the generic signature ofwrap_fun
),and then properly resolves
A@first
tostr
on call.generic_wrapped
also bindsT
toIterable[A@first]
(now specified as a TypeVar in the Generic class declaration ofWrap
),but fails to resolve
A@first
tostr
on a method invocation.This is reported as
"Literal['foobar']" cannot be assigned to parameter of type "Iterable[A@first]"
.This repro case includes a dataclass declaration for concision, but repros without dataclasses.
The repro case demonstrates the resolution failure with properties of the generic , a
__call__
on the generic and an operator resolution failure on the generic (presumably due to the type resolution failure surfacing as an operator match failure).Repro log from
pyright
CLI, which also functions in current Pylance:The text was updated successfully, but these errors were encountered: