Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Lib/test/test_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,29 @@ async def f_set():
with self.assertRaises(TypeError):
run_yielding_async_fn(f)

def test_frozenset_optimization_shared_set(self):
# gh-158490: frozenset({... for ...}) must not freeze a set that
# something else still references, here a trace function
kept = []
def tracer(frame, event, arg):
if event == 'return' and type(arg) is set:
kept.append(arg)
return tracer

class C:
x: frozenset({i for i in range(3)})

old_trace = sys.gettrace()
sys.settrace(tracer)
try:
fs = C.__annotations__['x']
finally:
sys.settrace(old_trace)
self.assertEqual(fs, frozenset({0, 1, 2}))
self.assertEqual(len(kept), 1)
self.assertIs(type(kept[0]), set)
self.assertIsNot(kept[0], fs)

def test_ascii(self):
self.assertEqual(ascii(''), '\'\'')
self.assertEqual(ascii(0), '0')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :class:`frozenset` of a set comprehension in a class annotation or type
alias freezing a set that a trace function or debugger still references.
14 changes: 14 additions & 0 deletions Python/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -4029,6 +4029,20 @@ maybe_optimize_function_call(compiler *c, expr_ty e, jump_target_label end)

if (_PyUnicode_EqualToASCIIString(func->v.Name.id, "frozenset")
&& (arg_expr->kind == Set_kind || arg_expr->kind == SetComp_kind)) {
if (arg_expr->kind == SetComp_kind) {
/* A comprehension that is not inlined returns its set from a
call, so a trace function may still hold a reference to it. */
PySTEntryObject *entry = _PySymtable_Lookup(SYMTABLE(c),
(void *)arg_expr);
if (entry == NULL) {
return ERROR;
}
int is_inlined = (entry->ste_type == InlinedComprehensionBlock);
Py_DECREF(entry);
if (!is_inlined) {
return 0;
}
}
NEW_JUMP_TARGET_LABEL(c, skip_optimization);

ADDOP_I(c, loc, COPY, 1);
Expand Down
Loading