[ty] Infer implicit type of cls in __new__ methods (#22584)

## Summary

Resolves https://github.com/astral-sh/ty/issues/2489.
This commit is contained in:
Ibraheem Ahmed
2026-01-15 15:42:16 -05:00
committed by GitHub
parent c696ef4025
commit 78d1343583
4 changed files with 6 additions and 10 deletions

View File

@@ -585,8 +585,8 @@ class Baz(Bar[Self]): ...
class MyMetaclass(type):
# TODO: reject the Self usage. because self cannot be used within a metaclass.
def __new__(cls) -> Self:
return super().__new__(cls)
def __new__(cls, name, bases, dct) -> Self:
return cls(name, bases, dct)
```
## Explicit annotations override implicit `Self`

View File

@@ -271,7 +271,7 @@ def f[T](x: T) -> list[T]:
class A:
def __new__(cls, value: list[int | str]):
return super().__new__(cls, value)
return super().__new__(cls)
def __init__(self, value: list[int | None]): ...

View File

@@ -76,7 +76,7 @@ from typing_extensions import Self
class Base:
def __new__(cls, x: int) -> Self:
return cls()
return cls(x)
class Foo(Base): ...

View File

@@ -101,7 +101,7 @@ use crate::types::diagnostic::{
use crate::types::enums::is_enum_class_by_inheritance;
use crate::types::function::{
FunctionDecorators, FunctionLiteral, FunctionType, KnownFunction, OverloadLiteral,
is_implicit_classmethod, is_implicit_staticmethod,
is_implicit_classmethod,
};
use crate::types::generics::{
GenericContext, InferableTypeVars, LegacyGenericBase, SpecializationBuilder, bind_typevar,
@@ -2915,10 +2915,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let function_node = function_definition.node(self.module());
let function_name = &function_node.name;
if is_implicit_staticmethod(function_name) {
return None;
}
let mut is_classmethod = is_implicit_classmethod(function_name);
let inference = infer_definition_types(db, method_definition);
for decorator in &function_node.decorator_list {
@@ -2942,7 +2938,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
.as_class_literal()?;
let typing_self = typing_self(db, self.scope(), Some(method_definition), class_literal);
if is_classmethod {
if is_classmethod || function_name == "__new__" {
typing_self
.map(|typing_self| SubclassOfType::from(db, SubclassOfInner::TypeVar(typing_self)))
} else {