From a9c5a4f137e98bba14a9100c81da1e1a2e041fd1 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Wed, 10 May 2023 13:11:03 -0700 Subject: [PATCH] gh-104357: fix inlined comprehensions with cells --- Lib/test/test_listcomps.py | 9 +++++++++ Python/symtable.c | 19 +++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 92fed98dd0004a..362b930b15cf26 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -163,6 +163,15 @@ def test_inner_cell_shadows_outer(self): outputs = {"y": [4, 4, 4, 4, 4], "i": 20} self._check_in_scopes(code, outputs) + def test_inner_cell_shadows_outer_no_store(self): + code = """ + def f(x): + return [lambda: x for x in range(x)] + y = [fn() for fn in f(2)] + """ + outputs = {"y": [1, 1]} + self._check_in_scopes(code, outputs) + def test_closure_can_jump_over_comp_scope(self): code = """ items = [(lambda: y) for i in range(5)] diff --git a/Python/symtable.c b/Python/symtable.c index 6e74d764245a57..9361674bf16594 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -607,12 +607,19 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, SET_SCOPE(scopes, k, scope); } else { - // free vars in comprehension that are locals in outer scope can - // now simply be locals, unless they are free in comp children - if ((PyLong_AsLong(existing) & DEF_BOUND) && - !is_free_in_any_child(comp, k)) { - if (PySet_Discard(comp_free, k) < 0) { - return 0; + if (PyLong_AsLong(existing) & DEF_BOUND) { + // cell vars in comprehension that are locals in outer scope + // must be promoted to cell so u_cellvars isn't wrong + if (scope == CELL && ste->ste_type == FunctionBlock) { + SET_SCOPE(scopes, k, scope); + } + + // free vars in comprehension that are locals in outer scope can + // now simply be locals, unless they are free in comp children + if (!is_free_in_any_child(comp, k)) { + if (PySet_Discard(comp_free, k) < 0) { + return 0; + } } } }