Repository: amaranth-lang/amaranth
Pull request #1408 (2024-06-18 14:01:05)

sim: improve error messages for weird objects passed as testbenches.


Patch:
diff --git a/amaranth/sim/core.py b/amaranth/sim/core.py
index 5c50399..2c9bc57 100644
--- a/amaranth/sim/core.py
+++ b/amaranth/sim/core.py
@@ -132,6 +132,18 @@ class Simulator:
 
     @staticmethod
     def _check_function(function, *, kind):
+        if inspect.isasyncgenfunction(function):
+            raise TypeError(
+                f"Cannot add a {kind} {function!r} because it is an async generator function "
+                f"(there is likely a stray `yield` in the function)")
+        if inspect.iscoroutine(function):
+            raise TypeError(
+                f"Cannot add a {kind} {function!r} because it is a coroutine object instead "
+                f"of a function (pass the function itself instead of calling it)")
+        if inspect.isgenerator(function) or inspect.isasyncgen(function):
+            raise TypeError(
+                f"Cannot add a {kind} {function!r} because it is a generator object instead "
+                f"of a function (pass the function itself instead of calling it)")
         if not (inspect.isgeneratorfunction(function) or inspect.iscoroutinefunction(function)):
             raise TypeError(
                 f"Cannot add a {kind} {function!r} because it is not an async function or "


Test patch:
diff --git a/tests/test_sim.py b/tests/test_sim.py
index b66ac04..e27b12c 100644
--- a/tests/test_sim.py
+++ b/tests/test_sim.py
@@ -716,8 +716,8 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
     def test_add_process_wrong_generator(self):
         with self.assertSimulation(Module()) as sim:
             with self.assertRaisesRegex(TypeError,
-                    r"^Cannot add a process <.+?> because it is not an async function or "
-                    r"generator function$"):
+                    r"^Cannot add a process <.+?> because it is a generator object instead of "
+                    r"a function \(pass the function itself instead of calling it\)$"):
                 def process():
                     yield Delay()
                 sim.add_process(process())
@@ -732,12 +732,39 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
     def test_add_testbench_wrong_generator(self):
         with self.assertSimulation(Module()) as sim:
             with self.assertRaisesRegex(TypeError,
-                    r"^Cannot add a testbench <.+?> because it is not an async function or "
-                    r"generator function$"):
+                    r"^Cannot add a testbench <.+?> because it is a generator object instead of "
+                    r"a function \(pass the function itself instead of calling it\)$"):
                 def testbench():
                     yield Delay()
                 sim.add_testbench(testbench())
 
+    def test_add_testbench_wrong_coroutine(self):
+        with self.assertSimulation(Module()) as sim:
+            with self.assertRaisesRegex(TypeError,
+                    r"^Cannot add a testbench <.+?> because it is a coroutine object instead of "
+                    r"a function \(pass the function itself instead of calling it\)$"):
+                async def testbench():
+                    pass
+                sim.add_testbench(testbench())
+
+    def test_add_testbench_wrong_async_generator(self):
+        with self.assertSimulation(Module()) as sim:
+            with self.assertRaisesRegex(TypeError,
+                    r"^Cannot add a testbench <.+?> because it is a generator object instead of "
+                    r"a function \(pass the function itself instead of calling it\)$"):
+                async def testbench():
+                    yield Delay()
+                sim.add_testbench(testbench())
+
+    def test_add_testbench_wrong_async_generator_func(self):
+        with self.assertSimulation(Module()) as sim:
+            with self.assertRaisesRegex(TypeError,
+                    r"^Cannot add a testbench <.+?> because it is an async generator function "
+                    r"\(there is likely a stray `yield` in the function\)$"):
+                async def testbench():
+                    yield Delay()
+                sim.add_testbench(testbench)
+
     def test_add_clock_wrong_twice(self):
         m = Module()
         s = Signal()
@@ -2015,15 +2042,6 @@ class SimulatorRegressionTestCase(FHDLTestCase):
         self.assertTrue(reached_tb)
         self.assertTrue(reached_proc)
 
-    def test_bug_1363(self):
-        sim = Simulator(Module())
-        with self.assertRaisesRegex(TypeError,
-                r"^Cannot add a testbench <.+?> because it is not an async function or "
-                r"generator function$"):
-            async def testbench():
-                yield Delay()
-            sim.add_testbench(testbench())
-
     def test_issue_1368(self):
         sim = Simulator(Module())
         async def testbench(ctx):