Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit96a7fb9

Browse files
gh-132775: Add _PyCode_ReturnsOnlyNone() (gh-132981)
The function indicates whether or not the function has a return statement.This is used by a later change related treating some functions like scripts.
1 parent75cbb8d commit96a7fb9

File tree

6 files changed

+123
-1
lines changed

6 files changed

+123
-1
lines changed

‎Include/internal/pycore_code.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,10 @@ extern void _Py_ClearTLBCIndex(_PyThreadStateImpl *tstate);
561561
externint_Py_ClearUnusedTLBC(PyInterpreterState*interp);
562562
#endif
563563

564+
565+
PyAPI_FUNC(int)_PyCode_ReturnsOnlyNone(PyCodeObject*);
566+
567+
564568
#ifdef__cplusplus
565569
}
566570
#endif

‎Include/internal/pycore_opcode_utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ extern "C" {
5454
(opcode) == RAISE_VARARGS || \
5555
(opcode) == RERAISE)
5656

57+
#defineIS_RETURN_OPCODE(opcode) \
58+
(opcode == RETURN_VALUE)
59+
5760

5861
/* Flags used in the oparg for MAKE_FUNCTION */
5962
#defineMAKE_FUNCTION_DEFAULTS 0x01

‎Lib/test/test_code.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@
216216
fromtest.support.bytecode_helperimportinstructions_with_positions
217217
fromopcodeimportopmap,opname
218218
from_testcapiimportcode_offset_to_line
219+
try:
220+
import_testinternalcapi
221+
exceptModuleNotFoundError:
222+
_testinternalcapi=None
219223

220224
COPY_FREE_VARS=opmap['COPY_FREE_VARS']
221225

@@ -425,6 +429,61 @@ def func():
425429
withself.assertWarns(DeprecationWarning):
426430
func.__code__.co_lnotab
427431

432+
@unittest.skipIf(_testinternalcapiisNone,'_testinternalcapi is missing')
433+
deftest_returns_only_none(self):
434+
value=True
435+
436+
defspam1():
437+
pass
438+
defspam2():
439+
return
440+
defspam3():
441+
returnNone
442+
defspam4():
443+
ifnotvalue:
444+
return
445+
...
446+
defspam5():
447+
ifnotvalue:
448+
returnNone
449+
...
450+
lambda1= (lambda:None)
451+
forfuncin [
452+
spam1,
453+
spam2,
454+
spam3,
455+
spam4,
456+
spam5,
457+
lambda1,
458+
]:
459+
withself.subTest(func):
460+
res=_testinternalcapi.code_returns_only_none(func.__code__)
461+
self.assertTrue(res)
462+
463+
defspam6():
464+
returnTrue
465+
defspam7():
466+
returnvalue
467+
defspam8():
468+
ifvalue:
469+
returnNone
470+
returnTrue
471+
defspam9():
472+
ifvalue:
473+
returnTrue
474+
returnNone
475+
lambda2= (lambda:True)
476+
forfuncin [
477+
spam6,
478+
spam7,
479+
spam8,
480+
spam9,
481+
lambda2,
482+
]:
483+
withself.subTest(func):
484+
res=_testinternalcapi.code_returns_only_none(func.__code__)
485+
self.assertFalse(res)
486+
428487
deftest_invalid_bytecode(self):
429488
deffoo():
430489
pass

‎Modules/_testinternalcapi.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,18 @@ iframe_getlasti(PyObject *self, PyObject *frame)
945945
returnPyLong_FromLong(PyUnstable_InterpreterFrame_GetLasti(f));
946946
}
947947

948+
staticPyObject*
949+
code_returns_only_none(PyObject*self,PyObject*arg)
950+
{
951+
if (!PyCode_Check(arg)) {
952+
PyErr_SetString(PyExc_TypeError,"argument must be a code object");
953+
returnNULL;
954+
}
955+
PyCodeObject*code= (PyCodeObject*)arg;
956+
intres=_PyCode_ReturnsOnlyNone(code);
957+
returnPyBool_FromLong(res);
958+
}
959+
948960
staticPyObject*
949961
get_co_framesize(PyObject*self,PyObject*arg)
950962
{
@@ -2074,6 +2086,7 @@ static PyMethodDef module_functions[] = {
20742086
{"iframe_getcode",iframe_getcode,METH_O,NULL},
20752087
{"iframe_getline",iframe_getline,METH_O,NULL},
20762088
{"iframe_getlasti",iframe_getlasti,METH_O,NULL},
2089+
{"code_returns_only_none",code_returns_only_none,METH_O,NULL},
20772090
{"get_co_framesize",get_co_framesize,METH_O,NULL},
20782091
{"jit_enabled",jit_enabled,METH_NOARGS,NULL},
20792092
#ifdef_Py_TIER2

‎Objects/codeobject.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,6 +1689,49 @@ PyCode_GetFreevars(PyCodeObject *code)
16891689
return_PyCode_GetFreevars(code);
16901690
}
16911691

1692+
1693+
/* Here "value" means a non-None value, since a bare return is identical
1694+
* to returning None explicitly. Likewise a missing return statement
1695+
* at the end of the function is turned into "return None". */
1696+
int
1697+
_PyCode_ReturnsOnlyNone(PyCodeObject*co)
1698+
{
1699+
// Look up None in co_consts.
1700+
Py_ssize_tnconsts=PyTuple_Size(co->co_consts);
1701+
intnone_index=0;
1702+
for (;none_index<nconsts;none_index++) {
1703+
if (PyTuple_GET_ITEM(co->co_consts,none_index)==Py_None) {
1704+
break;
1705+
}
1706+
}
1707+
if (none_index==nconsts) {
1708+
// None wasn't there, which means there was no implicit return,
1709+
// "return", or "return None". That means there must be
1710+
// an explicit return (non-None).
1711+
return0;
1712+
}
1713+
1714+
// Walk the bytecode, looking for RETURN_VALUE.
1715+
Py_ssize_tlen=Py_SIZE(co);
1716+
for (inti=0;i<len;i++) {
1717+
_Py_CODEUNITinst=_Py_GetBaseCodeUnit(co,i);
1718+
if (IS_RETURN_OPCODE(inst.op.code)) {
1719+
assert(i!=0);
1720+
// Ignore it if it returns None.
1721+
_Py_CODEUNITprev=_Py_GetBaseCodeUnit(co,i-1);
1722+
if (prev.op.code==LOAD_CONST) {
1723+
// We don't worry about EXTENDED_ARG for now.
1724+
if (prev.op.arg==none_index) {
1725+
continue;
1726+
}
1727+
}
1728+
return0;
1729+
}
1730+
}
1731+
return1;
1732+
}
1733+
1734+
16921735
#ifdef_Py_TIER2
16931736

16941737
staticvoid

‎Python/flowgraph.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ dump_instr(cfg_instr *i)
295295
staticinlineint
296296
basicblock_returns(constbasicblock*b) {
297297
cfg_instr*last=basicblock_last_instr(b);
298-
returnlast&&last->i_opcode==RETURN_VALUE;
298+
returnlast&&IS_RETURN_OPCODE(last->i_opcode);
299299
}
300300

301301
staticvoid

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp