prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  coroutines that return before their first yield cause the simulator to shutdown
  Repro:
  ```python
  @cocotb.test()
  def test_func_empty(dut):
      """ Test that a function can complete before the first yield """
      @cocotb.coroutine
      def func_empty():
          print("This line runs")
          return
          yield  # needed to make this a coroutine
      yield func_empty()
      print("This line is never reached")
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `cocotb/ipython_support.py`
  Content:
  ```
  1 # Copyright cocotb contributors
  2 # Licensed under the Revised BSD License, see LICENSE for details.
  3 # SPDX-License-Identifier: BSD-3-Clause
  4 import IPython
  5 from IPython.terminal.ipapp import load_default_config
  6 from IPython.terminal.prompts import Prompts, Token
  7 
  8 import cocotb
  9 
  10 
  11 class SimTimePrompt(Prompts):
  12     """ custom prompt that shows the sim time after a trigger fires """
  13     _show_time = 1
  14 
  15     def in_prompt_tokens(self, cli=None):
  16         tokens = super().in_prompt_tokens()
  17         if self._show_time == self.shell.execution_count:
  18             tokens = [
  19                 (Token.Comment, "sim time: {}".format(cocotb.utils.get_sim_time())),
  20                 (Token.Text, "\n"),
  21             ] + tokens
  22         return tokens
  23 
  24 
  25 def _runner(shell, x):
  26     """ Handler for async functions """
  27     ret = cocotb.scheduler.queue_function(x)
  28     shell.prompts._show_time = shell.execution_count
  29     return ret
  30 
  31 
  32 async def embed(user_ns: dict = {}):
  33     """
  34     Start an ipython shell in the current coroutine.
  35 
  36     Unlike using :func:`IPython.embed` directly, the :keyword:`await` keyword
  37     can be used directly from the shell to wait for triggers.
  38     The :keyword:`yield` keyword from the legacy :ref:`yield-syntax` is not supported.
  39 
  40     This coroutine will complete only when the user exits the interactive session.
  41 
  42     Args:
  43         user_ns:
  44             The variables to have made available in the shell.
  45             Passing ``locals()`` is often a good idea.
  46             ``cocotb`` will automatically be included.
  47 
  48     Notes:
  49 
  50         If your simulator does not provide an appropriate ``stdin``, you may
  51         find you cannot type in the resulting shell. Using simulators in batch
  52         or non-GUI mode may resolve this. This feature is experimental, and
  53         not all simulators are supported.
  54     """
  55     # ensure cocotb is in the namespace, for convenience
  56     default_ns = dict(cocotb=cocotb)
  57     default_ns.update(user_ns)
  58 
  59     # build the config to enable `await`
  60     c = load_default_config()
  61     c.TerminalInteractiveShell.loop_runner = lambda x: _runner(shell, x)
  62     c.TerminalInteractiveShell.autoawait = True
  63 
  64     # create a shell with access to the dut, and cocotb pre-imported
  65     shell = IPython.terminal.embed.InteractiveShellEmbed(
  66         user_ns=default_ns,
  67         config=c,
  68     )
  69 
  70     # add our custom prompts
  71     shell.prompts = SimTimePrompt(shell)
  72 
  73     # start the shell in a background thread
  74     @cocotb.external
  75     def run_shell():
  76         shell()
  77     await run_shell()
  78 
  79 
  80 @cocotb.test()
  81 async def run_ipython(dut):
  82     """ A test that launches an interactive Python shell.
  83 
  84     Do not call this directly - use this as ``make MODULE=cocotb.ipython_support``.
  85 
  86     Within the shell, a global ``dut`` variable pointing to the design will be present.
  87     """
  88     await cocotb.triggers.Timer(0)  # workaround for gh-637
  89     await embed(user_ns=dict(dut=dut))
  90
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/cocotb/ipython_support.py b/cocotb/ipython_support.py
  --- a/cocotb/ipython_support.py
  +++ b/cocotb/ipython_support.py
  @@ -85,5 +85,4 @@
   
       Within the shell, a global ``dut`` variable pointing to the design will be present.
       """
  -    await cocotb.triggers.Timer(0)  # workaround for gh-637
       await embed(user_ns=dict(dut=dut))
  
verification_info: {"golden_diff": "diff --git a/cocotb/ipython_support.py b/cocotb/ipython_support.py\n--- a/cocotb/ipython_support.py\n+++ b/cocotb/ipython_support.py\n@@ -85,5 +85,4 @@\n \n     Within the shell, a global ``dut`` variable pointing to the design will be present.\n     \"\"\"\n-    await cocotb.triggers.Timer(0)  # workaround for gh-637\n     await embed(user_ns=dict(dut=dut))\n", "issue": "coroutines that return before their first yield cause the simulator to shutdown\nRepro:\r\n```python\r\n@cocotb.test()\r\ndef test_func_empty(dut):\r\n    \"\"\" Test that a function can complete before the first yield \"\"\"\r\n    @cocotb.coroutine\r\n    def func_empty():\r\n        print(\"This line runs\")\r\n        return\r\n        yield  # needed to make this a coroutine\r\n    yield func_empty()\r\n    print(\"This line is never reached\")\r\n```\n", "before_files": [{"content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nimport IPython\nfrom IPython.terminal.ipapp import load_default_config\nfrom IPython.terminal.prompts import Prompts, Token\n\nimport cocotb\n\n\nclass SimTimePrompt(Prompts):\n    \"\"\" custom prompt that shows the sim time after a trigger fires \"\"\"\n    _show_time = 1\n\n    def in_prompt_tokens(self, cli=None):\n        tokens = super().in_prompt_tokens()\n        if self._show_time == self.shell.execution_count:\n            tokens = [\n                (Token.Comment, \"sim time: {}\".format(cocotb.utils.get_sim_time())),\n                (Token.Text, \"\\n\"),\n            ] + tokens\n        return tokens\n\n\ndef _runner(shell, x):\n    \"\"\" Handler for async functions \"\"\"\n    ret = cocotb.scheduler.queue_function(x)\n    shell.prompts._show_time = shell.execution_count\n    return ret\n\n\nasync def embed(user_ns: dict = {}):\n    \"\"\"\n    Start an ipython shell in the current coroutine.\n\n    Unlike using :func:`IPython.embed` directly, the :keyword:`await` keyword\n    can be used directly from the shell to wait for triggers.\n    The :keyword:`yield` keyword from the legacy :ref:`yield-syntax` is not supported.\n\n    This coroutine will complete only when the user exits the interactive session.\n\n    Args:\n        user_ns:\n            The variables to have made available in the shell.\n            Passing ``locals()`` is often a good idea.\n            ``cocotb`` will automatically be included.\n\n    Notes:\n\n        If your simulator does not provide an appropriate ``stdin``, you may\n        find you cannot type in the resulting shell. Using simulators in batch\n        or non-GUI mode may resolve this. This feature is experimental, and\n        not all simulators are supported.\n    \"\"\"\n    # ensure cocotb is in the namespace, for convenience\n    default_ns = dict(cocotb=cocotb)\n    default_ns.update(user_ns)\n\n    # build the config to enable `await`\n    c = load_default_config()\n    c.TerminalInteractiveShell.loop_runner = lambda x: _runner(shell, x)\n    c.TerminalInteractiveShell.autoawait = True\n\n    # create a shell with access to the dut, and cocotb pre-imported\n    shell = IPython.terminal.embed.InteractiveShellEmbed(\n        user_ns=default_ns,\n        config=c,\n    )\n\n    # add our custom prompts\n    shell.prompts = SimTimePrompt(shell)\n\n    # start the shell in a background thread\n    @cocotb.external\n    def run_shell():\n        shell()\n    await run_shell()\n\n\n@cocotb.test()\nasync def run_ipython(dut):\n    \"\"\" A test that launches an interactive Python shell.\n\n    Do not call this directly - use this as ``make MODULE=cocotb.ipython_support``.\n\n    Within the shell, a global ``dut`` variable pointing to the design will be present.\n    \"\"\"\n    await cocotb.triggers.Timer(0)  # workaround for gh-637\n    await embed(user_ns=dict(dut=dut))\n", "path": "cocotb/ipython_support.py"}], "after_files": [{"content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nimport IPython\nfrom IPython.terminal.ipapp import load_default_config\nfrom IPython.terminal.prompts import Prompts, Token\n\nimport cocotb\n\n\nclass SimTimePrompt(Prompts):\n    \"\"\" custom prompt that shows the sim time after a trigger fires \"\"\"\n    _show_time = 1\n\n    def in_prompt_tokens(self, cli=None):\n        tokens = super().in_prompt_tokens()\n        if self._show_time == self.shell.execution_count:\n            tokens = [\n                (Token.Comment, \"sim time: {}\".format(cocotb.utils.get_sim_time())),\n                (Token.Text, \"\\n\"),\n            ] + tokens\n        return tokens\n\n\ndef _runner(shell, x):\n    \"\"\" Handler for async functions \"\"\"\n    ret = cocotb.scheduler.queue_function(x)\n    shell.prompts._show_time = shell.execution_count\n    return ret\n\n\nasync def embed(user_ns: dict = {}):\n    \"\"\"\n    Start an ipython shell in the current coroutine.\n\n    Unlike using :func:`IPython.embed` directly, the :keyword:`await` keyword\n    can be used directly from the shell to wait for triggers.\n    The :keyword:`yield` keyword from the legacy :ref:`yield-syntax` is not supported.\n\n    This coroutine will complete only when the user exits the interactive session.\n\n    Args:\n        user_ns:\n            The variables to have made available in the shell.\n            Passing ``locals()`` is often a good idea.\n            ``cocotb`` will automatically be included.\n\n    Notes:\n\n        If your simulator does not provide an appropriate ``stdin``, you may\n        find you cannot type in the resulting shell. Using simulators in batch\n        or non-GUI mode may resolve this. This feature is experimental, and\n        not all simulators are supported.\n    \"\"\"\n    # ensure cocotb is in the namespace, for convenience\n    default_ns = dict(cocotb=cocotb)\n    default_ns.update(user_ns)\n\n    # build the config to enable `await`\n    c = load_default_config()\n    c.TerminalInteractiveShell.loop_runner = lambda x: _runner(shell, x)\n    c.TerminalInteractiveShell.autoawait = True\n\n    # create a shell with access to the dut, and cocotb pre-imported\n    shell = IPython.terminal.embed.InteractiveShellEmbed(\n        user_ns=default_ns,\n        config=c,\n    )\n\n    # add our custom prompts\n    shell.prompts = SimTimePrompt(shell)\n\n    # start the shell in a background thread\n    @cocotb.external\n    def run_shell():\n        shell()\n    await run_shell()\n\n\n@cocotb.test()\nasync def run_ipython(dut):\n    \"\"\" A test that launches an interactive Python shell.\n\n    Do not call this directly - use this as ``make MODULE=cocotb.ipython_support``.\n\n    Within the shell, a global ``dut`` variable pointing to the design will be present.\n    \"\"\"\n    await embed(user_ns=dict(dut=dut))\n", "path": "cocotb/ipython_support.py"}]}