ITADN

TypeVarTuple escapes method with very nested recursive tuple aliases

#11472OpenMeGaGiGaGon 创建于 2026-05-29
bug
M
MeGaGiGaGoncommented
**Describe the bug** When calling a method generic over a `TypeVarTuple` on a instance that contains deeply nested recursive tuples in type aliases, the generic "escapes" into the code. ``` Type "ForwardRefParser[tuple[Whitespace, Whitespace, tuple[BlockItem], OO@unpack_then], None]" is not assignable to declared type "ForwardRefParser[tuple[Whitespace, Whitespace, tuple[BlockItem], Whitespace], None]" ``` The issue is the `OO@unpack_then`, which escaped from the method. On the code sample provided there should be no error. If on the code sample you remove any of the levels of nesting of the type aliases, the issue goes away. Eg applying this diff makes the code pass ```diff - type Whitespace = tuple[tuple[tuple[tuple[Whitespace]]]] + type Whitespace = tuple[tuple[tuple[Whitespace]]] ``` Applying these two diffs at the same time makes the code pass: ```diff tuple[BlockItem], - Whitespace, ], ``` ```diff - lambda: ws.then(ws).unpack_then(block).unpack_then(ws) + lambda: ws.then(ws).unpack_then(block) ``` **Code or Screenshots** Code sample in [pyright playground](https://pyright-play.net/?code=GYJw9gtgBALgngBwJYDsDmUkQWEMrCoCGANgDRRgBuApiCEgCY0BQokUAxmCSTZzCRgUAZwB0RAEadM2XPgDCpElL4t1AAUIpSLTipEioAeQDWAbQAqAXQBcLKI6gB9ZxCIxOAC2dEQaEVcoAF4oAAoAImcqUgBXGgiyAEp1JyhmYBdnVCQYVzCRGhJgChiSeNsoSyT7NLTC4rFouJpKyxCoMvj1Fi1iEj0DIwBRenNhuwcnDKycvOcCopLOlsrhmqm6qAbgJq7WqGGO-Z74BBooACUaEViSGCsKCY6zK2soAB9DsYn1M4uAAp%2BQoga63e7mYxPd6hMF3B4wWIIPjmVAwCjGazQlj-KBAkAggBisRQnEh0I6Sl4qho5nMIhgIAoaKxeOBdDhEKhh2s1h6%2BiIhjZBLo5J5tWmNEyrjm%2BR2FGAJM4lXxRKVYomGy2jh2TUVpJV7JAxNJGphBCVqUlmRgXhoKEh3OME0WxQozjAtrohpFIEdGM1UAAtAA%2BYUg8yI5G0p2Yp6fEwTCVbEBEJCFKAAOU9AElsHwIPaYDRGKNwCArY4ZiSEEROKZnF6HQAqSwAZQxTpdmzqOx9EajKNbbdZE3dnrtIH7ouMXb5aSSwbDqtFg9pw87o4Tzsm2qgqfTF2zMDz0cLKGLpfouHUMwQ4EYsU4tJsYWcbQT2ZQF1CX5oi9DKpKgPDNj1PAsixLMsb0GQUjEJXAAHc-EYa5gBXP1uRdDCzS1JwNGoOgGGYHsZhlFBcjlJYFSVSoqRUSQUXMVkcKw3k8K2XU3BoGAiGcfVlSgeiaTpFijTNc0BJ7eokToMIkiabIKPmMJ7zAR9n3klI-kQC4AHUvFyG5a2fDo10jJEUXM8yDKMkQTJoXleRYRCREqBCQGQkBUKlHDbOLey6xoCg-3NNSNJoeT1BQMAwAQac-QZJks2ERyOnCp9Iu04BcBIWL4qgDyvJ89DxJ7czpKcfzjKCshKscarAufOq93MgAhPL6xzYsICxeqoEahyWqcPq0j-OrzSKlC0IwsIexUCBJEYIhKlcsQmzCVyFJrOsGw2xiwHrbaUBMva7RQTaRBSbTcXAmhz14wRhCMUJrMs2kbMMgKHNZO6Ho8IRRGcrAzyLAHnvcpDpt88S-rBp7RBC1KwofTKopxXSoA6w7TG6%2B6zPeizo3MOGL3BoH3i%2BdrOtxnq%2BQO%2BsEqJlFsa6umke-FH1LRlIgA) <details> <summary>Collapsed for readability</summary> ```python from typing import final, override from collections.abc import Callable @final class Ok[T]: __match_args__ = ("_value",) def __init__(self, value: T): self._value: T = value @final class Err[E]: def __init__(self, value: E): self._value: E = value type Result[T, E] = Ok[T] | Err[E] type ParserResult[O, E] = Result[tuple[int, O], E] type ParserFunc[O, E] = Callable[[str, int], ParserResult[O, E]] class Parser[O, E]: def __init__(self, func: ParserFunc[O, E]): self._func: ParserFunc[O, E] = func def then[OO, OE](self, _other: Parser[OO, OE]) -> Parser[tuple[O, OO], E | OE]: raise NotImplementedError def unpack_then[*TS, OO, OE]( self: Parser[tuple[*TS], E], _other: Parser[OO, OE] ) -> Parser[tuple[*TS, OO], E | OE]: raise NotImplementedError def produce[T](_: T | None = None) -> T: raise NotImplementedError class ForwardRefParser[O, E](Parser[O, E]): @override def __init__(self, func: Callable[[], Parser[O, E]]): self._meta_func: Callable[[], Parser[O, E]] = func super().__init__(produce()) type Whitespace = tuple[tuple[tuple[tuple[Whitespace]]]] ws: ForwardRefParser[Whitespace, None] = produce() noop: Parser[str, None] = produce() forloop: ForwardRefParser[ tuple[ Whitespace, Whitespace, tuple[BlockItem], Whitespace, ], None, ] = ForwardRefParser( lambda: ws.then(ws).unpack_then(block).unpack_then(ws) ) type Implementations = tuple[tuple[tuple[Whitespace], Implementations]] implementations: ForwardRefParser[Implementations, None] = produce() type BlockItem = tuple[tuple[Implementations]] | tuple[BlockItem] block: Parser[tuple[BlockItem], None] = produce() ``` </details> **VS Code extension or command-line** Tested on online playground pyright version `1.1.410`
0 条评论