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

Code before:
                }
                Ok(builder.build())
            };

        let owner = match owner_type {
            Type::Never => SuperOwnerKind::Dynamic(DynamicType::Unknown),
            Type::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic),
            Type::ClassLiteral(class) => SuperOwnerKind::Class(ClassType::NonGeneric(class)),
            Type::SubclassOf(subclass_of_type) => match subclass_of_type.subclass_of() {
                SubclassOfInner::Class(class) => SuperOwnerKind::Class(class),
                SubclassOfInner::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic),
                SubclassOfInner::TypeVar(bound_typevar) => {
                    let typevar = bound_typevar.typevar(db);
                    match typevar.bound_or_constraints(db) {
                        Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
                            let class = match bound {
                                Type::NominalInstance(instance) => Some(instance.class(db)),
                                Type::ProtocolInstance(protocol) => protocol
                                    .to_nominal_instance()
                                    .map(|instance| instance.class(db)),
                                _ => None,
                            };
                            if let Some(class) = class {
                                SuperOwnerKind::ClassTypeVar(bound_typevar, class)
                            } else {
                                return Err(BoundSuperError::AbstractOwnerType {
                                    owner_type,
                                    pivot_class: pivot_class_type,
                                    typevar_context: Some(typevar),
                                });
                            }
                        }
                        Some(TypeVarBoundOrConstraints::Constraints(constraints)) => {
                            return build_constrained_union(
                                constraints,
                                bound_typevar,
                                typevar,
                                SuperOwnerKind::ClassTypeVar,
                            );
                        }
                        None => {
                            // No bound means the implicit upper bound is `object`.
                            SuperOwnerKind::ClassTypeVar(bound_typevar, ClassType::object(db))
                        }
                    }
                }
            },
            Type::NominalInstance(instance) => SuperOwnerKind::Instance(instance),

            Type::ProtocolInstance(protocol) => {
                if let Some(nominal_instance) = protocol.to_nominal_instance() {

Review comment (refactor):
This is not really the right error kind here -- we'll throw this now for typevars with various upper bounds that are not necessarily abstract/structural at all (as in the `type[]` examples you added in the tests), they are just "types we can't extract a class from".

I'm actually wondering if the right thing here is not to error, but to fall back to the behavior from before this PR (where we just delegate to the bound). I think in most(?) cases that we don't handle as `ClassTypeVar`, that will just end up throwing an error later -- but it will be a more accurate error than this one. And if it doesn't throw an error, that means we've got a typevar whose upper bound is actually a valid subclass of the pivot type -- treating such a case as the upper bound at least won't be any worse than our behavior today.

Code after:
                            if let Some(pivot) = pivot_class_literal {
                                if !class.iter_mro(db).any(|superclass| match superclass {
                                    ClassBase::Dynamic(_) => true,
                                    ClassBase::Generic
                                    | ClassBase::Protocol
                                    | ClassBase::TypedDict => false,
                                    ClassBase::Class(superclass) => {
                                        superclass.class_literal(db).0 == pivot
                                    }
                                }) {
                                    return Err(BoundSuperError::FailingConditionCheck {
                                        pivot_class: pivot_class_type,
                                        owner: owner_type,
                                        typevar_context: Some(typevar),
                                    });
                                }
                            }
                            let owner = make_owner(bound_typevar, class);
                            builder = builder.add(Type::BoundSuper(BoundSuperType::new(
                                db,
                                pivot_class,
                                owner,
                            )));
                        }
                        None => {
                            // Delegate to the constraint to get better error messages
                            // if the constraint is incompatible with the pivot class.
                            builder = builder.add(delegate_to(*constraint)?);
                        }
                    }
                }
                Ok(builder.build())
            };

        let owner = match owner_type {
            Type::Never => SuperOwnerKind::Dynamic(DynamicType::Unknown),
            Type::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic),
            Type::ClassLiteral(class) => SuperOwnerKind::Class(ClassType::NonGeneric(class)),
            Type::SubclassOf(subclass_of_type) => match subclass_of_type.subclass_of() {
                SubclassOfInner::Class(class) => SuperOwnerKind::Class(class),
                SubclassOfInner::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic),
                SubclassOfInner::TypeVar(bound_typevar) => {
                    let typevar = bound_typevar.typevar(db);
                    match typevar.bound_or_constraints(db) {
                        Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
                            let class = match bound {
                                Type::NominalInstance(instance) => Some(instance.class(db)),
                                Type::ProtocolInstance(protocol) => protocol
                                    .to_nominal_instance()
                                    .map(|instance| instance.class(db)),
                                _ => None,