@@ -447,3 +447,114 @@ def test_complex_not_folded(source, expected):
447447 pytest .skip ('Complex subtraction representation differs in Python 2' )
448448
449449 run_test (source , expected )
450+
451+
452+ @pytest .mark .parametrize (
453+ ('source' , 'expected' ), [
454+ # These fold because the result is 0j or the folded form is shorter
455+ ('-3j + 3j' , '0j' ),
456+ ('1j + -1j' , '0j' ),
457+ ]
458+ )
459+ def test_negative_complex_in_binop_folded (source , expected ):
460+ """
461+ Test that negative complex numbers (UnaryOp USub on complex) participate in BinOp folding.
462+ """
463+ if sys .version_info < (3 , 0 ):
464+ pytest .skip ('Complex number representation differs in Python 2' )
465+
466+ run_test (source , expected )
467+
468+
469+ @pytest .mark .parametrize (
470+ ('source' , 'expected' ), [
471+ ('-3j + 1j' , '-3j+1j' ),
472+ ('-5j * 2' , '-5j*2' ),
473+ ('2 * -5j' , '2*-5j' ),
474+ ('-10j + 5j' , '-10j+5j' ),
475+ ]
476+ )
477+ def test_negative_complex_in_binop_not_folded (source , expected ):
478+ """
479+ Test that some negative complex operations don't fold due to representation issues.
480+
481+ When negating a pure imaginary number like -2j, Python represents -(-2j) as (-0+2j),
482+ which makes the folded form longer than the original expression.
483+ """
484+ if sys .version_info < (3 , 0 ):
485+ pytest .skip ('Complex number representation differs in Python 2' )
486+
487+ run_test (source , expected )
488+
489+
490+ @pytest .mark .parametrize (
491+ ('source' , 'expected' ), [
492+ ('~0 + 1' , '0' ),
493+ ('~5 & 0xff' , '250' ),
494+ ('~0 | 5' , '-1' ), # -1 in binary is all 1s, so -1 | x = -1
495+ ('1 + ~0' , '0' ),
496+ ('~1 + 2' , '0' ),
497+ ('~0xff & 0xff' , '0' ),
498+ ]
499+ )
500+ def test_invert_in_binop (source , expected ):
501+ """
502+ Test that bitwise invert (UnaryOp Invert) participates in BinOp folding.
503+ """
504+ run_test (source , expected )
505+
506+
507+ @pytest .mark .parametrize (
508+ ('source' , 'expected' ), [
509+ ('~0' , '~0' ),
510+ ('~1' , '~1' ),
511+ ('~5' , '~5' ),
512+ ('~255' , '~255' ),
513+ ]
514+ )
515+ def test_invert_not_folded (source , expected ):
516+ """
517+ Test that simple bitwise invert on literals is not folded when the result is not shorter.
518+
519+ ~0 = -1, ~1 = -2, ~5 = -6, etc. These are the same length or longer.
520+ """
521+ run_test (source , expected )
522+
523+
524+ @pytest .mark .parametrize (
525+ ('source' , 'expected' ), [
526+ ('~~0' , '0' ),
527+ ('~~5' , '5' ),
528+ ('~~~0' , '~0' ),
529+ ('~~~~5' , '5' ),
530+ ]
531+ )
532+ def test_double_invert_folded (source , expected ):
533+ """
534+ Test that double bitwise invert is folded.
535+
536+ ~~x = x, so double invert should fold away.
537+ """
538+ run_test (source , expected )
539+
540+
541+ @pytest .mark .parametrize (
542+ ('source' , 'expected' ), [
543+ # In Python, True == 1 and False == 0 for arithmetic
544+ ('-5 + True' , '-4' ),
545+ ('10 * False' , '0' ),
546+ ('True + True' , '2' ),
547+ ('~True' , '-2' ), # ~1 = -2, shorter than ~True
548+ ('~False' , '-1' ), # ~0 = -1, shorter than ~False
549+ ]
550+ )
551+ def test_mixed_numeric_bool_folded (source , expected ):
552+ """
553+ Test folding of expressions mixing numeric and boolean operands.
554+
555+ Python treats True as 1 and False as 0 in numeric contexts.
556+ """
557+ if sys .version_info < (3 , 4 ):
558+ pytest .skip ('NameConstant not in python < 3.4' )
559+
560+ run_test (source , expected )
0 commit comments