Skip to content

Commit 089213e

Browse files
wanda-phiwhitequark
authored andcommitted
Implement RFC 46: Change Shape.cast(range(1)) to unsigned(0).
1 parent 1fe7bd0 commit 089213e

File tree

3 files changed

+12
-4
lines changed

3 files changed

+12
-4
lines changed

amaranth/hdl/_ast.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ def cast(obj, *, src_loc_at=0):
9393
9494
* a :class:`Shape`, where the result is itself;
9595
* an :class:`int`, where the result is :func:`unsigned(obj) <unsigned>`;
96-
* a :class:`range`, where the result is wide enough to represent any element of the range,
97-
and is signed if any element of the range is signed;
96+
* a :class:`range`, where the result has minimal width required to represent all elements
97+
of the range, and is signed if any element of the range is signed;
9898
* an :class:`enum.Enum` whose members are all :ref:`constant-castable <lang-constcasting>`
9999
or :class:`enum.IntEnum`, where the result is wide enough to represent any member of
100100
the enumeration, and is signed if any member of the enumeration is signed;
@@ -121,6 +121,8 @@ def cast(obj, *, src_loc_at=0):
121121
signed = obj[0] < 0 or obj[-1] < 0
122122
width = max(bits_for(obj[0], signed),
123123
bits_for(obj[-1], signed))
124+
if obj[0] == obj[-1] == 0:
125+
width = 0
124126
return Shape(width, signed)
125127
elif isinstance(obj, type) and issubclass(obj, Enum):
126128
# For compatibility with third party enumerations, handle them as if they were

docs/changes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ Implemented RFCs
3636

3737
.. _RFC 17: https://amaranth-lang.org/rfcs/0017-remove-log2-int.html
3838
.. _RFC 39: https://amaranth-lang.org/rfcs/0039-empty-case.html
39+
.. _RFC 46: https://amaranth-lang.org/rfcs/0046-shape-range-1.html
3940

4041
* `RFC 17`_: Remove ``log2_int``
4142
* `RFC 39`_: Change semantics of no-argument ``m.Case()``
43+
* `RFC 46`_: Change ``Shape.cast(range(1))`` to ``unsigned(0)``
4244

4345

4446
Language changes
@@ -52,6 +54,7 @@ Language changes
5254
* Changed: ``Value.matches()`` with no patterns is ``Const(0)`` instead of ``Const(1)``. (`RFC 39`_)
5355
* Changed: ``Signal(range(stop), reset=stop)`` warning has been changed into a hard error and made to trigger on any out-of range value.
5456
* Changed: ``Signal(range(0))`` is now valid without a warning.
57+
* Changed: ``Shape.cast(range(1))`` is now ``unsigned(0)``. (`RFC 46`_)
5558
* Deprecated: :func:`amaranth.utils.log2_int`. (`RFC 17`_)
5659
* Removed: (deprecated in 0.4) :meth:`Const.normalize`. (`RFC 5`_)
5760
* Removed: (deprecated in 0.4) :class:`Repl`. (`RFC 10`_)

tests/test_hdl_ast.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def test_cast_range(self):
115115
self.assertEqual(s3.width, 4)
116116
self.assertEqual(s3.signed, True)
117117
s4 = Shape.cast(range(0, 1))
118-
self.assertEqual(s4.width, 1)
118+
self.assertEqual(s4.width, 0)
119119
self.assertEqual(s4.signed, False)
120120
s5 = Shape.cast(range(-1, 0))
121121
self.assertEqual(s5.width, 1)
@@ -129,6 +129,9 @@ def test_cast_range(self):
129129
s8 = Shape.cast(range(0, 10, 3))
130130
self.assertEqual(s8.width, 4)
131131
self.assertEqual(s8.signed, False)
132+
s9 = Shape.cast(range(0, 3, 3))
133+
self.assertEqual(s9.width, 0)
134+
self.assertEqual(s9.signed, False)
132135

133136
def test_cast_enum(self):
134137
s1 = Shape.cast(UnsignedEnum)
@@ -1088,7 +1091,7 @@ def test_shape(self):
10881091
s10 = Signal(range(0))
10891092
self.assertEqual(s10.shape(), unsigned(0))
10901093
s11 = Signal(range(1))
1091-
self.assertEqual(s11.shape(), unsigned(1))
1094+
self.assertEqual(s11.shape(), unsigned(0))
10921095

10931096
def test_shape_wrong(self):
10941097
with self.assertRaisesRegex(TypeError,

0 commit comments

Comments
 (0)