From 2e05364117954730fc4d2a3df262db0f87da9c84 Mon Sep 17 00:00:00 2001 From: Jeongseop Lim Date: Thu, 13 Aug 2026 20:27:24 +0900 Subject: [PATCH] Normalize round() result to an exact int (#8511) int.__round__ returned the receiver unchanged on the no-rounding path, so round() on an int subclass handed back an instance of that subclass: round(True) was True, not 1. CPython routes both no-op paths (ndigits is None, and ndigits >= 0) through long_long(), which reuses the reference only when the value is an exact int and otherwise copies it into a fresh one. Return zelf.__int__(vm).into_pyref(), which goes through into_exact_or() and is the same normalization the neighbouring __trunc__, __floor__ and __ceil__ already perform. Assisted-by: Claude Code:claude-opus-5 --- crates/vm/src/builtins/int.rs | 4 +++- extra_tests/snippets/builtin_round.py | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/crates/vm/src/builtins/int.rs b/crates/vm/src/builtins/int.rs index 278a9cecb..c12bf2c72 100644 --- a/crates/vm/src/builtins/int.rs +++ b/crates/vm/src/builtins/int.rs @@ -487,7 +487,9 @@ impl PyInt { return vm.ctx.new_int(rounded); } } - zelf + // No rounding to do, but an int subclass must still be normalized to an + // exact int, the way CPython's long_long() does. + zelf.__int__(vm).into_pyref() } #[pymethod] diff --git a/extra_tests/snippets/builtin_round.py b/extra_tests/snippets/builtin_round.py index e94d97542..83725420a 100644 --- a/extra_tests/snippets/builtin_round.py +++ b/extra_tests/snippets/builtin_round.py @@ -93,3 +93,21 @@ assert math.copysign(1.0, round(0.0, 2)) == 1.0 assert round(1.0, 1000) == 1.0 assert round(1.0, -1000) == 0.0 assert round(1.7976931348623157e308, 0) == 1.7976931348623157e308 + + +# round() normalizes an int subclass to an exact int, like CPython's long_long(). +assert round(True) == 1 +assert type(round(True)) is int +assert type(round(True, 0)) is int +assert type(round(False)) is int + + +class MyInt(int): + pass + + +assert round(MyInt(5)) == 5 +assert type(round(MyInt(5))) is int +assert type(round(MyInt(5), 2)) is int +# A negative ndigits already produced a fresh exact int. +assert type(round(MyInt(15), -1)) is int