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

Code before:
            )
            .then_some(i)
        })
        .collect();
    if indices.len() != 1 {
        return None;
    }
    let resolved_index = resolved_bases
        .iter()
        .position(|base| matches!(base, ClassBase::Generic))?;
    if resolved_index == resolved_bases.len() - 1 {
        return None;
    }
    let mut reordered = resolved_bases.to_vec();
    let generic = reordered.remove(resolved_index);
    reordered.push(generic);
    let mut seqs: Vec<VecDeque<ClassBase<'db>>> = Vec::with_capacity(reordered.len() + 1);
    for base in &reordered {
        if base.has_cyclic_mro(db) {
            return None;
        }
        seqs.push(base.mro(db, None).collect());
    }
    seqs.push(reordered.iter().copied().collect());
    c3_merge(seqs)?;
    Some(indices[0])
}

/// Error for dynamic class MRO computation with fallback MRO.
///
/// Separate from [`StaticMroError`] because dynamic classes can only have a subset of MRO errors.
#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize, salsa::Update)]
pub(crate) struct DynamicMroError<'db> {
    kind: DynamicMroErrorKind<'db>,
    fallback_mro: Mro<'db>,
}

impl<'db> DynamicMroError<'db> {
    /// Return the error kind describing why we could not resolve the MRO.
    pub(crate) fn reason(&self) -> &DynamicMroErrorKind<'db> {
        &self.kind
    }

    /// Return the fallback MRO to use for type inference.
    pub(crate) fn fallback_mro(&self) -> &Mro<'db> {
        &self.fallback_mro
    }
}

/// Error kinds for dynamic class MRO computation.
///

Review comment (suggestion):
This suggestion requires adding an import of `itertools::Itertools` to the top of the file so that we can use the `.exactly_one()` method

```suggestion
    // Only attempt an autofix if `Generic[]` appears exactly once in the original bases list.
    let single_index = original_bases
        .iter()
        .enumerate()
        .filter_map(|(i, base)| {
            matches!(
                base,
                Type::KnownInstance(KnownInstanceType::SubscriptedGeneric(_))
            )
            .then_some(i)
        })
        .exactly_one()
        .ok()?;

    // This should always be true if the original bases list contains exactly one
    // subscripted `Generic`, but return `None` here just to be safe.
    if resolved_bases.get(single_index) != Some(&ClassBase::Generic) {
        return None;
    }

    let mut reordered: VecDeque<ClassBase<'db>> = resolved_bases.iter().copied().collect();
    let generic = reordered.remove(single_index)?;
    reordered.push_back(generic);
    let mut seqs: Vec<VecDeque<ClassBase<'db>>> = Vec::with_capacity(reordered.len() + 1);
    for base in &reordered {
        if base.has_cyclic_mro(db) {
            return None;
        }
        seqs.push(base.mro(db, None).collect());
    }
    seqs.push(reordered);
    c3_merge(seqs)?;
    Some(single_index)
```

Code after:
    db: &'db dyn Db,
    resolved_bases: &[ClassBase<'db>],
    original_bases: &[Type<'db>],
) -> Option<usize> {
    // Only attempt an autofix if `Generic[]` appears exactly once in the original bases list.
    let single_index = original_bases
        .iter()
        .enumerate()
        .filter_map(|(i, base)| {
            matches!(
                base,
                Type::KnownInstance(KnownInstanceType::SubscriptedGeneric(_))
            )
            .then_some(i)
        })
        .exactly_one()
        .ok()?;

    // This should always be true if the original bases list contains exactly one
    // subscripted `Generic`, but return `None` here just to be safe.
    if resolved_bases.get(single_index) != Some(&ClassBase::Generic) {
        return None;
    }

    let mut reordered: VecDeque<ClassBase<'db>> = resolved_bases.iter().copied().collect();
    let generic = reordered.remove(single_index)?;
    reordered.push_back(generic);
    let mut seqs: Vec<VecDeque<ClassBase<'db>>> = Vec::with_capacity(reordered.len() + 1);
    for base in &reordered {
        if base.has_cyclic_mro(db) {
            return None;
        }
        seqs.push(base.mro(db, None).collect());
    }
    seqs.push(reordered);
    c3_merge(seqs)?;
    Some(single_index)
}

/// Error for dynamic class MRO computation with fallback MRO.
///
/// Separate from [`StaticMroError`] because dynamic classes can only have a subset of MRO errors.
#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize, salsa::Update)]
pub(crate) struct DynamicMroError<'db> {
    kind: DynamicMroErrorKind<'db>,
    fallback_mro: Mro<'db>,
}

impl<'db> DynamicMroError<'db> {
    /// Return the error kind describing why we could not resolve the MRO.
    pub(crate) fn reason(&self) -> &DynamicMroErrorKind<'db> {