Skip to content

gh-121914: Change the names of the symbol tables for lambda and genexpr #135288

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
5 changes: 0 additions & 5 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(deterministic)
STRUCT_FOR_ID(device)
STRUCT_FOR_ID(dict)
STRUCT_FOR_ID(dictcomp)
STRUCT_FOR_ID(difference_update)
STRUCT_FOR_ID(digest)
STRUCT_FOR_ID(digest_size)
Expand Down Expand Up @@ -470,7 +469,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(func)
STRUCT_FOR_ID(future)
STRUCT_FOR_ID(generation)
STRUCT_FOR_ID(genexpr)
STRUCT_FOR_ID(get)
STRUCT_FOR_ID(get_debug)
STRUCT_FOR_ID(get_event_loop)
Expand Down Expand Up @@ -546,7 +544,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(kw2)
STRUCT_FOR_ID(kwdefaults)
STRUCT_FOR_ID(label)
STRUCT_FOR_ID(lambda)
STRUCT_FOR_ID(last)
STRUCT_FOR_ID(last_exc)
STRUCT_FOR_ID(last_node)
Expand All @@ -562,7 +559,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(line)
STRUCT_FOR_ID(line_buffering)
STRUCT_FOR_ID(lineno)
STRUCT_FOR_ID(listcomp)
STRUCT_FOR_ID(little)
STRUCT_FOR_ID(lo)
STRUCT_FOR_ID(locale)
Expand Down Expand Up @@ -708,7 +704,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(server_hostname)
STRUCT_FOR_ID(server_side)
STRUCT_FOR_ID(session)
STRUCT_FOR_ID(setcomp)
STRUCT_FOR_ID(setpgroup)
STRUCT_FOR_ID(setsid)
STRUCT_FOR_ID(setsigdef)
Expand Down
5 changes: 0 additions & 5 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 0 additions & 20 deletions Include/internal/pycore_unicodeobject_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 0 additions & 12 deletions Lib/symtable.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,25 +255,13 @@ def is_local_symbol(ident):
if is_local_symbol(st.name):
match st.type:
case _symtable.TYPE_FUNCTION:
# generators are of type TYPE_FUNCTION with a ".0"
# parameter as a first parameter (which makes them
# distinguishable from a function named 'genexpr')
if st.name == 'genexpr' and '.0' in st.varnames:
continue
Comment on lines -258 to -262
Copy link
Member

Choose a reason for hiding this comment

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

Thank you. This hack was ugly.

d[st.name] = 1
case _symtable.TYPE_TYPE_PARAMETERS:
# Get the function-def block in the annotation
# scope 'st' with the same identifier, if any.
scope_name = st.name
for c in st.children:
if c.name == scope_name and c.type == _symtable.TYPE_FUNCTION:
# A generic generator of type TYPE_FUNCTION
# cannot be a direct child of 'st' (but it
# can be a descendant), e.g.:
#
# class A:
# type genexpr[genexpr] = (x for x in [])
assert scope_name != 'genexpr' or '.0' not in c.varnames
d[scope_name] = 1
break
self.__methods = tuple(d)
Expand Down
52 changes: 52 additions & 0 deletions Lib/test/test_symtable.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,58 @@ def test_symtable_entry_repr(self):
expected = f"<symtable entry top({self.top.get_id()}), line {self.top.get_lineno()}>"
self.assertEqual(repr(self.top._table), expected)

def test_lambda(self):
st = symtable.symtable("lambda x: x", "?", "exec")
self.assertEqual(len(st.get_children()), 1)
st = st.get_children()[0]
self.assertIs(st.get_type(), symtable.SymbolTableType.FUNCTION)
self.assertEqual(st.get_name(), "<lambda>")
self.assertFalse(st.is_nested())
self.assertEqual(sorted(st.get_identifiers()), ["x"])
self.assertEqual(st.get_children(), [])

def test_nested_lambda(self):
st = symtable.symtable("lambda x: lambda y=x: y", "?", "exec")
self.assertEqual(len(st.get_children()), 1)
st = st.get_children()[0]
self.assertIs(st.get_type(), symtable.SymbolTableType.FUNCTION)
self.assertEqual(st.get_name(), "<lambda>")
self.assertFalse(st.is_nested())
self.assertEqual(sorted(st.get_identifiers()), ["x"])
self.assertEqual(len(st.get_children()), 1)
st = st.get_children()[0]
self.assertIs(st.get_type(), symtable.SymbolTableType.FUNCTION)
self.assertEqual(st.get_name(), "<lambda>")
self.assertTrue(st.is_nested())
self.assertEqual(sorted(st.get_identifiers()), ["y"])
self.assertEqual(st.get_children(), [])

def test_genexpr(self):
st = symtable.symtable("(x for x in a)", "?", "exec")
self.assertEqual(len(st.get_children()), 1)
st = st.get_children()[0]
self.assertIs(st.get_type(), symtable.SymbolTableType.FUNCTION)
self.assertEqual(st.get_name(), "<genexpr>")
self.assertFalse(st.is_nested())
self.assertEqual(sorted(st.get_identifiers()), [".0", "x"])
self.assertEqual(st.get_children(), [])

def test_nested_genexpr(self):
st = symtable.symtable("((y for y in x) for x in a)", "?", "exec")
self.assertEqual(len(st.get_children()), 1)
st = st.get_children()[0]
self.assertIs(st.get_type(), symtable.SymbolTableType.FUNCTION)
self.assertEqual(st.get_name(), "<genexpr>")
self.assertFalse(st.is_nested())
self.assertEqual(sorted(st.get_identifiers()), [".0", "x"])
self.assertEqual(len(st.get_children()), 1)
st = st.get_children()[0]
self.assertIs(st.get_type(), symtable.SymbolTableType.FUNCTION)
self.assertEqual(st.get_name(), "<genexpr>")
self.assertTrue(st.is_nested())
self.assertEqual(sorted(st.get_identifiers()), [".0", "y"])
self.assertEqual(st.get_children(), [])


class ComprehensionTests(unittest.TestCase):
def get_identifiers_recursive(self, st, res):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Changed the names of the symbol tables for lambda expressions and generator
expressions to "<lambda>" and "<genexpr>" respectively to avoid conflicts
with user-defined names.
10 changes: 5 additions & 5 deletions Python/symtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -2413,7 +2413,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT_SEQ(st, expr, e->v.Lambda.args->defaults);
if (e->v.Lambda.args->kw_defaults)
VISIT_SEQ_WITH_NULL(st, expr, e->v.Lambda.args->kw_defaults);
if (!symtable_enter_block(st, &_Py_ID(lambda),
if (!symtable_enter_block(st, &_Py_STR(anon_lambda),
FunctionBlock, (void *)e, LOCATION(e))) {
return 0;
}
Expand Down Expand Up @@ -3055,31 +3055,31 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e,
static int
symtable_visit_genexp(struct symtable *st, expr_ty e)
{
return symtable_handle_comprehension(st, e, &_Py_ID(genexpr),
return symtable_handle_comprehension(st, e, &_Py_STR(anon_genexpr),
e->v.GeneratorExp.generators,
e->v.GeneratorExp.elt, NULL);
}

static int
symtable_visit_listcomp(struct symtable *st, expr_ty e)
{
return symtable_handle_comprehension(st, e, &_Py_ID(listcomp),
return symtable_handle_comprehension(st, e, &_Py_STR(anon_listcomp),
Copy link
Member

Choose a reason for hiding this comment

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

Should there be tests for this one too?

Copy link
Member Author

Choose a reason for hiding this comment

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

I cannot write them.

e->v.ListComp.generators,
e->v.ListComp.elt, NULL);
}

static int
symtable_visit_setcomp(struct symtable *st, expr_ty e)
{
return symtable_handle_comprehension(st, e, &_Py_ID(setcomp),
return symtable_handle_comprehension(st, e, &_Py_STR(anon_setcomp),
e->v.SetComp.generators,
e->v.SetComp.elt, NULL);
}

static int
symtable_visit_dictcomp(struct symtable *st, expr_ty e)
{
return symtable_handle_comprehension(st, e, &_Py_ID(dictcomp),
return symtable_handle_comprehension(st, e, &_Py_STR(anon_dictcomp),
e->v.DictComp.generators,
e->v.DictComp.key,
e->v.DictComp.value);
Expand Down
Loading