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

Code before:
    where
        I: IntoIterator<Item = T>,
        T: Into<Type<'db>>,
    {
        Type::tuple(TupleType::heterogeneous(
            db,
            elements.into_iter().map(Into::into),
        ))
    }

    pub(crate) fn empty_tuple(db: &'db dyn Db) -> Self {
        Type::tuple_instance(TupleType::empty(db))
    }

    /// **Private** helper function to create a `Type::NominalInstance` from a tuple.
    fn tuple_instance(tuple: TupleType<'db>) -> Self {
        Type::NominalInstance(NominalInstanceType(NominalInstanceInner::ExactTuple(tuple)))
    }

    pub(crate) const fn is_nominal_instance(self) -> bool {
        matches!(self, Type::NominalInstance(_))
    }

    /// Returns whether the definition of this type is generic
    /// (this is different from whether this type *is* a generic type; a type that is already fully specialized is not a generic type).
    pub(crate) fn is_definition_generic(self, db: &'db dyn Db) -> bool {
        match self {
            Type::Union(union) => union
                .elements(db)
                .iter()
                .any(|ty| ty.is_definition_generic(db)),
            Type::Intersection(intersection) => {
                intersection
                    .positive(db)
                    .iter()
                    .any(|ty| ty.is_definition_generic(db))
                    || intersection
                        .negative(db)
                        .iter()
                        .any(|ty| ty.is_definition_generic(db))
            }
            Type::NominalInstance(instance_type) => match instance_type.0 {
                NominalInstanceInner::NonTuple(class) => class.is_generic(),
                NominalInstanceInner::ExactTuple(_) => true,
                NominalInstanceInner::Object => false,
            },
            Type::ProtocolInstance(protocol) => {
                matches!(protocol.inner, Protocol::FromClass(class) if class.is_generic())
            }
            Type::TypedDict(typed_dict) => typed_dict.defining_class().is_generic(),
            Type::Dynamic(dynamic) => {

Review comment (suggestion):
This method no longer seems like it belongs in `instance.rs`; it's not specific to `Type::NominalInstance` anymore

Code after:
    where
        I: IntoIterator<Item = T>,
        T: Into<Type<'db>>,
    {
        Type::tuple(TupleType::heterogeneous(
            db,
            elements.into_iter().map(Into::into),
        ))
    }

    pub(crate) fn empty_tuple(db: &'db dyn Db) -> Self {
        Type::tuple_instance(TupleType::empty(db))
    }

    /// **Private** helper function to create a `Type::NominalInstance` from a tuple.
    fn tuple_instance(tuple: TupleType<'db>) -> Self {
        Type::NominalInstance(NominalInstanceType(NominalInstanceInner::ExactTuple(tuple)))
    }

    pub(crate) const fn is_nominal_instance(self) -> bool {
        matches!(self, Type::NominalInstance(_))
    }

    pub(crate) const fn as_nominal_instance(self) -> Option<NominalInstanceType<'db>> {
        match self {
            Type::NominalInstance(instance_type) => Some(instance_type),
            _ => None,
        }
    }

    /// Return `true` if `self` is a nominal instance of the given known class.
    pub(crate) fn is_instance_of(self, db: &'db dyn Db, known_class: KnownClass) -> bool {
        match self {
            Type::NominalInstance(instance) => instance.class(db).is_known(db, known_class),
            _ => false,
        }
    }

    /// Synthesize a protocol instance type with a given set of read-only property members.
    pub(super) fn protocol_with_readonly_members<'a, M>(db: &'db dyn Db, members: M) -> Self
    where
        M: IntoIterator<Item = (&'a str, Type<'db>)>,
    {
        Self::ProtocolInstance(ProtocolInstanceType::synthesized(
            SynthesizedProtocolType::new(
                db,
                ProtocolInterface::with_property_members(db, members),
                &NormalizedVisitor::default(),
            ),
        ))
    }