Skip to content

fix(transpiler): @when result assignment silently dropped in exported module#30

Open
xemishra wants to merge 1 commit into
microsoft:mainfrom
xemishra:fix/transpiler-assign-wrapped-in-expr
Open

fix(transpiler): @when result assignment silently dropped in exported module#30
xemishra wants to merge 1 commit into
microsoft:mainfrom
xemishra:fix/transpiler-assign-wrapped-in-expr

Conversation

@xemishra
Copy link
Copy Markdown

@xemishra xemishra commented Jun 6, 2026

Summary

WhenTransformer.visit_FunctionDef in transpiler.py was returning
ast.Expr(ast.Assign(...)) an ast.Assign statement incorrectly
wrapped inside an ast.Expr node.

This caused a silent double failure:

  • ast.Assign is a statement, not an expression, so the wrapping
    violates the Python AST contract.
  • visit_Module filters out every ast.Expr node to strip bare
    expression statements. Because the return value matched that filter,
    the name = whencall(...) assignment was thrown away entirely.

Impact

For every @when-decorated function, the variable that should hold
the result Cown was never assigned in the exported module. Any code
that read .value, checked .exception, or chained behaviors on the
result was operating on None (or whatever the name happened to be
bound to previously), with no error at schedule time.

Root cause

# Before (buggy)
return ast.Expr(ast.Assign([ast.Name(id=node.name)], when_call))

Fix

# After
assign = ast.Assign(
    targets=[ast.Name(id=node.name, ctx=ast.Store())],
    value=when_call,
)
ast.copy_location(assign, node)
ast.fix_missing_locations(assign)
return assign

Returning a bare ast.Assign passes the visit_Module filter
correctly, satisfies the AST node contract, and ensures the result
Cown is bound to the user's chosen name in the exported module.

Testing

Verified by invoking export_module() directly on a minimal source
containing a @when-decorated function and asserting that
name = whencall(...) appears in the unparsed output, which it did
not before this fix.

@matajoh matajoh self-assigned this Jun 8, 2026
@matajoh matajoh added the bug Something isn't working label Jun 8, 2026
@matajoh
Copy link
Copy Markdown
Member

matajoh commented Jun 8, 2026

Hi! Thanks for this contribution. I'm curious as this definitely works currently (i.e., tests pass which use this functionality) but provided all the workflows are green then I see no reason not to merge as is. Is there a specific regression test you could add to test_transpiler.py for this issue?

@matajoh matajoh self-requested a review June 8, 2026 09:38
Comment thread src/bocpy/transpiler.py

def export_main() -> ExportResult:
"""Export the currently running __main__ module."""
return export_module_from_file(sys.modules["__main__"].__file__)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you removed the newline at the end of the file, which is a style requirement for the repo (it is causing the lint PR gate to fail.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants