Commit f726a3c8 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #27942: String constants now interned recursively in tuples and frozensets.

parents e2132623 cb94a53e
......@@ -102,6 +102,7 @@ consts: ('None',)
"""
import sys
import unittest
import weakref
from test.support import run_doctest, run_unittest, cpython_only
......@@ -134,6 +135,43 @@ class CodeTest(unittest.TestCase):
self.assertEqual(co.co_name, "funcname")
self.assertEqual(co.co_firstlineno, 15)
class CodeConstsTest(unittest.TestCase):
def find_const(self, consts, value):
for v in consts:
if v == value:
return v
self.assertIn(value, consts) # rises an exception
self.fail('Should be never reached')
def assertIsInterned(self, s):
if s is not sys.intern(s):
self.fail('String %r is not interned' % (s,))
@cpython_only
def test_interned_string(self):
co = compile('res = "str_value"', '?', 'exec')
v = self.find_const(co.co_consts, 'str_value')
self.assertIsInterned(v)
@cpython_only
def test_interned_string_in_tuple(self):
co = compile('res = ("str_value",)', '?', 'exec')
v = self.find_const(co.co_consts, ('str_value',))
self.assertIsInterned(v[0])
@cpython_only
def test_interned_string_in_frozenset(self):
co = compile('res = a in {"str_value"}', '?', 'exec')
v = self.find_const(co.co_consts, frozenset(('str_value',)))
self.assertIsInterned(tuple(v)[0])
@cpython_only
def test_interned_string_default(self):
def f(a='str_value'):
return a
self.assertIsInterned(f())
class CodeWeakRefTest(unittest.TestCase):
......@@ -163,7 +201,7 @@ class CodeWeakRefTest(unittest.TestCase):
def test_main(verbose=None):
from test import test_code
run_doctest(test_code, verbose)
run_unittest(CodeTest, CodeWeakRefTest)
run_unittest(CodeTest, CodeConstsTest, CodeWeakRefTest)
if __name__ == "__main__":
......
......@@ -10,6 +10,8 @@ What's New in Python 3.6.0 beta 2
Core and Builtins
-----------------
- Issue #27942: String constants now interned recursively in tuples and frozensets.
- Issue #21578: Fixed misleading error message when ImportError called with
invalid keyword args.
......
......@@ -54,6 +54,50 @@ intern_strings(PyObject *tuple)
}
}
/* Intern selected string constants */
static int
intern_string_constants(PyObject *tuple)
{
int modified = 0;
Py_ssize_t i;
for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
PyObject *v = PyTuple_GET_ITEM(tuple, i);
if (PyUnicode_CheckExact(v)) {
if (all_name_chars(v)) {
PyObject *w = v;
PyUnicode_InternInPlace(&v);
if (w != v) {
PyTuple_SET_ITEM(tuple, i, v);
modified = 1;
}
}
}
else if (PyTuple_CheckExact(v)) {
intern_string_constants(v);
}
else if (PyFrozenSet_CheckExact(v)) {
PyObject *tmp = PySequence_Tuple(v);
if (tmp == NULL) {
PyErr_Clear();
continue;
}
if (intern_string_constants(tmp)) {
v = PyFrozenSet_New(tmp);
if (v == NULL) {
PyErr_Clear();
}
else {
PyTuple_SET_ITEM(tuple, i, v);
modified = 1;
}
}
Py_DECREF(tmp);
}
}
return modified;
}
PyCodeObject *
PyCode_New(int argcount, int kwonlyargcount,
......@@ -92,13 +136,7 @@ PyCode_New(int argcount, int kwonlyargcount,
intern_strings(varnames);
intern_strings(freevars);
intern_strings(cellvars);
/* Intern selected string constants */
for (i = PyTuple_GET_SIZE(consts); --i >= 0; ) {
PyObject *v = PyTuple_GetItem(consts, i);
if (!all_name_chars(v))
continue;
PyUnicode_InternInPlace(&PyTuple_GET_ITEM(consts, i));
}
intern_string_constants(consts);
/* Create mapping between cells and arguments if needed. */
if (n_cellvars) {
Py_ssize_t total_args = argcount + kwonlyargcount +
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment