Skip to content

math.ldexp() rejects an x that defines __float__ or __index__ #9508

Closed

Description

@jseop-lim

Feature

math.ldexp(x, i) raises TypeError in RustPython when x is neither a float nor an int, but CPython converts x with __float__ or __index__ like every other math function.

Reproduction

import math

class F:
    def __float__(self):
        return 1.5

print(math.ldexp(F(), 1))

RustPython:

TypeError: unexpected type F

CPython:

3.0

The same TypeError comes from an x with only __index__, from fractions.Fraction(1, 2), and from an x whose __float__ raises, where CPython propagates that exception instead.

Root cause

LdexpArgs binds x as Either<PyRef<PyFloat>, PyIntRef>, so only exact float and int payloads pass and Either::try_from_object turns everything else into unexpected type. CPython's math_ldexp converts x with PyFloat_AsDouble, which calls __float__ and then __index__.

Fix

Read a float instance directly and convert anything else with ArgIntoFloat, which raises OverflowError for an int too large for a float, so the try_bigint_to_f64 branch goes away. ArgIntoFloat on its own would call __float__ on a float subclass, which PyFloat_AsDouble does not.

Environment

  • RustPython 713e14c (0.6.1, Python 3.15.0a, macOS arm64), also reproduced on 0.4.0 (Debian 12)
  • CPython v3.15.2, also v3.14.4 and v3.12.10 (macOS arm64)

Python Documentation or reference to CPython source code

  • CPython math_ldexp: Modules/clinic/mathmodule.c.h#L257-L266 converts a non-float x with PyFloat_AsDouble:

    if (PyFloat_CheckExact(args[0])) {
        x = PyFloat_AS_DOUBLE(args[0]);
    }
    else
    {
        x = PyFloat_AsDouble(args[0]);
        if (x == -1.0 && PyErr_Occurred()) {
            goto exit;
        }
    }
  • Documentation: math.ldexp

AI disclosure: this report was drafted with Claude Code (claude-opus-5-5) and reviewed by me before submission. The divergence was found by differential testing against CPython and checked against CPython 3.15.2, and every source reference above was checked against the linked revisions.

Activity

  1. added
    C-compatA discrepancy between RustPython and CPython
    on Nov 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-compatA discrepancy between RustPython and CPython

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions