Repository: numpy/numpy
File: numpy/_core/src/multiarray/methods.c (C)

Code before:
                &PyArray_Type,
                PyArray_DESCR(self),
                PyArray_NDIM(self),
                PyArray_DIMS(self),
                PyArray_STRIDES(self),
                PyArray_DATA(self),
                PyArray_FLAGS(self),
                NULL,
                (PyObject *)self
        );
        if (new == NULL) {
            Py_XDECREF(newtype);
            return NULL;
        }
        self = new;
    }
    else {
        Py_INCREF(self);
    }

    if (copy == NPY_COPY_ALWAYS) {
        if (newtype == NULL) {
            newtype = PyArray_DESCR(self);
            // Take a new strong reference to compensate for
            // PyArray_CastToType stealing a reference to newtype.
            Py_INCREF(newtype);
        }
        ret = PyArray_CastToType(self, newtype, 0);
        Py_DECREF(self);
        return ret;
    } else { // copy == NPY_COPY_IF_NEEDED || copy == NPY_COPY_NEVER
        if (newtype == NULL || PyArray_EquivTypes(PyArray_DESCR(self), newtype)) {
            // If newtype isn't NULL then release a strong reference
            // introduced by PyArray_DescrConverter2 in arg parsing.
            Py_XDECREF(newtype);
            return (PyObject *)self;
        }
        if (copy == NPY_COPY_IF_NEEDED) {
            ret = PyArray_CastToType(self, newtype, 0);
            Py_DECREF(self);
            return ret;
        } else { // copy == NPY_COPY_NEVER
            PyErr_SetString(PyExc_ValueError, npy_no_copy_err_msg);
            // On error release a strong reference introduced by
            // PyArray_DescrConverter2 in arg parsing.
            Py_DECREF(newtype);
            Py_DECREF(self);
            return NULL;
        }
    }
}

Review comment (suggestion):
```suggestion
            Py_INCREF(newtype);  // newtype is owned.
```
Maybe. I don't like the overly long comments, TBH.

We could add a comment on all `CastToType` calls that it steals the reference, though.

Code after:
    if (!PyArray_CheckExact(self)) {
        PyArrayObject *new;

        Py_INCREF(PyArray_DESCR(self));
        new = (PyArrayObject *)PyArray_NewFromDescrAndBase(
                &PyArray_Type,
                PyArray_DESCR(self),
                PyArray_NDIM(self),
                PyArray_DIMS(self),
                PyArray_STRIDES(self),
                PyArray_DATA(self),
                PyArray_FLAGS(self),
                NULL,
                (PyObject *)self
        );
        if (new == NULL) {
            Py_DECREF(newtype);
            return NULL;
        }
        self = new;
    }
    else {
        Py_INCREF(self);
    }

    if (copy == NPY_COPY_ALWAYS) {
        ret = PyArray_CastToType(self, newtype, 0);  // steals newtype reference
        Py_DECREF(self);
        return ret;
    } else { // copy == NPY_COPY_IF_NEEDED || copy == NPY_COPY_NEVER
        if (PyArray_EquivTypes(PyArray_DESCR(self), newtype)) {
            Py_DECREF(newtype);
            return (PyObject *)self;
        }
        if (copy == NPY_COPY_IF_NEEDED) {
            ret = PyArray_CastToType(self, newtype, 0);  // steals newtype reference.
            Py_DECREF(self);
            return ret;
        } else { // copy == NPY_COPY_NEVER
            PyErr_SetString(PyExc_ValueError, npy_no_copy_err_msg);
            Py_DECREF(newtype);
            Py_DECREF(self);
            return NULL;
        }
    }
}

/*
 * Check whether any of the input and output args have a non-default
 * __array_ufunc__ method. Return 1 if so, 0 if not, and -1 on error.
 *