Skip to content

Commit fc31f93

Browse files
Factor in duplicates.
1 parent 8146629 commit fc31f93

1 file changed

Lines changed: 25 additions & 5 deletions

File tree

Objects/codeobject.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,7 +1714,7 @@ static int
17141714
identify_unbound_names(PyThreadState *tstate, PyCodeObject *co,
17151715
PyObject *globalnames, PyObject *attrnames,
17161716
PyObject *globalsns, PyObject *builtinsns,
1717-
struct co_unbound_counts *counts)
1717+
struct co_unbound_counts *counts, int *p_numdupes)
17181718
{
17191719
// This function is inspired by inspect.getclosurevars().
17201720
// It would be nicer if we had something similar to co_localspluskinds,
@@ -1729,6 +1729,7 @@ identify_unbound_names(PyThreadState *tstate, PyCodeObject *co,
17291729
assert(builtinsns == NULL || PyDict_Check(builtinsns));
17301730
assert(counts == NULL || counts->total == 0);
17311731
struct co_unbound_counts unbound = {0};
1732+
int numdupes = 0;
17321733
Py_ssize_t len = Py_SIZE(co);
17331734
for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
17341735
_Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
@@ -1747,6 +1748,12 @@ identify_unbound_names(PyThreadState *tstate, PyCodeObject *co,
17471748
if (PySet_Add(attrnames, name) < 0) {
17481749
return -1;
17491750
}
1751+
if (PySet_Contains(globalnames, name)) {
1752+
if (_PyErr_Occurred(tstate)) {
1753+
return -1;
1754+
}
1755+
numdupes += 1;
1756+
}
17501757
}
17511758
else if (inst.op.code == LOAD_GLOBAL) {
17521759
int oparg = GET_OPARG(co, i, inst.op.arg);
@@ -1778,11 +1785,20 @@ identify_unbound_names(PyThreadState *tstate, PyCodeObject *co,
17781785
if (PySet_Add(globalnames, name) < 0) {
17791786
return -1;
17801787
}
1788+
if (PySet_Contains(attrnames, name)) {
1789+
if (_PyErr_Occurred(tstate)) {
1790+
return -1;
1791+
}
1792+
numdupes += 1;
1793+
}
17811794
}
17821795
}
17831796
if (counts != NULL) {
17841797
*counts = unbound;
17851798
}
1799+
if (p_numdupes != NULL) {
1800+
*p_numdupes = numdupes;
1801+
}
17861802
return 0;
17871803
}
17881804

@@ -1932,20 +1948,24 @@ _PyCode_SetUnboundVarCounts(PyThreadState *tstate,
19321948

19331949
// Fill in unbound.globals and unbound.numattrs.
19341950
struct co_unbound_counts unbound = {0};
1951+
int numdupes = 0;
19351952
Py_BEGIN_CRITICAL_SECTION(co);
19361953
res = identify_unbound_names(
19371954
tstate, co, globalnames, attrnames, globalsns, builtinsns,
1938-
&unbound);
1955+
&unbound, &numdupes);
19391956
Py_END_CRITICAL_SECTION();
19401957
if (res < 0) {
19411958
goto finally;
19421959
}
19431960
assert(unbound.numunknown == 0);
1944-
assert(unbound.total <= counts->unbound.total);
1961+
assert(unbound.total - numdupes <= counts->unbound.total);
19451962
assert(counts->unbound.numunknown == counts->unbound.total);
1946-
unbound.numunknown = counts->unbound.total - unbound.total;
1947-
unbound.total = counts->unbound.total;
1963+
// There may be a name that is both a global and an attr.
1964+
int totalunbound = counts->unbound.total + numdupes;
1965+
unbound.numunknown = totalunbound - unbound.total;
1966+
unbound.total = totalunbound;
19481967
counts->unbound = unbound;
1968+
counts->total += numdupes;
19491969
res = 0;
19501970

19511971
finally:

0 commit comments

Comments
 (0)