Repository: amaranth-lang/amaranth
Pull request #1137 (2024-02-13 23:30:19)

hdl._ast: fix using 0-width `Switch` with integer keys. [0.4 backport]
This comes up in `AssignmentLegalizer`-produced `Switch`es for `ArrayProxy`.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1137?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`a669aa3`)](https://app.codecov.io/gh/amaranth-lang/amaranth/commit/a669aa38525d32e34344c7fa6f108a3767ae6f5c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) 83.85% compared to head [(`fe53716`)](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1137?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) 83.73%.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           v0.4.x    #1137      +/-   ##
==========================================
- Coverage   83.85%   83.73%   -0.12%     
==========================================
  Files          55       55              
  Lines        8106     8110       +4     
  Branches     1979     1720     -259     
==========================================
- Hits         6797     6791       -6     
- Misses       1095     1102       +7     
- Partials      214      217       +3     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1137?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang).


Patch:
diff --git a/amaranth/hdl/ast.py b/amaranth/hdl/ast.py
index 9b7b6e7..6b529d6 100644
--- a/amaranth/hdl/ast.py
+++ b/amaranth/hdl/ast.py
@@ -1769,8 +1769,14 @@ class Switch(Statement):
                     key = "".join(key.split()) # remove whitespace
                 elif isinstance(key, int):
                     key = format(key & key_mask, "b").rjust(len(self.test), "0")
+                    # fixup for 0-width test
+                    if key_mask == 0:
+                        key = ""
                 elif isinstance(key, Enum):
                     key = format(key.value & key_mask, "b").rjust(len(self.test), "0")
+                    # fixup for 0-width test
+                    if key_mask == 0:
+                        key = ""
                 else:
                     raise TypeError("Object {!r} cannot be used as a switch key"
                                     .format(key))
diff --git a/amaranth/sim/_pyrtl.py b/amaranth/sim/_pyrtl.py
index a740060..17c7919 100644
--- a/amaranth/sim/_pyrtl.py
+++ b/amaranth/sim/_pyrtl.py
@@ -383,7 +383,7 @@ class _StatementCompiler(StatementVisitor, _Compiler):
                         value = int("".join("0" if b == "-" else  b  for b in pattern), 2)
                         gen_checks.append(f"{value} == ({mask} & {gen_test})")
                     else:
-                        value = int(pattern, 2)
+                        value = int(pattern or "0", 2)
                         gen_checks.append(f"{value} == {gen_test}")
             if index == 0:
                 self.emitter.append(f"if {' or '.join(gen_checks)}:")


Test patch:
diff --git a/tests/test_hdl_ast.py b/tests/test_hdl_ast.py
index de8288a..ad9b9dd 100644
--- a/tests/test_hdl_ast.py
+++ b/tests/test_hdl_ast.py
@@ -1471,6 +1471,16 @@ class SwitchTestCase(FHDLTestCase):
         s = Switch(Const(0, 8), {-10: []})
         self.assertEqual(s.cases, {("11110110",): []})
 
+    def test_int_zero_width(self):
+        s = Switch(Const(0, 0), {0: []})
+        self.assertEqual(s.cases, {("",): []})
+
+    def test_int_zero_width_enum(self):
+        class ZeroEnum(Enum):
+            A = 0
+        s = Switch(Const(0, 0), {ZeroEnum.A: []})
+        self.assertEqual(s.cases, {("",): []})
+
     def test_enum_case(self):
         s = Switch(Const(0, UnsignedEnum), {UnsignedEnum.FOO: []})
         self.assertEqual(s.cases, {("01",): []})
diff --git a/tests/test_sim.py b/tests/test_sim.py
index 75ab66c..56cd666 100644
--- a/tests/test_sim.py
+++ b/tests/test_sim.py
@@ -1014,6 +1014,19 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
         m.d.comb += a.eq(op)
         Simulator(m)
 
+    def test_switch_zero(self):
+        m = Module()
+        a = Signal(0)
+        o = Signal()
+        with m.Switch(a):
+            with m.Case(""):
+                m.d.comb += o.eq(1)
+        with self.assertSimulation(m) as sim:
+            def process():
+                yield Settle()
+                self.assertEqual((yield o), 1)
+            sim.add_process(process)
+
 
 class SimulatorRegressionTestCase(FHDLTestCase):
     def test_bug_325(self):