From 74c02d416eaefe3fb84bdada9110ed98c303c0fd Mon Sep 17 00:00:00 2001 From: ichyo Date: Thu, 24 Oct 2019 00:26:02 +0900 Subject: [PATCH] Fix wrong const optimization for "1.0 / 0.0" case In cpython, "1.0 / 0.0" raises ZeroDivisionError ``` >>> 1.0 / 0.0 Traceback (most recent call last): File "", line 1, in ZeroDivisionError: float division by zer ``` but RustPython doesn't ``` >>>>> 1.0 / 0.0 inf ``` This is because they emits different byte codes. ``` $ echo "1.0 / 0.0" > zero-div.py $ python -m dis zero-div.py 1 0 LOAD_CONST 0 (1.0) 2 LOAD_CONST 1 (0.0) 4 BINARY_TRUE_DIVIDE 6 POP_TOP 8 LOAD_CONST 2 (None) 10 RETURN_VALUE $ cargo run --example dis zero-div.py zero-div.py: 0 LoadConst (inf) 1 Pop 2 LoadConst (None) 3 ReturnValue ``` This commit stops optimization for zero division case to generate same byte codes. --- compiler/src/peephole/optimizations.rs | 2 +- tests/snippets/floats.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/src/peephole/optimizations.rs b/compiler/src/peephole/optimizations.rs index b0fb7531a..28bac862c 100644 --- a/compiler/src/peephole/optimizations.rs +++ b/compiler/src/peephole/optimizations.rs @@ -52,7 +52,7 @@ pub fn operator(buf: &mut impl OptimizationBuffer) { (op!(Multiply), lc!(Float, lhs), lc!(Float, rhs)) => { emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs * rhs) } - (op!(Divide), lc!(Float, lhs), lc!(Float, rhs)) => { + (op!(Divide), lc!(Float, lhs), lc!(Float, rhs)) if rhs != 0.0 => { emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs / rhs) } (op!(Power), lc!(Float, lhs), lc!(Float, rhs)) => { diff --git a/tests/snippets/floats.py b/tests/snippets/floats.py index aa17bd87d..0e585c476 100644 --- a/tests/snippets/floats.py +++ b/tests/snippets/floats.py @@ -144,6 +144,10 @@ assert_raises(ZeroDivisionError, lambda: 2 / 0.0) assert_raises(ZeroDivisionError, lambda: 2 // 0.0) assert_raises(ZeroDivisionError, lambda: 2 % 0.0) # assert_raises(ZeroDivisionError, divmod, 2, 0.0) +assert_raises(ZeroDivisionError, lambda: 2.0 / 0.0) +assert_raises(ZeroDivisionError, lambda: 2.0 // 0.0) +assert_raises(ZeroDivisionError, lambda: 2.0 % 0.0) +assert_raises(ZeroDivisionError, divmod, 2.0, 0.0) assert 1.2.__int__() == 1 assert 1.2.__float__() == 1.2