Skip to content

Preserve padded handler returns and unpacked comprehension iterators - #9

Open
EiNSTeiN- wants to merge 2 commits into
ejfkdev:mainfrom
EiNSTeiN-:fix/handler-returns-comprehension-iterators
Open

EiNSTeiN- wants to merge 2 commits into
ejfkdev:mainfrom
EiNSTeiN-:fix/handler-returns-comprehension-iterators

Conversation

@EiNSTeiN-

Copy link
Copy Markdown

I am opening this PR to fix two small boundary errors: losing a handler's return value when cleanup is followed by padding, and losing a comprehension's accumulator when an unpacked target consumes its modeled iterator.

For the handler case, the return must remain inside its exception clause even when the bytecode contains NOPs between POP_EXCEPT and RETURN_VALUE:

async def handled(read, log):
    try:
        await read()
        log("saved")
    except ValueError:
        log("locked")
        return False
    except Exception as error:
        log("failed", error)
        return False
    return True

NOP/NOT_TAKEN/CACHE between POP_EXCEPT and a return do not end the handler's return trailer. The current scan stops at that padding, which can leave a bare return where False is already loaded. Continuing through the padding keeps the carried value in its handler and leaves the success return outside it. The padded bytecode examples preserve jump targets and exception-table boundaries.

For the comprehension case, multiple unpacked generators must retain their iterator slots until cleanup:

def select(groups):
    return [(a, c) for a, b in groups for c, d in b]

Assembling an unpacked inline-comprehension target currently consumes the modeled iterator, even though the VM retains a distinct iterator until loop cleanup. Restoring that iterator prevents END_FOR/POP cleanup from discarding the result accumulator. The repair preserves cleanup for simple targets as well as mixed simple/unpacked generators. Variations include six unpacked names across three generators and list, set and dictionary results:

[(a, c, e) for a, b in groups for c, d in b for e, f in d]
{(a, c) for a, b in groups for c, d in b}
{a: c for a, b in groups for c, d in b}

The iterator repair addresses comprehensions inlined since Python 3.12. The return-trailer repair also applies to the Python 3.11 exception-table layout; it does not depend on comprehension inlining.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant