Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork3.1k
Description
I'm seeing extremely slow type-checking (around 1–2 minutes) for a very small, self-contained example involving constrainedTypeVars, generic subclasses, and many overloads. The code produces no errors but mypy appears to spend a disproportionate amount of time resolving types.
The example defines twoTypeVars constrained to ~15Literal[str] values, a generic base classPbase[T], several subclassesP1[T] …P14[T], and a generic classFn[T1, T2] whosecall method is overloaded to preserve the concrete subclass while transforming the type parameter. The full reproduction is below.
importtypingastclassLetterT:A=t.Literal["a"]B=t.Literal["b"]C=t.Literal["c"]D=t.Literal["d"]E=t.Literal["e"]F=t.Literal["f"]G=t.Literal["g"]H=t.Literal["h"]I=t.Literal["i"]J=t.Literal["j"]K=t.Literal["k"]L=t.Literal["l"]M=t.Literal["m"]N=t.Literal["n"]O=t.Literal["o"]T1=t.TypeVar("T1",LetterT.A,LetterT.B,LetterT.C,LetterT.D,LetterT.E,LetterT.F,LetterT.G,LetterT.H,LetterT.I,LetterT.J,LetterT.K,LetterT.L,LetterT.M,LetterT.N,LetterT.O,)T2=t.TypeVar("T2",LetterT.A,LetterT.B,LetterT.C,LetterT.D,LetterT.E,LetterT.F,LetterT.G,LetterT.H,LetterT.I,LetterT.J,LetterT.K,LetterT.L,LetterT.M,LetterT.N,LetterT.O,)classPbase(t.Generic[T1]):def__init__(self,v:T1)->None:self.v:T1=vclassP1(Pbase[T1]): ...classP2(Pbase[T1]): ...classP3(Pbase[T1]): ...classP4(Pbase[T1]): ...classP5(Pbase[T1]): ...classP6(Pbase[T1]): ...classP7(Pbase[T1]): ...classP8(Pbase[T1]): ...classP9(Pbase[T1]): ...classP10(Pbase[T1]): ...classP11(Pbase[T1]): ...classP12(Pbase[T1]): ...classP13(Pbase[T1]): ...classP14(Pbase[T1]): ...classFn(t.Generic[T1,T2]):def__init__(self,a:T1,b:T2)->None:self.a:T1=aself.b:T2=b@t.overloaddefcall(self,p:P1[T1])->P1[T2]: ...@t.overloaddefcall(self,p:P2[T1])->P2[T2]: ...@t.overloaddefcall(self,p:P3[T1])->P3[T2]: ...@t.overloaddefcall(self,p:P4[T1])->P4[T2]: ...@t.overloaddefcall(self,p:P5[T1])->P5[T2]: ...@t.overloaddefcall(self,p:P6[T1])->P6[T2]: ...@t.overloaddefcall(self,p:P7[T1])->P7[T2]: ...@t.overloaddefcall(self,p:P8[T1])->P8[T2]: ...@t.overloaddefcall(self,p:P9[T1])->P9[T2]: ...@t.overloaddefcall(self,p:P10[T1])->P10[T2]: ...@t.overloaddefcall(self,p:P11[T1])->P11[T2]: ...@t.overloaddefcall(self,p:P12[T1])->P12[T2]: ...@t.overloaddefcall(self,p:P13[T1])->P13[T2]: ...@t.overloaddefcall(self,p:P14[T1])->P14[T2]: ...defcall(self,p):# type: ignore[no-untyped-def]returnFn(self.b,p.v)
Runningmypy repro.py --no-incremental consistently takes on the order of minutes on my machine. Removing any one of the following makes the runtime drop back to normal: theLiteral constraints, the number of overloads, or the generic subclass hierarchy. This suggests a combinatorial blow-up in constraint solving and/or overload resolution. While using a boundedTypeVar instead of explicit constraints does improve performance, that is not a viable option in my case, as I need to parameterize these classes with precise, concreteLiteral types rather than a common upper bound.
This is primarily a performance report; I'm not sure whether this is a known limitation or an opportunity for optimization, but the scaling behavior seems unexpectedly poor for such a small input.
I also attach the command I used to benchmark type checking time.
$time mypy repro.py --no-incrementalreal 1m44.220suser 1m44.065ssys 0m1.409s
Any ideas what might be the issue? How hard would it be to solve it?