hdl.ast: warn on bare integer value used in Cat()/Repl().
authorwhitequark <whitequark@whitequark.org>
Sat, 11 Dec 2021 08:18:33 +0000 (08:18 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 31 Dec 2021 20:04:18 +0000 (20:04 +0000)
Fixes #639.

nmigen/hdl/ast.py
tests/test_hdl_ast.py

index ae010a0af2e6b8973cea72686fbaaece1569f969..0049c0474045d71219495c7b3f396fb427fb8bfa 100644 (file)
@@ -831,7 +831,14 @@ class Cat(Value):
     """
     def __init__(self, *args, src_loc_at=0):
         super().__init__(src_loc_at=src_loc_at)
-        self.parts = [Value.cast(v) for v in flatten(args)]
+        self.parts = []
+        for index, arg in enumerate(flatten(args)):
+            if isinstance(arg, int) and arg not in [0, 1]:
+                warnings.warn("Argument #{} of Cat() is a bare integer {} used in bit vector "
+                              "context; consider specifying explicit width using C({}, {}) instead"
+                              .format(index + 1, arg, arg, bits_for(arg)),
+                              SyntaxWarning, stacklevel=2 + src_loc_at)
+            self.parts.append(Value.cast(arg))
 
     def shape(self):
         return Shape(sum(len(part) for part in self.parts))
@@ -880,6 +887,11 @@ class Repl(Value):
                             .format(count))
 
         super().__init__(src_loc_at=src_loc_at)
+        if isinstance(value, int) and value not in [0, 1]:
+            warnings.warn("Value argument of Repl() is a bare integer {} used in bit vector "
+                          "context; consider specifying explicit width using C({}, {}) instead"
+                          .format(value, value, bits_for(value)),
+                          SyntaxWarning, stacklevel=2 + src_loc_at)
         self.value = Value.cast(value)
         self.count = count
 
index fb25f39a7478dfc6808424a5ec47cfb46c55654c..83f6071a1605dd777c5bccba5bcd1745719b7b96 100644 (file)
@@ -746,6 +746,17 @@ class CatTestCase(FHDLTestCase):
                 r"^Object 'foo' cannot be converted to an nMigen value$"):
             Cat("foo")
 
+    def test_int_01(self):
+        with warnings.catch_warnings():
+            warnings.filterwarnings(action="error", category=SyntaxWarning)
+            Cat(0, 1, 1, 0)
+
+    def test_int_wrong(self):
+        with self.assertWarnsRegex(SyntaxWarning,
+                r"^Argument #1 of Cat\(\) is a bare integer 2 used in bit vector context; "
+                r"consider specifying explicit width using C\(2, 2\) instead$"):
+            Cat(2)
+
 
 class ReplTestCase(FHDLTestCase):
     def test_shape(self):
@@ -769,6 +780,18 @@ class ReplTestCase(FHDLTestCase):
         r = Repl(0, 3)
         self.assertEqual(repr(r), "(repl (const 1'd0) 3)")
 
+    def test_int_01(self):
+        with warnings.catch_warnings():
+            warnings.filterwarnings(action="error", category=SyntaxWarning)
+            Repl(0, 3)
+            Repl(1, 3)
+
+    def test_int_wrong(self):
+        with self.assertWarnsRegex(SyntaxWarning,
+                r"^Value argument of Repl\(\) is a bare integer 2 used in bit vector context; "
+                r"consider specifying explicit width using C\(2, 2\) instead$"):
+            Repl(2, 3)
+
 
 class ArrayTestCase(FHDLTestCase):
     def test_acts_like_array(self):