Skip to content

Commit 9b31385

Browse files
committed
[mypyc] Make for loop over list memory safe on free-threaded builds
1 parent 2f21f98 commit 9b31385

9 files changed

Lines changed: 35 additions & 20 deletions

mypyc/irbuild/for_helpers.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
Var,
2929
)
3030
from mypy.types import LiteralType, TupleType, get_proper_type, get_proper_types
31+
from mypyc.common import IS_FREE_THREADED
3132
from mypyc.ir.ops import (
3233
ERR_NEVER,
3334
BasicBlock,
@@ -81,7 +82,12 @@
8182
)
8283
from mypyc.primitives.exc_ops import no_err_occurred_op, propagate_if_error_op
8384
from mypyc.primitives.generic_ops import aiter_op, anext_op, iter_op, next_op
84-
from mypyc.primitives.list_ops import list_append_op, list_get_item_unsafe_op, new_list_set_item_op
85+
from mypyc.primitives.list_ops import (
86+
list_append_op,
87+
list_get_item_int64_op,
88+
list_get_item_unsafe_op,
89+
new_list_set_item_op,
90+
)
8591
from mypyc.primitives.misc_ops import stop_async_iteration_op
8692
from mypyc.primitives.registry import CFunctionDescription
8793
from mypyc.primitives.set_ops import set_add_op
@@ -866,7 +872,10 @@ def unsafe_index(builder: IRBuilder, target: Value, index: Value, line: int) ->
866872
# since we want to use __getitem__ if we don't have an unsafe version,
867873
# so we just check manually.
868874
if is_list_rprimitive(target.type):
869-
return builder.primitive_op(list_get_item_unsafe_op, [target, index], line)
875+
if not IS_FREE_THREADED:
876+
return builder.primitive_op(list_get_item_unsafe_op, [target, index], line)
877+
else:
878+
return builder.primitive_op(list_get_item_int64_op, [target, index], line)
870879
elif is_tuple_rprimitive(target.type):
871880
return builder.call_c(tuple_get_item_unsafe_op, [target, index], line)
872881
elif is_str_rprimitive(target.type):

mypyc/test-data/irbuild-basic.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1870,7 +1870,7 @@ L0:
18701870
r5 = a.f(12, 6, r4)
18711871
return 1
18721872

1873-
[case testListComprehension]
1873+
[case testListComprehension_withgil]
18741874
from typing import List
18751875

18761876
def f() -> List[int]:
@@ -1931,7 +1931,7 @@ L7:
19311931
L8:
19321932
return r0
19331933

1934-
[case testDictComprehension]
1934+
[case testDictComprehension_withgil]
19351935
from typing import Dict
19361936
def f() -> Dict[int, int]:
19371937
return {x: x*x for x in [1,2,3] if x != 2 if x != 3}
@@ -1993,7 +1993,7 @@ L7:
19931993
L8:
19941994
return r0
19951995

1996-
[case testLoopsMultipleAssign]
1996+
[case testLoopsMultipleAssign_withgil]
19971997
from typing import List, Tuple
19981998
def f(l: List[Tuple[int, int, int]]) -> List[int]:
19991999
for x, y, z in l:

mypyc/test-data/irbuild-lists.test

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ L0:
379379
r2 = r1 >= 0 :: signed
380380
return 1
381381

382-
[case testListBuiltFromGenerator]
382+
[case testListBuiltFromGenerator_withgil]
383383
from typing import List
384384
def f(source: List[int]) -> None:
385385
a = list(x + 1 for x in source)
@@ -448,7 +448,7 @@ L8:
448448
b = r11
449449
return 1
450450

451-
[case testGeneratorNext]
451+
[case testGeneratorNext_withgil]
452452
from typing import List, Optional
453453

454454
def test(x: List[int]) -> None:
@@ -489,7 +489,7 @@ L5:
489489
res = r6
490490
return 1
491491

492-
[case testSimplifyListUnion]
492+
[case testSimplifyListUnion_withgil]
493493
from typing import List, Union, Optional
494494

495495
def narrow(a: Union[List[str], List[bytes], int]) -> int:
@@ -923,7 +923,7 @@ L10:
923923
a = r3
924924
return 1
925925

926-
[case testListBuiltFromStars]
926+
[case testListBuiltFromStars_withgil]
927927
from typing import Final
928928

929929
abc: Final = "abc"

mypyc/test-data/irbuild-set.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ L0:
5353
r0 = PySet_New(l)
5454
return r0
5555

56-
[case testNewSetFromIterable2]
56+
[case testNewSetFromIterable2_withgil]
5757
def f(x: int) -> int:
5858
return x
5959

@@ -273,7 +273,7 @@ L4:
273273
e = r0
274274
return 1
275275

276-
[case testNewSetFromIterable3]
276+
[case testNewSetFromIterable3_withgil]
277277
def f1(x: int) -> int:
278278
return x
279279

mypyc/test-data/irbuild-statements.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ L1:
243243
r2 = r0 < r1 :: signed
244244
if r2 goto L2 else goto L4 :: bool
245245
L2:
246-
r3 = list_get_item_unsafe ls, r0
246+
r3 = CPyList_GetItemInt64(ls, r0)
247247
r4 = unbox(int, r3)
248248
x = r4
249249
r5 = CPyTagged_Add(y, x)
@@ -899,7 +899,7 @@ L0:
899899
r6 = r5 >= 0 :: signed
900900
return 1
901901

902-
[case testForEnumerate]
902+
[case testForEnumerate_withgil]
903903
from typing import List, Iterable
904904

905905
def f(a: List[int]) -> None:
@@ -967,7 +967,7 @@ L4:
967967
L5:
968968
return 1
969969

970-
[case testForZip]
970+
[case testForZip_withgil]
971971
from typing import List, Iterable, Sequence
972972

973973
def f(a: List[int], b: Sequence[bool]) -> None:

mypyc/test-data/irbuild-tuple.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ L5:
281281
L6:
282282
return r6
283283

284-
[case testTupleBuiltFromList]
284+
[case testTupleBuiltFromList_withgil]
285285
def f(val: int) -> bool:
286286
return val % 2 == 0
287287

@@ -1018,7 +1018,7 @@ L5:
10181018
a = r42
10191019
return 1
10201020

1021-
[case testTupleBuiltFromStars]
1021+
[case testTupleBuiltFromStars_withgil]
10221022
from typing import Final
10231023

10241024
abc: Final = "abc"

mypyc/test-data/irbuild-vec-i64.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ L3:
334334
L4:
335335
return r1
336336

337-
[case testVecI64FastComprehensionFromList]
337+
[case testVecI64FastComprehensionFromList_nogil]
338338
from librt.vecs import vec
339339
from mypy_extensions import i64
340340
from typing import List
@@ -364,7 +364,7 @@ L1:
364364
r4 = r2 < r3 :: signed
365365
if r4 goto L2 else goto L4 :: bool
366366
L2:
367-
r5 = list_get_item_unsafe l, r2
367+
r5 = CPyList_GetItemInt64(l, r2)
368368
r6 = unbox(i64, r5)
369369
x = r6
370370
r7 = x + 1

mypyc/test-data/lowering-int.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ L4:
332332
L5:
333333
return 4
334334

335-
[case testLowerIntForLoop_64bit]
335+
[case testLowerIntForLoop_withgil_64bit]
336336
from __future__ import annotations
337337

338338
def f(l: list[int]) -> None:

mypyc/test/test_lowering.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from mypy.errors import CompileError
88
from mypy.test.config import test_temp_dir
99
from mypy.test.data import DataDrivenTestCase
10-
from mypyc.common import TOP_LEVEL_NAME
10+
from mypyc.common import IS_FREE_THREADED, TOP_LEVEL_NAME
1111
from mypyc.ir.pprint import format_func
1212
from mypyc.options import CompilerOptions
1313
from mypyc.test.testutil import (
@@ -36,6 +36,12 @@ def run_case(self, testcase: DataDrivenTestCase) -> None:
3636
if options is None:
3737
# Skipped test case
3838
return
39+
if "_withgil" in testcase.name and IS_FREE_THREADED:
40+
# Test case should only run on a non-free-threaded build.
41+
return
42+
if "_nogil" in testcase.name and not IS_FREE_THREADED:
43+
# Test case should only run on a free-threaded build.
44+
return
3945
with use_custom_builtins(os.path.join(self.data_prefix, ICODE_GEN_BUILTINS), testcase):
4046
expected_output = remove_comment_lines(testcase.output)
4147
expected_output = replace_word_size(expected_output)

0 commit comments

Comments
 (0)