Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/class.rs (Rust)

Code before:
            // Constructor calls to `tuple` and subclasses of `tuple` are handled in
            // `Type::bindings`, but constructor calls to `tuple[int]`, `tuple[int, ...]`,
            // `tuple[int, *tuple[str, ...]]` (etc.) are handled by the default constructor-call
            // logic (we synthesize a `__new__` method for them in `ClassType::own_class_member`).
            self.is_known(db, KnownClass::Tuple) && !self.is_generic()
        ) || CodeGeneratorKind::TypedDict.matches(
            db,
            self.class_literal(db).0,
            self.class_literal(db).1,
        );

        // Use regular `try_call` for all subclasses of `enum.Enum`. This is a temporary
        // special-casing until we support the functional syntax for creating enum classes.
        let is_enum_subclass = KnownClass::Enum
            .to_class_literal(db)
            .to_class_type(db)
            .is_some_and(|enum_class| self.is_subclass_of(db, enum_class));

        // Use regular `try_call` for `typing._SpecialForm` and its subclasses. The typeshed
        // stub for `_SpecialForm` doesn't include `__init__`, but the runtime implementation
        // does accept a callable. Classes like `typing_extensions._ExtensionsSpecialForm`
        // inherit from `_SpecialForm` and are used as decorators.
        let is_special_form_subclass = KnownClass::SpecialForm
            .to_class_literal(db)
            .to_class_type(db)
            .is_some_and(|special_form_class| self.is_subclass_of(db, special_form_class));

        !has_special_cased_constructor && !is_enum_subclass && !is_special_form_subclass
    }
}

fn into_callable_cycle_initial<'db>(
    db: &'db dyn Db,
    _id: salsa::Id,
    _self: ClassType<'db>,
) -> CallableTypes<'db> {
    CallableTypes::one(CallableType::bottom(db))
}

impl<'db> From<GenericAlias<'db>> for ClassType<'db> {
    fn from(generic: GenericAlias<'db>) -> ClassType<'db> {
        ClassType::Generic(generic)
    }
}

impl<'db> From<ClassType<'db>> for Type<'db> {
    fn from(class: ClassType<'db>) -> Type<'db> {
        match class {
            ClassType::NonGeneric(non_generic) => non_generic.into(),
            ClassType::Generic(generic) => generic.into(),
        }

Review comment (bug):
I suspect this is wrong... But setuptools defines:

https://github.com/pypa/setuptools/blob/d198e86f57231e83de87975c5c82bc40c196da79/setuptools/_vendor/typing_extensions.py#L210

Then uses it as a decorator:

https://github.com/pypa/setuptools/blob/d198e86f57231e83de87975c5c82bc40c196da79/setuptools/_vendor/typing_extensions.py#L2168

It _does_ have an `__init__` at runtime:

https://github.com/python/cpython/blob/c99f7667436d8978b4077704333e2a351f2a026f/Lib/typing.py#L544

But not in the typeshed definition.


Code after:

        match name {
            "__len__" if class_literal.is_tuple(db) => {
                let return_type = specialization
                    .and_then(|spec| spec.tuple(db))
                    .and_then(|tuple| tuple.len().into_fixed_length())
                    .and_then(|len| i64::try_from(len).ok())
                    .map(Type::IntLiteral)
                    .unwrap_or_else(|| KnownClass::Int.to_instance(db));

                let parameters = Parameters::new(
                    db,
                    [Parameter::positional_only(Some(Name::new_static("self")))
                        .with_annotated_type(Type::instance(db, self))],
                );

                let synthesized_dunder_method =
                    Type::function_like_callable(db, Signature::new(parameters, return_type));

                Member::definitely_declared(synthesized_dunder_method)
            }

            "__getitem__" if class_literal.is_tuple(db) => {
                specialization
                    .and_then(|spec| spec.tuple(db))
                    .map(|tuple| {
                        let mut element_type_to_indices: FxIndexMap<Type<'db>, Vec<i64>> =
                            FxIndexMap::default();

                        match tuple {
                            // E.g. for `tuple[int, str]`, we will generate the following overloads:
                            //
                            //    __getitem__(self, index: Literal[0, -2], /) -> int
                            //    __getitem__(self, index: Literal[1, -1], /) -> str
                            //
                            TupleSpec::Fixed(fixed_length_tuple) => {
                                let tuple_length = fixed_length_tuple.len();

                                for (index, ty) in
                                    fixed_length_tuple.iter_all_elements().enumerate()
                                {
                                    let entry = element_type_to_indices.entry(ty).or_default();
                                    if let Ok(index) = i64::try_from(index) {
                                        entry.push(index);
                                    }
                                    if let Ok(index) = i64::try_from(tuple_length - index) {
                                        entry.push(0 - index);
                                    }
                                }
                            }