A bunch of overlapping protocols in `@overload`s causes Pyright's runtime to explode.
- Dominant language
- Python
- Stars
- 15.6k
- Forks
- 1.8k
- Avg merge
- 12h 13m
- Merged PRs (30d)
- 52
Description
**Describe the bug**
The following code causes Pyright to be stuck at 100% CPU usage for at least an hour. Where I manually cancelled the process.
The code is mid-rewrite, very broken, and likely makes no sense. But removing the final class causes 100% CPU usage for ~4s, so sorry for the massive code dump of half written nonsense.
**VS Code extension or command-line**
- VS Code with Pylance (new profile).
- The command-line tool (`pip install pyright`).
(Sorry not sure how to find the Pyright versions for both.)
Code
**WARNING**: You may want to use a VS Code profile without Pylance installed.
```python
from __future__ import annotations
import abc
from collections.abc import Iterable
import itertools
from typing import Any, Protocol, overload
__all__ = [
"IN_A",
"IN_D",
"IN_V",
"IN_AD",
"IN_AV",
"IN_DV",
"IN_ADV",
"IC_A",
"IC_D",
"IC_V",
"IC_AD",
"IC_AV",
"IC_DV",
"IC_ADV",
]
class IN_A[TConfig, TIn, TOut](metaclass=abc.ABCMeta):
pass
class IN_D[TConfig, TIn](metaclass=abc.ABCMeta):
pass
class IN_V[TConfig, TError, TIn](metaclass=abc.ABCMeta):
pass
class IN_AD[TConfig, TIn, TOut](IN_A[TConfig, TIn, TOut], IN_D[TConfig, TIn], metaclass=abc.ABCMeta):
pass
class IN_AV[TConfig, TError, TIn, TOut](IN_A[TConfig, TIn, TOut], IN_V[TConfig, TError, TIn], metaclass=abc.ABCMeta):
pass
class IN_DV[TConfig, TError, TIn](IN_D[TConfig, TIn], IN_V[TConfig, TError, TIn], metaclass=abc.ABCMeta):
pass
class IN_ADV[TConfig, TError, TIn, TOut](IN_A[TConfig, TIn, TOut], IN_D[TConfig, TIn], IN_V[TConfig, TError, TIn], metaclass=abc.ABCMeta):
pass
class IC_A[TConfig, TIn, TOut](IN_A[TConfig, TIn, TOut], Protocol, metaclass=abc.ABCMeta):
@overload
def chain[TC, TE, TO](self, other: IN_ADV[TC, TE, TOut, TO]) -> IC_ADV[TConfig | TC, TE, TIn, TO]: ...
@overload
def chain[TC, TO](self, other: IN_AD[TC, TOut, TO]) -> IC_AD[TConfig | TC, TIn, TO]: ...
@overload
def chain[TC, TE, TO](self, other: IN_AV[TC, TE, TOut, TO]) -> IC_AV[TConfig | TC, TE, TIn, TO]: ...
@overload
def chain[TC, TE](self, other: IN_DV[TC, TE, TOut]) -> IC_ADV[TConfig | TC, TE, TIn]: ...
@overload
def chain[TC, TO](self, other: IN_A[TC, TOut, TO]) -> IC_A[TConfig | TC, TIn, TO]: ...
@overload
def chain[TC](self, other: IN_D[TC, TOut]) -> IC_AD[TConfig | TC, TIn]: ...
@overload
def chain[TC, TE](self, other: IN_V[TC, TE, TOut]) -> IC_AV[TConfig | TC, TE, TIn]: ...
@overload
def chain(self, other: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
raise NotImplementedError(f"{type(self).__name__}.chain has not been defined")
class IC_D[TConfig, TIn](IN_D[TConfig, TIn], Protocol, metaclass=abc.ABCMeta):
@overload
def chain[TC, TE, TO](self, other: IN_ADV[TC, TE, TIn, TO]) -> IC_ADV[TConfig | TC, TE, TIn, TO]: ...
@overload
def chain[TC, TO](self, other: IN_AD[TC, TIn, TO]) -> IC_AD[TConfig | TC, TIn, TO]: ...
@overload
def chain[TC, TE, TO](self, other: IN_AV[TC, TE, TIn, TO]) -> IC_ADV[TConfig | TC, TE, TIn, TO]: ...
@overload
def chain[TC, TE](self, other: IN_DV[TC, TE, TIn]) -> IC_DV[TConfig | TC, TE, TIn]: ...
@overload
def chain[TC, TO](self, other: IN_A[TC, TIn, TO]) -> IC_AD[TConfig | TC, TIn, TO]: ...
@overload
def chain[TC](self, other: IN_D[TC, TIn]) -> IC_D[TConfig | TC, TIn]: ...
@overload
def chain[TC, TE](self, other: IN_V[TC, TE, TIn]) -> IC_DV[TConfig | TC, TE, TIn]: ...
@overload
def chain(self, other: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
raise NotImplementedError(f"{type(self).__name__}.chain has not been defined")
class IC_V[TConfig, TError, TIn](IN_V[TConfig, TError, TIn], Protocol, metaclass=abc.ABCMeta):
@overload
def chain[TC, TE, TO](self, other: IN_ADV[TC, TE, TIn, TO]) -> IC_ADV[TConfig | TC, TError | TE, TIn, TO]: ...
@overload
def chain[TC, TO](self, other: IN_AD[TC, TIn, TO]) -> IC_ADV[TConfig | TC, TError, TIn, TO]: ...
@overload
def chain[TC, TE, TO](self, other: IN_AV[TC, TE, TIn, TO]) -> IC_AV[TConfig | TC, TError | TE, TIn, TO]: ...
@overload
def chain[TC, TE](self, other: IN_DV[TC, TE, TIn]) -> IC_DV[TConfig | TC, TError | TE, TIn]: ...
@overload
def chain[TC, TO](self, other: IN_A[TC, TIn, TO]) -> IC_AV[TConfig | TC, TError, TIn, TO]: ...
@overload
def chain[TC](self, other: IN_D[TC, TIn]) -> IC_DV[TConfig | TC, TError, TIn]: ...
@overload
def chain[TC, TE](self, other: IN_V[TC, TE, TIn]) -> IC_V[TConfig | TC, TError | TE, TIn]: ...
@overload
def chain(self, other: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
raise NotImplementedError(f"{type(self).__name__}.chain has not been defined")
class IC_AD[TConfig, TIn, TOut](IN_AD[TConfig, TIn, TOut], Protocol, metaclass=abc.ABCMeta):
@overload
def chain[TC, TE, TO](self, other: IN_ADV[TC, TE, TOut, TO]) -> IC_ADV[TConfig | TC, TE, TIn, TO]: ...
@overload
def chain[TC, TO](self, other: IN_AD[TC, TOut, TO]) -> IC_AD[TConfig | TC, TIn, TO]: ...
@overload
def chain[TC, TE, TO](self, other: IN_AV[TC, TE, TOut, TO]) -> IC_ADV[TConfig | TC, TE, TIn, TO]: ...
@overload
def chain[TC, TE](self, other: IN_DV[TC, TE, TOut]) -> IC_ADV[TConfig | TC, TE, TIn]: ...
@overload
def chain[TC, TO](self, other: IN_A[TC, TOut, TO]) -> IC_AD[TConfig | TC, TIn, TO]: ...
@overload
def chain[TC](self, other: IN_D[TC, TOut]) -> IC_AD[TConfig | TC, TIn]: ...
@overload
def chain[TC, TE](self, other: IN_V[TC, TE, TOut]) -> IC_ADV[TConfig | TC, TE, TIn]: ...
@overload
def chain(self, other: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
raise NotImplementedError(f"{type(self).__name__}.chain has not been defined")
class IC_AV[TConfig, TError, TIn, TOut](IN_AV[TConfig, TError, TIn, TOut], Protocol, metaclass=abc.ABCMeta):
@overload
def chain[TC, TE, TO](self, other: IN_ADV[TC, TE, TOut, TO]) -> IC_ADV[TConfig | TC, TError | TE, TIn, TO]: ...
@overload
def chain[TC, TO](self, other: IN_AD[TC, TOut, TO]) -> IC_ADV[TConfig | TC, TError, TIn, TO]: ...
@overload
def chain[TC, TE, TO](self, other: IN_AV[TC, TE, TOut, TO]) -> IC_AV[TConfig | TC, TError | TE, TIn, TO]: ...
@overload
def chain[TC, TE](self, other: IN_DV[TC, TE, TOut]) -> IC_ADV[TConfig | TC, TError | TE, TIn]: ...
@overload
def chain[TC, TO](self, other: IN_A[TC, TOut, TO]) -> IC_AV[TConfig | TC, TError, TIn, TO]: ...
@overload
def chain[TC](self, other: IN_D[TC, TOut]) -> IC_ADV[TConfig | TC, TError, TIn]: ...
@overload
def chain[TC, TE](self, other: IN_V[TC, TE, TOut]) -> IC_AV[TConfig | TC, TError | TE, TIn]: ...
@overload
def chain(self, other: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
raise NotImplementedError(f"{type(self).__name__}.chain has not been defined")
class IC_DV[TConfig, TError, TIn](IN_DV[TConfig, TError, TIn], Protocol, metaclass=abc.ABCMeta):
@overload
def chain[TC, TE, TO](self, other: IN_ADV[TC, TE, TIn, TO]) -> IC_ADV[TConfig | TC, TError | TE, TIn, TO]: ...
@overload
def chain[TC, TO](self, other: IN_AD[TC, TIn, TO]) -> IC_ADV[TConfig | TC, TError, TIn, TO]: ...
@overload
def chain[TC, TE, TO](self, other: IN_AV[TC, TE, TIn, TO]) -> IC_ADV[TConfig | TC, TError | TE, TIn, TO]: ...
@overload
def chain[TC, TE](self, other: IN_DV[TC, TE, TIn]) -> IC_DV[TConfig | TC, TError | TE, TIn]: ...
@overload
def chain[TC, TO](self, other: IN_A[TC, TIn, TO]) -> IC_ADV[TConfig | TC, TError, TIn, TO]: ...
@overload
def chain[TC](self, other: IN_D[TC, TIn]) -> IC_DV[TConfig | TC, TError, TIn]: ...
@overload
def chain[TC, TE](self, other: IN_V[TC, TE, TIn]) -> IC_DV[TConfig | TC, TError | TE, TIn]: ...
@overload
def chain(self, other: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
raise NotImplementedError(f"{type(self).__name__}.chain has not been defined")
class IC_ADV[TConfig, TError, TIn, TOut](IN_ADV[TConfig, TError, TIn, TOut], Protocol, metaclass=abc.ABCMeta):
@overload
def chain[TC, TE, TO](self, other: IN_ADV[TC, TE, TOut, TO]) -> IC_ADV[TConfig | TC, TError | TE, TIn, TO]: ...
@overload
def chain[TC, TO](self, other: IN_AD[TC, TOut, TO]) -> IC_ADV[TConfig | TC, TError, TIn, TO]: ...
@overload
def chain[TC, TE, TO](self, other: IN_AV[TC, TE, TOut, TO]) -> IC_ADV[TConfig | TC, TError | TE, TIn, TO]: ...
@overload
def chain[TC, TE](self, other: IN_DV[TC, TE, TOut]) -> IC_ADV[TConfig | TC, TError | TE, TIn]: ...
@overload
def chain[TC, TO](self, other: IN_A[TC, TOut, TO]) -> IC_ADV[TConfig | TC, TError, TIn, TO]: ...
@overload
def chain[TC](self, other: IN_D[TC, TOut]) -> IC_ADV[TConfig | TC, TError, TIn]: ...
@overload
def chain[TC, TE](self, other: IN_V[TC, TE, TOut]) -> IC_ADV[TConfig | TC, TError | TE, TIn]: ...
@overload
def chain(self, other: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
raise NotImplementedError(f"{type(self).__name__}.chain has not been defined")
```
Contributor guide
Research direction
Run the supplied Python reproducer with the command-line tool and compare its behavior with VS Code/Pylance. Trace the type-checking path for the overlapping Protocol and @overload declarations; done means analysis completes without sustained 100% CPU usage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100