Skip to content
Snippets Groups Projects
Select Git revision
  • d8dc918deb8d4b13b8919706f9f208542c9ef2e6
  • master default protected
2 results

compile.c

  • Damien George's avatar
    d8dc918d
    py/compile: Handle return/break/continue correctly in async with. · d8dc918d
    Damien George authored
    Before this patch the context manager's __aexit__() method would not be
    executed if a return/break/continue statement was used to exit an async
    with block.  async with now has the same semantics as normal with.
    
    The fix here applies purely to the compiler, and does not modify the
    runtime at all. It might (eventually) be better to define new bytecode(s)
    to handle async with (and maybe other async constructs) in a cleaner, more
    efficient way.
    
    One minor drawback with addressing this issue purely in the compiler is
    that it wasn't possible to get 100% CPython semantics.  The thing that is
    different here to CPython is that the __aexit__ method is not looked up in
    the context manager until it is needed, which is after the body of the
    async with statement has executed.  So if a context manager doesn't have
    __aexit__ then CPython raises an exception before the async with is
    executed, whereas uPy will raise it after it is executed.  Note that
    __aenter__ is looked up at the beginning in uPy because it needs to be
    called straightaway, so if the context manager isn't a context manager then
    it'll still raise an exception at the same location as CPython.  The only
    difference is if the context manager has the __aenter__ method but not the
    __aexit__ method, then in that case uPy has different behaviour.  But this
    is a very minor, and acceptable, difference.
    d8dc918d
    History
    py/compile: Handle return/break/continue correctly in async with.
    Damien George authored
    Before this patch the context manager's __aexit__() method would not be
    executed if a return/break/continue statement was used to exit an async
    with block.  async with now has the same semantics as normal with.
    
    The fix here applies purely to the compiler, and does not modify the
    runtime at all. It might (eventually) be better to define new bytecode(s)
    to handle async with (and maybe other async constructs) in a cleaner, more
    efficient way.
    
    One minor drawback with addressing this issue purely in the compiler is
    that it wasn't possible to get 100% CPython semantics.  The thing that is
    different here to CPython is that the __aexit__ method is not looked up in
    the context manager until it is needed, which is after the body of the
    async with statement has executed.  So if a context manager doesn't have
    __aexit__ then CPython raises an exception before the async with is
    executed, whereas uPy will raise it after it is executed.  Note that
    __aenter__ is looked up at the beginning in uPy because it needs to be
    called straightaway, so if the context manager isn't a context manager then
    it'll still raise an exception at the same location as CPython.  The only
    difference is if the context manager has the __aenter__ method but not the
    __aexit__ method, then in that case uPy has different behaviour.  But this
    is a very minor, and acceptable, difference.