Skip to content

Type inference error in frozen dataclasses inheritance #2636

@andreasoprani

Description

@andreasoprani

Summary

I think ty is misreporting an error due to a type-inference related problem.
I'll paste below the snippet that reproduces the error that I have in my codebase, the output of ty check and pyright and then some considerations.

Code:

from dataclasses import dataclass


@dataclass
class Configuration:
    pass


@dataclass(frozen=True)
class SomeClass:
    config: Configuration | None

    def foo(self) -> int:
        raise NotImplementedError


@dataclass
class SpecificConfiguration(Configuration):
    x: int = 0


@dataclass(frozen=True)
class SpecificClass(SomeClass):
    config: SpecificConfiguration | None = None

    def foo(self) -> int:
        if self.config is None:
            return SpecificConfiguration().x
        return self.config.x


print(SpecificClass(config=SpecificConfiguration()).foo())
print(SpecificClass().foo())

ty check:

error[unresolved-attribute]: Object of type `Configuration` has no attribute `x`
  --> script.py:29:16
   |
27 |         if self.config is None:
28 |             return SpecificConfiguration().x
29 |         return self.config.x
   |                ^^^^^^^^^^^^^
   |
info: rule `unresolved-attribute` is enabled by default

Found 1 diagnostic

pyright:

0 errors, 0 warnings, 0 informations

Ty seems to infer that the type of self.config is Configuration which is the type of that attribute in the parent class while pyright correctly infers it as SpecificConfiguration, pyright could be relying here on the fact that the dataclasses are frozen maybe.

Note that:

  • If I remove frozen=True from both classes I get the following error from pyright: "config" overrides symbol of same name in class "SomeClass", Variable is mutable so its type is invariant while no new error appeas in ty.
  • If I change the config declaration in SomeClass to config: Configuration | None = None ty returns with no errors (All checks passed!) which is a little weird since nothing really changed in the type declaration.
  • Pyright is set on strict mode.

I could be mistaken and maybe ty is behaving correctly, I'm not an expert in Python typing so in that case feel free to close the issue and please let me know what I'm missing.

Version

ty 0.0.14 (16597f5 2026-01-26)

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdataclassesIssues relating to dataclasses and dataclass_transform

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions