DetachHead / basedpyright

pyright fork with various type checking improvements, improved vscode support and pylance features built into the language server
https://docs.basedpyright.com
Other
1.15k stars 21 forks source link

`dataclass`'s generated `__replace__` breaks lsp #854

Open KotlinIsland opened 1 day ago

KotlinIsland commented 1 day ago
from dataclasses import dataclass

@dataclass(frozen=True)
class Foo:
    a: object

@dataclass(frozen=True)
class Bar(Foo):
    a: int

def do[T: Foo](f: T) -> T:
    return f.__replace__(a="")

b = do(Bar(1))
_ = b.a + 1  # runtime error

mypy generates it with a monomorphic return type, so this error is picked up

it's an issue with the generated types for __replace__ being invalid subtypes to repro this without dataclasses would require using ReadOnly to get the same behavior as a frozen dataclass:

class Foo:
    def __init__(self, a: object):
        self.a: ReadOnly[object] = a

    def r(self, a: object) -> Self:
        return type(self)(a)

class Bar(Foo):
    def __init__(self, a: int):
        self.a: ReadOnly[int] = a

    # def r(self, a: int) -> Self:  # huuh????
    #     return type(self)(a)

def do[T: Foo](f: T) -> T:
    return f.r(a="")

b = do(Bar())
_ = b.a + 1  # runtime error 
KotlinIsland commented 1 day ago

it's an issue with type( and unsafe constructors

DetachHead commented 1 day ago

123

KotlinIsland commented 1 day ago

so it's an issue with type, but the impl of the generated __replace__ does something like that (return self.__class__(**changes))

so this is still unsafe and inventing a new type won't make this error go away

KotlinIsland commented 1 day ago

it's actually an issue with the generated types for __replace__ being invalid subtypes

DetachHead commented 1 day ago

upstream issue: https://github.com/microsoft/pyright/issues/9351

DetachHead commented 1 day ago

also dataclasses.replace is completely untyped anyway