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

Code before:
                // Mapping base class types is used for normalization and applying type mappings,
                // neither of which have any effect on `float` or `complex` (which are already
                // fully normalized and non-generic), so we don't need to bother calling `f`.
                NewTypeBase::Float | NewTypeBase::Complex => {}
            }
        }
        // If we get here, there is no `ClassType` (because this newtype is either float/complex or
        // cyclic), and we don't call `f` at all.
        Some(self)
    }

    pub(crate) fn map_base_class_type(
        self,
        db: &'db dyn Db,
        f: impl FnOnce(ClassType<'db>) -> ClassType<'db>,
    ) -> Self {
        self.try_map_base_class_type(db, |class_type| Some(f(class_type)))
            .unwrap()
    }

    pub(crate) fn base_is_union(self, db: &'db dyn Db) -> bool {
        match self.base(db) {
            NewTypeBase::ClassType(_) | NewTypeBase::NewType(_) => false,
            NewTypeBase::Float | NewTypeBase::Complex => true,
        }
    }
}

pub(crate) fn walk_newtype_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
    db: &'db dyn Db,
    newtype: NewType<'db>,
    visitor: &V,
) {
    visitor.visit_type(db, newtype.base(db).instance_type(db));
}

/// `typing.NewType` typically wraps a class type, but it can also wrap another newtype.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize, salsa::Update)]
pub enum NewTypeBase<'db> {
    ClassType(ClassType<'db>),
    NewType(NewType<'db>),
    // `float` and `complex` are special-cased in type position, where they refer to `int | float`
    // and `int | float | complex` respectively. As an extension of that special case, we allow
    // them in `NewType` bases, even though unions and other typing constructs normally aren't
    // allowed.
    Float,
    Complex,
}

impl<'db> NewTypeBase<'db> {
    pub fn instance_type(self, db: &'db dyn Db) -> Type<'db> {

Review comment (refactor):
The issue with this helper is that it only inspected the immediate base type, as opposed to traversing all the way to the concrete (non-new-type) base. This is unlikely to be what any caller really wants.

Code after:
                // Mapping base class types is used for normalization and applying type mappings,
                // neither of which have any effect on `float` or `complex` (which are already
                // fully normalized and non-generic), so we don't need to bother calling `f`.
                NewTypeBase::Float | NewTypeBase::Complex => {}
            }
        }
        // If we get here, there is no `ClassType` (because this newtype is either float/complex or
        // cyclic), and we don't call `f` at all.
        Some(self)
    }

    pub(crate) fn map_base_class_type(
        self,
        db: &'db dyn Db,
        f: impl FnOnce(ClassType<'db>) -> ClassType<'db>,
    ) -> Self {
        self.try_map_base_class_type(db, |class_type| Some(f(class_type)))
            .unwrap()
    }
}

pub(crate) fn walk_newtype_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
    db: &'db dyn Db,
    newtype: NewType<'db>,
    visitor: &V,
) {
    visitor.visit_type(db, newtype.base(db).instance_type(db));
}

/// `typing.NewType` typically wraps a class type, but it can also wrap another newtype.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize, salsa::Update)]
pub enum NewTypeBase<'db> {
    ClassType(ClassType<'db>),
    NewType(NewType<'db>),
    // `float` and `complex` are special-cased in type position, where they refer to `int | float`
    // and `int | float | complex` respectively. As an extension of that special case, we allow
    // them in `NewType` bases, even though unions and other typing constructs normally aren't
    // allowed.
    Float,
    Complex,
}

impl<'db> NewTypeBase<'db> {
    pub fn instance_type(self, db: &'db dyn Db) -> Type<'db> {
        match self {
            NewTypeBase::ClassType(class_type) => Type::instance(db, class_type),
            NewTypeBase::NewType(newtype) => Type::NewTypeInstance(newtype),
            NewTypeBase::Float => KnownUnion::Float.to_type(db),
            NewTypeBase::Complex => KnownUnion::Complex.to_type(db),
        }
    }