Skip to content

Fix complex(real, imag) converting imag before checking real - #1230

Open
jseop-lim wants to merge 1 commit into
oracle:masterfrom
jseop-lim:GH-1225-complex-arg-order
Open

jseop-lim wants to merge 1 commit into
oracle:masterfrom
jseop-lim:GH-1225-complex-arg-order

Conversation

@jseop-lim

Copy link
Copy Markdown
Contributor

Description

Fixes #1225

When imag is neither a complex nor a string, complex(real, imag) called imag.__float__ before checking that real is a number, so an exception from that call replaced the first-argument TypeError. CPython's complex_new_impl checks the type of real, then of imag, and only then converts real followed by imag (complexobject.c#L945-L1018).

AS-IS

>>> complex({}, RaisingImag())         # RaisingImag.__float__ raises RuntimeError
RuntimeError
>>> complex(RaisingReal(), RaisingImag())  # RaisingReal.__float__ raises KeyError
RuntimeError
>>> complex({}, {})
TypeError: complex() second argument must be a number, not 'dict'

TO-BE

>>> complex({}, RaisingImag())
TypeError: complex() first argument must be a string or a number, not 'dict'
>>> complex(RaisingReal(), RaisingImag())
KeyError
>>> complex({}, {})
TypeError: complex() first argument must be a string or a number, not 'dict'

(matching CPython)

Changes

  • Reorder ComplexNewNode.complexFromComplexObject to raise the first-argument error, then the second-argument error, and only then convert real and imag in that order. The other (Object, long|double|PInt) specializations already check real first.
  • Add test_create_checks_arguments_before_converting to tests/test_complex.py.

Testing

mx python-jvm on linux-aarch64, then mx graalpytest test_complex.py (11 passed) and test.test_complex from lib-python (35 passed, same as master). The new test fails on the unpatched build. Twelve complex() call shapes, covering __float__, __index__ and __complex__ arguments and imag= alone, now print the same as CPython 3.12.13.

complexFromComplexObject, the specialization taken when imag is
neither a complex nor a string, called imag's __float__ before it
looked at real, so an exception from that conversion replaced the
first-argument TypeError and complex(Real(), Imag()) converted imag
first.

CPython's complex_new_impl checks the type of real, then of imag, and
only then converts real followed by imag. The specialization now does
the same; the (Object, long/double/PInt) specializations already
check real first.

Signed-off-by: Jeongseop Lim <jeongseop_lim@korea.ac.kr>
@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Oct 20, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: complex(real, imag) converts imag before rejecting a non-number real

1 participant