fix(transpiler): @when result assignment silently dropped in exported module#30
fix(transpiler): @when result assignment silently dropped in exported module#30xemishra wants to merge 5 commits into
Conversation
|
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 |
|
@microsoft-github-policy-service agree |
|
I've added a test for this scenario and updated the PR accordingly. |
Awesome, thank you for this as well. I've figured out what it was about this that was confusing me. Because standard BOC practice is for behaviors to be defined within functions, this: from bocpy import when, Cown, wait
def main():
x = Cown(0)
@when(x)
def add_one(x):
x.value += 1
@when(add_one, x)
def print_x(_, x):
print(x.value)
if __name__ == "__main__":
main()
wait()works fine, but your case is when the behavior is defined at the module level, which explains why it wasn't caught. Thanks for finding this! |
|
I have restored the trailing newline in test_transpiler.py, which was causing the lint PR gate failure. The fix has been pushed. |
Summary
WhenTransformer.visit_FunctionDefintranspiler.pywas returningast.Expr(ast.Assign(...))anast.Assignstatement incorrectlywrapped inside an
ast.Exprnode.This caused a silent double failure:
ast.Assignis a statement, not an expression, so the wrappingviolates the Python AST contract.
visit_Modulefilters out everyast.Exprnode to strip bareexpression 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 holdthe result
Cownwas never assigned in the exported module. Any codethat read
.value, checked.exception, or chained behaviors on theresult was operating on
None(or whatever the name happened to bebound to previously), with no error at schedule time.
Root cause
Fix
Returning a bare
ast.Assignpasses thevisit_Modulefiltercorrectly, satisfies the AST node contract, and ensures the result
Cownis bound to the user's chosen name in the exported module.Testing
Verified by invoking
export_module()directly on a minimal sourcecontaining a
@when-decorated function and asserting thatname = whencall(...)appears in the unparsed output, which it didnot before this fix.