Skip to content

False positive invalid-super-argument in metaclass __call__ with TypeVar-typed cls #3231

@gaborbernat

Description

@gaborbernat

Summary

When a metaclass __call__ uses a TypeVar-typed cls parameter (a standard pattern to preserve subclass return types), ty emits a false positive invalid-super-argument on the super() call.

Minimal reproducer:

from __future__ import annotations
from typing import TypeVar, Any

_T = TypeVar("_T", bound="Base")

class Meta(type):
    def __call__(cls: type[_T], *args: Any, **kwargs: Any) -> _T:
        return super().__call__(*args, **kwargs)
        #      ^^^^^^^ error[invalid-super-argument]

class Base(metaclass=Meta):
    pass

class Sub(Base):
    def extra(self) -> int:
        return 42

reveal_type(Sub())  # correctly inferred as Sub
Sub().extra()       # correctly no error

Output:

error[invalid-super-argument]: `type[_T@__call__]` is not an instance or subclass of `<class 'Meta'>` in `super(<class 'Meta'>, type[_T@__call__])` call

info: Type variable `_T` has upper bound `Base`
info: `Base` is not an instance or subclass of `<class 'Meta'>`

Expected: No diagnostic. cls is type[_T] where _T: Base, and Base uses Meta as its metaclass, so type[_T] is always an instance of Meta. The implicit super() should resolve to super(Meta, cls) without error.

Note: The return type inference and attribute resolution both work correctly — reveal_type(Sub()) shows Sub and Sub().extra() passes. Only the super() call is flagged.

This pattern is recommended by the typing spec for constructors and is the standard way to type a metaclass __call__ that preserves subclass return types.

Version

ty 0.0.29 (438a78d 2026-04-05)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions