From: awygle Date: Tue, 7 Jul 2020 05:17:03 +0000 (-0700) Subject: hdl.ast: don't inherit Shape from NamedTuple. X-Git-Tag: 24jan2021_ls180~28 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=659b0e8189fdf99be678d5713259ba59726d991b;p=nmigen.git hdl.ast: don't inherit Shape from NamedTuple. Fixes #421. --- diff --git a/nmigen/hdl/ast.py b/nmigen/hdl/ast.py index 37a3b46..55b825b 100644 --- a/nmigen/hdl/ast.py +++ b/nmigen/hdl/ast.py @@ -32,7 +32,7 @@ class DUID: DUID.__next_uid += 1 -class Shape(typing.NamedTuple): +class Shape: """Bit width and signedness of a value. A ``Shape`` can be constructed using: @@ -55,8 +55,15 @@ class Shape(typing.NamedTuple): signed : bool If ``False``, the value is unsigned. If ``True``, the value is signed two's complement. """ - width: int = 1 - signed: bool = False + def __init__(self, width=1, signed=False): + if not isinstance(width, int) or width < 0: + raise TypeError("Width must be a non-negative integer, not {!r}" + .format(width)) + self.width = width + self.signed = signed + + def __iter__(self): + return iter((self.width, self.signed)) @staticmethod def cast(obj, *, src_loc_at=0): @@ -95,13 +102,20 @@ class Shape(typing.NamedTuple): else: return "unsigned({})".format(self.width) - -# TODO: use dataclasses instead of this hack -def _Shape___init__(self, width=1, signed=False): - if not isinstance(width, int) or width < 0: - raise TypeError("Width must be a non-negative integer, not {!r}" - .format(width)) -Shape.__init__ = _Shape___init__ + def __eq__(self, other): + if isinstance(other, tuple) and len(other) == 2: + width, signed = other + if isinstance(width, int) and isinstance(signed, bool): + return self.width == width and self.signed == signed + else: + raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, " + "not {!r}" + .format(other)) + if not isinstance(other, Shape): + raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, " + "not {!r}" + .format(other)) + return self.width == other.width and self.signed == other.signed def unsigned(width): diff --git a/nmigen/test/test_hdl_ast.py b/nmigen/test/test_hdl_ast.py index b724ad6..691408a 100644 --- a/nmigen/test/test_hdl_ast.py +++ b/nmigen/test/test_hdl_ast.py @@ -39,6 +39,16 @@ class ShapeTestCase(FHDLTestCase): msg="Width must be a non-negative integer, not -1"): Shape(-1) + def test_compare_wrong(self): + with self.assertRaises(TypeError, + msg="Shapes may be compared with other Shapes and (int, bool) tuples, not 'hi'"): + Shape(1, True) == 'hi' + + def test_compare_tuple_wrong(self): + with self.assertRaises(TypeError, + msg="Shapes may be compared with other Shapes and (int, bool) tuples, not (2, 3)"): + Shape(1, True) == (2, 3) + def test_repr(self): self.assertEqual(repr(Shape()), "unsigned(1)") self.assertEqual(repr(Shape(2, True)), "signed(2)")