Repository: numpy/numpy
File: numpy/_core/src/umath/dispatching.cpp (C++)

Code before:
             */
            Py_INCREF(signature[i]);
            Py_XSETREF(op_dtypes[i], signature[i]);
            assert(i >= ufunc->nin || !NPY_DT_is_abstract(signature[i]));
        }
        else if (i >= nin) {
            /*
             * We currently just ignore outputs if not in signature, this will
             * always give the/a correct result (limits registering specialized
             * loops which include the cast).
             * (See also comment in resolve_implementation_info.)
             */
            Py_CLEAR(op_dtypes[i]);
        }
        /*
         * If the op_dtype ends up being a non-legacy one, then we cannot use
         * legacy promotion (unless this is a python scalar).
         */
        if (op_dtypes[i] != NULL && !NPY_DT_is_legacy(op_dtypes[i]) && (
                signature[i] != NULL ||  // signature cannot be a pyscalar
                !(PyArray_FLAGS(ops[i]) & NPY_ARRAY_WAS_PYTHON_LITERAL))) {
            legacy_promotion_is_possible = NPY_FALSE;
        }
    }

    PyObject *info = try_promote_and_get_info_and_ufuncimpl(ufunc,
            ops, signature, op_dtypes, legacy_promotion_is_possible);

    if (info == NULL) {
        goto handle_error;
    }

    method = (PyArrayMethodObject *)PyTuple_GET_ITEM(info, 1);
    all_dtypes = PyTuple_GET_ITEM(info, 0);

    /*
     * In certain cases (only the logical ufuncs really), the loop we found may
     * not be reduce-compatible.  Since the machinery can't distinguish a
     * reduction with an output from a normal ufunc call, we have to assume
     * the result DType is correct and force it for the input (if not forced
     * already).
     * NOTE: This does assume that all loops are "safe" see the NOTE in this
     *       comment.  That could be relaxed, in which case we may need to
     *       cache if a call was for a reduction.
     */
    if (ensure_reduce_compatible && signature[0] == NULL &&
            PyTuple_GET_ITEM(all_dtypes, 0) != PyTuple_GET_ITEM(all_dtypes, 2)) {
        signature[0] = (PyArray_DTypeMeta *)PyTuple_GET_ITEM(all_dtypes, 2);
        Py_INCREF(signature[0]);
        return promote_and_get_ufuncimpl(ufunc,
                ops, signature, op_dtypes,

Review comment (suggestion):
I could also make it so this function only gets called on the GIL-disabled build, which might be slightly faster on the GIL-enabled build

Code after:
            /*
             * We currently just ignore outputs if not in signature, this will
             * always give the/a correct result (limits registering specialized
             * loops which include the cast).
             * (See also comment in resolve_implementation_info.)
             */
            Py_CLEAR(op_dtypes[i]);
        }
        /*
         * If the op_dtype ends up being a non-legacy one, then we cannot use
         * legacy promotion (unless this is a python scalar).
         */
        if (op_dtypes[i] != NULL && !NPY_DT_is_legacy(op_dtypes[i]) && (
                signature[i] != NULL ||  // signature cannot be a pyscalar
                !(PyArray_FLAGS(ops[i]) & NPY_ARRAY_WAS_PYTHON_LITERAL))) {
            legacy_promotion_is_possible = NPY_FALSE;
        }
    }

#ifdef Py_GIL_DISABLED
    PyObject *info = promote_and_get_info_and_ufuncimpl_with_locking(ufunc,
            ops, signature, op_dtypes, legacy_promotion_is_possible);
#else
    PyObject *info = promote_and_get_info_and_ufuncimpl(ufunc,
            ops, signature, op_dtypes, legacy_promotion_is_possible);
#endif

    if (info == NULL) {
        goto handle_error;
    }

    method = (PyArrayMethodObject *)PyTuple_GET_ITEM(info, 1);
    all_dtypes = PyTuple_GET_ITEM(info, 0);

    /*
     * In certain cases (only the logical ufuncs really), the loop we found may
     * not be reduce-compatible.  Since the machinery can't distinguish a
     * reduction with an output from a normal ufunc call, we have to assume
     * the result DType is correct and force it for the input (if not forced
     * already).
     * NOTE: This does assume that all loops are "safe" see the NOTE in this
     *       comment.  That could be relaxed, in which case we may need to
     *       cache if a call was for a reduction.
     */
    if (ensure_reduce_compatible && signature[0] == NULL &&
            PyTuple_GET_ITEM(all_dtypes, 0) != PyTuple_GET_ITEM(all_dtypes, 2)) {
        signature[0] = (PyArray_DTypeMeta *)PyTuple_GET_ITEM(all_dtypes, 2);
        Py_INCREF(signature[0]);
        return promote_and_get_ufuncimpl(ufunc,
                ops, signature, op_dtypes,
                force_legacy_promotion,