Skip to content

Commit 219d8d2

Browse files
gh-87859: Track Code Object Local Kinds For Arguments (gh-132980)
Doing this was always the intention. I was finally motivated to find the time to do it. See #87859 (comment).
1 parent 96a7fb9 commit 219d8d2

File tree

6 files changed

+372
-194
lines changed

6 files changed

+372
-194
lines changed

Include/internal/pycore_code.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,14 @@ typedef struct {
177177
*/
178178

179179
// Note that these all fit within a byte, as do combinations.
180-
// Later, we will use the smaller numbers to differentiate the different
181-
// kinds of locals (e.g. pos-only arg, varkwargs, local-only).
182-
#define CO_FAST_HIDDEN 0x10
183-
#define CO_FAST_LOCAL 0x20
184-
#define CO_FAST_CELL 0x40
185-
#define CO_FAST_FREE 0x80
180+
#define CO_FAST_ARG_POS (0x02) // pos-only, pos-or-kw, varargs
181+
#define CO_FAST_ARG_KW (0x04) // kw-only, pos-or-kw, varkwargs
182+
#define CO_FAST_ARG_VAR (0x08) // varargs, varkwargs
183+
#define CO_FAST_ARG (CO_FAST_ARG_POS | CO_FAST_ARG_KW | CO_FAST_ARG_VAR)
184+
#define CO_FAST_HIDDEN (0x10)
185+
#define CO_FAST_LOCAL (0x20)
186+
#define CO_FAST_CELL (0x40)
187+
#define CO_FAST_FREE (0x80)
186188

187189
typedef unsigned char _PyLocals_Kind;
188190

Lib/test/_code_definitions.py

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
2+
3+
def spam_minimal():
4+
# no arg defaults or kwarg defaults
5+
# no annotations
6+
# no local vars
7+
# no free vars
8+
# no globals
9+
# no builtins
10+
# no attr access (names)
11+
# no code
12+
return
13+
14+
15+
def spam_full(a, b, /, c, d:int=1, *args, e, f:object=None, **kwargs) -> tuple:
16+
# arg defaults, kwarg defaults
17+
# annotations
18+
# all kinds of local vars, except cells
19+
# no free vars
20+
# some globals
21+
# some builtins
22+
# some attr access (names)
23+
x = args
24+
y = kwargs
25+
z = (a, b, c, d)
26+
kwargs['e'] = e
27+
kwargs['f'] = f
28+
extras = list((x, y, z, spam, spam.__name__))
29+
return tuple(a, b, c, d, e, f, args, kwargs), extras
30+
31+
32+
def spam(x):
33+
return x, None
34+
35+
36+
def spam_N(x):
37+
def eggs_nested(y):
38+
return None, y
39+
return eggs_nested, x
40+
41+
42+
def spam_C(x):
43+
a = 1
44+
def eggs_closure(y):
45+
return None, y, a, x
46+
return eggs_closure, a, x
47+
48+
49+
def spam_NN(x):
50+
def eggs_nested_N(y):
51+
def ham_nested(z):
52+
return None, z
53+
return ham_nested, y
54+
return eggs_nested_N, x
55+
56+
57+
def spam_NC(x):
58+
a = 1
59+
def eggs_nested_C(y):
60+
def ham_closure(z):
61+
return None, z, y, a, x
62+
return ham_closure, y
63+
return eggs_nested_C, a, x
64+
65+
66+
def spam_CN(x):
67+
a = 1
68+
def eggs_closure_N(y):
69+
def ham_C_nested(z):
70+
return None, z
71+
return ham_C_nested, y, a, x
72+
return eggs_closure_N, a, x
73+
74+
75+
def spam_CC(x):
76+
a = 1
77+
def eggs_closure_C(y):
78+
b = 2
79+
def ham_C_closure(z):
80+
return None, z, b, y, a, x
81+
return ham_C_closure, b, y, a, x
82+
return eggs_closure_C, a, x
83+
84+
85+
eggs_nested, *_ = spam_N(1)
86+
eggs_closure, *_ = spam_C(1)
87+
eggs_nested_N, *_ = spam_NN(1)
88+
eggs_nested_C, *_ = spam_NC(1)
89+
eggs_closure_N, *_ = spam_CN(1)
90+
eggs_closure_C, *_ = spam_CC(1)
91+
92+
ham_nested, *_ = eggs_nested_N(2)
93+
ham_closure, *_ = eggs_nested_C(2)
94+
ham_C_nested, *_ = eggs_closure_N(2)
95+
ham_C_closure, *_ = eggs_closure_C(2)
96+
97+
98+
TOP_FUNCTIONS = [
99+
# shallow
100+
spam_minimal,
101+
spam_full,
102+
spam,
103+
# outer func
104+
spam_N,
105+
spam_C,
106+
spam_NN,
107+
spam_NC,
108+
spam_CN,
109+
spam_CC,
110+
]
111+
NESTED_FUNCTIONS = [
112+
# inner func
113+
eggs_nested,
114+
eggs_closure,
115+
eggs_nested_N,
116+
eggs_nested_C,
117+
eggs_closure_N,
118+
eggs_closure_C,
119+
# inner inner func
120+
ham_nested,
121+
ham_closure,
122+
ham_C_nested,
123+
ham_C_closure,
124+
]
125+
FUNCTIONS = [
126+
*TOP_FUNCTIONS,
127+
*NESTED_FUNCTIONS,
128+
]
129+
130+
131+
# generators
132+
133+
def gen_spam_1(*args):
134+
for arg in args:
135+
yield arg
136+
137+
138+
def gen_spam_2(*args):
139+
yield from args
140+
141+
142+
async def async_spam():
143+
pass
144+
coro_spam = async_spam()
145+
coro_spam.close()
146+
147+
148+
async def asyncgen_spam(*args):
149+
for arg in args:
150+
yield arg
151+
asynccoro_spam = asyncgen_spam(1, 2, 3)
152+
153+
154+
FUNCTION_LIKE = [
155+
gen_spam_1,
156+
gen_spam_2,
157+
async_spam,
158+
asyncgen_spam,
159+
]
160+
FUNCTION_LIKE_APPLIED = [
161+
coro_spam, # actually FunctionType?
162+
asynccoro_spam, # actually FunctionType?
163+
]

Lib/test/_crossinterp_definitions.py

+2-165
Original file line numberDiff line numberDiff line change
@@ -3,172 +3,9 @@
33

44

55
#######################################
6-
# functions
7-
8-
def spam_minimal():
9-
# no arg defaults or kwarg defaults
10-
# no annotations
11-
# no local vars
12-
# no free vars
13-
# no globals
14-
# no builtins
15-
# no attr access (names)
16-
# no code
17-
return
18-
19-
20-
def spam_full(a, b, /, c, d:int=1, *args, e, f:object=None, **kwargs) -> tuple:
21-
# arg defaults, kwarg defaults
22-
# annotations
23-
# all kinds of local vars, except cells
24-
# no free vars
25-
# some globals
26-
# some builtins
27-
# some attr access (names)
28-
x = args
29-
y = kwargs
30-
z = (a, b, c, d)
31-
kwargs['e'] = e
32-
kwargs['f'] = f
33-
extras = list((x, y, z, spam, spam.__name__))
34-
return tuple(a, b, c, d, e, f, args, kwargs), extras
35-
36-
37-
def spam(x):
38-
return x, None
39-
40-
41-
def spam_N(x):
42-
def eggs_nested(y):
43-
return None, y
44-
return eggs_nested, x
45-
46-
47-
def spam_C(x):
48-
a = 1
49-
def eggs_closure(y):
50-
return None, y, a, x
51-
return eggs_closure, a, x
52-
53-
54-
def spam_NN(x):
55-
def eggs_nested_N(y):
56-
def ham_nested(z):
57-
return None, z
58-
return ham_nested, y
59-
return eggs_nested_N, x
60-
61-
62-
def spam_NC(x):
63-
a = 1
64-
def eggs_nested_C(y):
65-
def ham_closure(z):
66-
return None, z, y, a, x
67-
return ham_closure, y
68-
return eggs_nested_C, a, x
69-
70-
71-
def spam_CN(x):
72-
a = 1
73-
def eggs_closure_N(y):
74-
def ham_C_nested(z):
75-
return None, z
76-
return ham_C_nested, y, a, x
77-
return eggs_closure_N, a, x
78-
79-
80-
def spam_CC(x):
81-
a = 1
82-
def eggs_closure_C(y):
83-
b = 2
84-
def ham_C_closure(z):
85-
return None, z, b, y, a, x
86-
return ham_C_closure, b, y, a, x
87-
return eggs_closure_N, a, x
88-
89-
90-
eggs_nested, *_ = spam_N(1)
91-
eggs_closure, *_ = spam_C(1)
92-
eggs_nested_N, *_ = spam_NN(1)
93-
eggs_nested_C, *_ = spam_NC(1)
94-
eggs_closure_N, *_ = spam_CN(1)
95-
eggs_closure_C, *_ = spam_CC(1)
96-
97-
ham_nested, *_ = eggs_nested_N(2)
98-
ham_closure, *_ = eggs_nested_C(2)
99-
ham_C_nested, *_ = eggs_closure_N(2)
100-
ham_C_closure, *_ = eggs_closure_C(2)
101-
102-
103-
TOP_FUNCTIONS = [
104-
# shallow
105-
spam_minimal,
106-
spam_full,
107-
spam,
108-
# outer func
109-
spam_N,
110-
spam_C,
111-
spam_NN,
112-
spam_NC,
113-
spam_CN,
114-
spam_CC,
115-
]
116-
NESTED_FUNCTIONS = [
117-
# inner func
118-
eggs_nested,
119-
eggs_closure,
120-
eggs_nested_N,
121-
eggs_nested_C,
122-
eggs_closure_N,
123-
eggs_closure_C,
124-
# inner inner func
125-
ham_nested,
126-
ham_closure,
127-
ham_C_nested,
128-
ham_C_closure,
129-
]
130-
FUNCTIONS = [
131-
*TOP_FUNCTIONS,
132-
*NESTED_FUNCTIONS,
133-
]
134-
135-
136-
#######################################
137-
# function-like
138-
139-
# generators
140-
141-
def gen_spam_1(*args):
142-
for arg in args:
143-
yield arg
144-
6+
# functions and generators
1457

146-
def gen_spam_2(*args):
147-
yield from args
148-
149-
150-
async def async_spam():
151-
pass
152-
coro_spam = async_spam()
153-
coro_spam.close()
154-
155-
156-
async def asyncgen_spam(*args):
157-
for arg in args:
158-
yield arg
159-
asynccoro_spam = asyncgen_spam(1, 2, 3)
160-
161-
162-
FUNCTION_LIKE = [
163-
gen_spam_1,
164-
gen_spam_2,
165-
async_spam,
166-
asyncgen_spam,
167-
]
168-
FUNCTION_LIKE_APPLIED = [
169-
coro_spam, # actually FunctionType?
170-
asynccoro_spam, # actually FunctionType?
171-
]
8+
from test._code_definitions import *
1729

17310

17411
#######################################

0 commit comments

Comments
 (0)