Repository: amaranth-lang/amaranth (python)

Issue:
`rotate_*` crashes on 0-width `Value`
```
>>> a = Signal(0)
>>> a.rotate_left(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/mwk/amaranth/amaranth/hdl/ast.py", line 519, in rotate_left
    amount %= len(self)
ZeroDivisionError: integer modulo by zero
```

Pull request description:
hdl.ast: guard `rotate_*` against 0-width values.
Fixes #808.

Patch:
diff --git a/amaranth/hdl/ast.py b/amaranth/hdl/ast.py
index 427293e..cbf2e60 100644
--- a/amaranth/hdl/ast.py
+++ b/amaranth/hdl/ast.py
@@ -516,7 +516,8 @@ class Value(metaclass=ABCMeta):
         """
         if not isinstance(amount, int):
             raise TypeError("Rotate amount must be an integer, not {!r}".format(amount))
-        amount %= len(self)
+        if len(self) != 0:
+            amount %= len(self)
         return Cat(self[-amount:], self[:-amount]) # meow :3
 
     def rotate_right(self, amount):
@@ -534,7 +535,8 @@ class Value(metaclass=ABCMeta):
         """
         if not isinstance(amount, int):
             raise TypeError("Rotate amount must be an integer, not {!r}".format(amount))
-        amount %= len(self)
+        if len(self) != 0:
+            amount %= len(self)
         return Cat(self[amount:], self[:amount])
 
     def eq(self, value):


Test patch:
diff --git a/tests/test_hdl_ast.py b/tests/test_hdl_ast.py
index b4e93e8..65f2404 100644
--- a/tests/test_hdl_ast.py
+++ b/tests/test_hdl_ast.py
@@ -321,6 +321,10 @@ class ValueTestCase(FHDLTestCase):
                         "(cat (slice (const 9'd256) 1:9) (slice (const 9'd256) 0:1))")
         self.assertRepr(Const(256).rotate_left(-7),
                         "(cat (slice (const 9'd256) 7:9) (slice (const 9'd256) 0:7))")
+        self.assertRepr(Const(0, 0).rotate_left(3),
+                        "(cat (slice (const 0'd0) 0:0) (slice (const 0'd0) 0:0))")
+        self.assertRepr(Const(0, 0).rotate_left(-3),
+                        "(cat (slice (const 0'd0) 0:0) (slice (const 0'd0) 0:0))")
 
     def test_rotate_left_wrong(self):
         with self.assertRaisesRegex(TypeError,
@@ -336,6 +340,10 @@ class ValueTestCase(FHDLTestCase):
                         "(cat (slice (const 9'd256) 8:9) (slice (const 9'd256) 0:8))")
         self.assertRepr(Const(256).rotate_right(-7),
                         "(cat (slice (const 9'd256) 2:9) (slice (const 9'd256) 0:2))")
+        self.assertRepr(Const(0, 0).rotate_right(3),
+                        "(cat (slice (const 0'd0) 0:0) (slice (const 0'd0) 0:0))")
+        self.assertRepr(Const(0, 0).rotate_right(-3),
+                        "(cat (slice (const 0'd0) 0:0) (slice (const 0'd0) 0:0))")
 
     def test_rotate_right_wrong(self):
         with self.assertRaisesRegex(TypeError,