Skip to content

Commit

Permalink
Implement RFC 39: Warn on Case() and matches() with no patterns.
Browse files Browse the repository at this point in the history
  • Loading branch information
wanda-phi authored and whitequark committed Jan 16, 2024
1 parent 197c234 commit 4c1d0f3
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 7 deletions.
2 changes: 2 additions & 0 deletions amaranth/hdl/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,8 @@ def matches(self, *patterns):
continue
matches.append(self == pattern)
if not matches:
warnings.warn("The value of Value.matches() with no patterns will change to Const(0) "
"in Amaranth 0.5", SyntaxWarning, stacklevel=2)
return Const(1)
elif len(matches) == 1:
return matches[0]
Expand Down
19 changes: 18 additions & 1 deletion amaranth/hdl/dsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ def Case(self, *patterns):
src_loc = tracer.get_src_loc(src_loc_at=1)
switch_data = self._get_ctrl("Switch")
new_patterns = ()
if not patterns:
warnings.warn("The behavior of Case() with no patterns will change to never-active "
"in Amaranth 0.5; use Default() instead", SyntaxWarning, stacklevel=3)
# This code should accept exactly the same patterns as `v.matches(...)`.
for pattern in patterns:
if isinstance(pattern, str) and any(bit not in "01- \t" for bit in pattern):
Expand Down Expand Up @@ -353,8 +356,22 @@ def Case(self, *patterns):
self._ctrl_context = "Switch"
self._statements = _outer_case

@contextmanager
def Default(self):
return self.Case()
self._check_context("Default", context="Switch")
src_loc = tracer.get_src_loc(src_loc_at=1)
switch_data = self._get_ctrl("Switch")
try:
_outer_case, self._statements = self._statements, []
self._ctrl_context = None
yield
self._flush_ctrl()
if () not in switch_data["cases"]:
switch_data["cases"][()] = self._statements
switch_data["case_src_locs"][()] = src_loc
finally:
self._ctrl_context = "Switch"
self._statements = _outer_case

@contextmanager
def FSM(self, reset=None, domain="sync", name="fsm"):
Expand Down
4 changes: 3 additions & 1 deletion tests/test_hdl_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,9 @@ def test_xor_value(self):

def test_matches(self):
s = Signal(4)
self.assertRepr(s.matches(), "(const 1'd1)")
with self.assertWarnsRegex(SyntaxWarning,
r"^The value of Value.matches\(\) with no patterns will change to Const\(0\)"):
self.assertRepr(s.matches(), "(const 1'd1)")
self.assertRepr(s.matches(1), """
(== (sig s) (const 1'd1))
""")
Expand Down
12 changes: 7 additions & 5 deletions tests/test_hdl_dsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,11 +387,13 @@ def test_Switch(self):

def test_Switch_default_Case(self):
m = Module()
with m.Switch(self.w1):
with m.Case(3):
m.d.comb += self.c1.eq(1)
with m.Case():
m.d.comb += self.c2.eq(1)
with self.assertWarnsRegex(SyntaxWarning,
r"^The behavior of Case\(\) with no patterns will change to never-active"):
with m.Switch(self.w1):
with m.Case(3):
m.d.comb += self.c1.eq(1)
with m.Case():
m.d.comb += self.c2.eq(1)
m._flush()
self.assertRepr(m._statements, """
(
Expand Down

0 comments on commit 4c1d0f3

Please sign in to comment.