TypeVar using old syntax falsely identified as not a TypeVar in very specific situation
ImogenBits opened this issue · comments
Not sure how to even describe the root cause of this, but I've found some incredibly strange behaviour when using the old TypVar syntax with weird bounds. This is a minimal working example to see the bug:
def early_reference():
Second
T = TypeVar("T", bound="All")
class First(Generic[T]): # pyright error: Type argument for "Generic" must be a type variable
attr: T # pyright error: Type variable "T" has no meaning in this context
class Second(Generic[T]):
attr: T
All = First | Second
It seems that some part of the type var machinery breaks when you use the old syntax to define a TypeVar, it is bound to a union of types that use it, and one of those types is used above the TypeVar definition. The error occurs on all classes except the first one to be referenced above the TypeVar line. E.g. if you replace the body of early_reference
in the example with references to both First and Second the error will move depending on which is first.
I'm using the VSCode extension and pyright 1.1.362
You have created a circular reference. Pyright's lazy evaluator is designed to be able to evaluate the type of any expression at any time, and it recursively evaluates types of symbols until it's able to answer the initial request. However, if there is a true circular dependency between symbols, pyright will not be able to deterministically evaluate types.
In your case, the type of class First
depends on TypeVar T
which is bound to All
which depends on class First
.
This is effectively a duplicate of #6009, where a similar situation occurs with the default
value of a TypeVar rather than the bound
.
I've looked for ways to break this circular dependency in a deterministic way, for example by deferring evaluation of the upper bound. This turns out to be really difficult.
I've left bug #6009 open because I would like to fix this eventually, but it's not something that is likely to be fixed anytime soon.
I'm going to close this issue as a duplicate.