Repository: amaranth-lang/amaranth
Pull request #1134 (2024-02-13 22:50:09)

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

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1134?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) Report
Attention: `2 lines` in your changes are missing coverage. Please review.
> Comparison is base [(`353a8ce`)](https://app.codecov.io/gh/amaranth-lang/amaranth/commit/353a8ce7e313e8d203635151402ef88a0171bf45?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) 85.47% compared to head [(`80f28f6`)](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1134?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) 85.44%.

> :exclamation: Current head 80f28f6 differs from pull request most recent head 9bd16ac. Consider uploading reports for the commit 9bd16ac to get more accurate results

| [Files](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1134?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) | Patch % | Lines |
|---|---|---|
| [amaranth/hdl/\_ast.py](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1134?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang#diff-YW1hcmFudGgvaGRsL19hc3QucHk=) | 0.00% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1134?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) |

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


```diff
@@            Coverage Diff             @@
##             main    #1134      +/-   ##
==========================================
- Coverage   85.47%   85.44%   -0.04%     
==========================================
  Files          42       42              
  Lines        8358     8360       +2     
  Branches     1973     1974       +1     
==========================================
- Hits         7144     7143       -1     
- Misses       1017     1019       +2     
- Partials      197      198       +1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/1134?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 b3b160c..5eaf56f 100644
--- a/amaranth/hdl/_ast.py
+++ b/amaranth/hdl/_ast.py
@@ -2294,8 +2294,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 b18f99f..7e52eea 100644
--- a/amaranth/sim/_pyrtl.py
+++ b/amaranth/sim/_pyrtl.py
@@ -378,7 +378,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)}:")
diff --git a/pyproject.toml b/pyproject.toml
index 7049cae..ed58a02 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -57,7 +57,7 @@ source-includes = [
 
 [tool.pdm.dev-dependencies]
 test = [
-  "yowasp-yosys!=0.37.0.*",
+  "yowasp-yosys>=0.38",
   "coverage",
 ]
 docs = [


Test patch:
diff --git a/tests/test_hdl_ast.py b/tests/test_hdl_ast.py
index 4b14f6b..9880ba5 100644
--- a/tests/test_hdl_ast.py
+++ b/tests/test_hdl_ast.py
@@ -1473,6 +1473,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 01e55d3..7950fe6 100644
--- a/tests/test_sim.py
+++ b/tests/test_sim.py
@@ -1064,6 +1064,18 @@ 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():
+                self.assertEqual((yield o), 1)
+            sim.add_testbench(process)
+
 
 class SimulatorRegressionTestCase(FHDLTestCase):
     def test_bug_325(self):