microsoft / microsoft/pyright

Passing a generic type via a parameter of type `type[T]` can leak an unsolved type variable

Open
#10,631 0 comments 1 reaction 0 assignees View on GitHub
bug
Dominant language
Python
Stars
15.6k
Forks
1.8k
Avg merge
12h 13m
Merged PRs (30d)
52

Description

**Describe the bug**

I have a generic class that allows specifying its type variable by passing a `type` object to the `__init__` method. The `__init__` method uses a function-scoped type variable for the passed-in `type` object as well as its `self` type. If the passed-in `type` object is itself a generic type, then Pyright seems to be leaking an unsolved type variable, even if the passed-in generic type has a default.

Context: The actual class wraps a NumPy array and allows you to pass in a NumPy dtype-like object in order to specify the array element type for an empty array. Its `__init__` method has an overload that takes `type[T] | np.dtype[T]` for the dtype-like object. The passed-in generic type is `np.bool`. This class turned up a issue with `np.bool` behavior in mypy: https://github.com/numpy/numpy/issues/29245 . While testing the workaround for that issue, I encountered this other issue with Pyright. @jorenham came up with a minimal reproduction that doesn't depend on NumPy.

**Code or Screenshots**

```
from typing import reveal_type

class Boolean[B: bool = bool]:
def __init__(self, b: B, /): ...

class Wrapper[T]:
dtype: type[T]
def __init__[U](self: Wrapper[U], dtype: type[U]) -> None:
self.dtype = dtype

reveal_type(Wrapper(Boolean)) # Wrapper[Boolean[B@Boolean]]
```

https://pyright-play.net/?pythonVersion=3.14&strict=true&code=GYJw9gtgBALgngBwJYDsDmUkQWEMogCmAboQIYA2A%2BvAoQFCMDGFZAzm1AEJhgXkoA2lwBcUAEa8KUALwSpAXRH0oqqABNCwKFSqokMXQAo2hCsAA0EsVysB6AJRiAdK%2BasOUAOogyCOiCCACpKKmrqtIRikcEKYaqa2rr6hlSCAKoKJmbAYj5%2BARkKVhGIUbBlRQ5QALQAfFAAcmAoUfFqqqbmzqV0shqRjESklDRlRvn%2BhCBGPHwCDg70QA

If you remove the type variable U and use T directly (`def __init__(self, dtype: type[T]) -> None:`), it doesn't leak an unsolved type variable:
```
Type of "Wrapper(Boolean)" is "Wrapper[Boolean[bool]]"
```

**VS Code extension or command-line**
pyright 1.1.402, command-line

Contributor guide

Open the contributing guide

Research direction

Start by running the minimal reproduction from the issue with pyright 1.1.402 and compare the inferred type for Wrapper(Boolean) with the version that uses T directly. Trace the generic type inference for the function-scoped U and the defaulted Boolean type variable; done means the unsolved variable no longer leaks and the result is reported as Wrapper[Boolean[bool]].

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.