Skip to content

Commit 12aa642

Browse files
authored
1 parent 4629de4 commit 12aa642

File tree

9 files changed

+131
-3
lines changed

9 files changed

+131
-3
lines changed

mypyc/doc/list_operations.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Operators
3232

3333
* ``lst[n]`` (get item by integer index)
3434
* ``lst[n:m]``, ``lst[n:]``, ``lst[:m]``, ``lst[:]`` (slicing)
35+
* ``lst1 + lst2``, ``lst += iter``
3536
* ``lst * n``, ``n * lst``
3637
* ``obj in lst``
3738

mypyc/doc/tuple_operations.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Operators
2121

2222
* ``tup[n]`` (integer index)
2323
* ``tup[n:m]``, ``tup[n:]``, ``tup[:m]`` (slicing)
24+
* ``tup1 + tup2``
2425

2526
Statements
2627
----------

mypyc/primitives/list_ops.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,24 @@
271271
error_kind=ERR_MAGIC,
272272
)
273273

274+
# list + list
275+
binary_op(
276+
name="+",
277+
arg_types=[list_rprimitive, list_rprimitive],
278+
return_type=list_rprimitive,
279+
c_function_name="PySequence_Concat",
280+
error_kind=ERR_MAGIC,
281+
)
282+
283+
# list += list
284+
binary_op(
285+
name="+=",
286+
arg_types=[list_rprimitive, object_rprimitive],
287+
return_type=list_rprimitive,
288+
c_function_name="PySequence_InPlaceConcat",
289+
error_kind=ERR_MAGIC,
290+
)
291+
274292
# list * int
275293
binary_op(
276294
name="*",

mypyc/primitives/tuple_ops.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
object_rprimitive,
1616
tuple_rprimitive,
1717
)
18-
from mypyc.primitives.registry import custom_op, function_op, load_address_op, method_op
18+
from mypyc.primitives.registry import binary_op, custom_op, function_op, load_address_op, method_op
1919

2020
# Get the 'builtins.tuple' type object.
2121
load_address_op(name="builtins.tuple", type=object_rprimitive, src="PyTuple_Type")
@@ -74,6 +74,15 @@
7474
error_kind=ERR_MAGIC,
7575
)
7676

77+
# tuple + tuple
78+
binary_op(
79+
name="+",
80+
arg_types=[tuple_rprimitive, tuple_rprimitive],
81+
return_type=tuple_rprimitive,
82+
c_function_name="PySequence_Concat",
83+
error_kind=ERR_MAGIC,
84+
)
85+
7786
# tuple[begin:end]
7887
tuple_slice_op = custom_op(
7988
arg_types=[tuple_rprimitive, int_rprimitive, int_rprimitive],

mypyc/test-data/fixtures/ir.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ def __getitem__(self, i: slice) -> Tuple[T_co, ...]: pass
208208
def __len__(self) -> int: pass
209209
def __iter__(self) -> Iterator[T_co]: ...
210210
def __contains__(self, item: object) -> int: ...
211+
@overload
212+
def __add__(self, value: Tuple[T_co, ...], /) -> Tuple[T_co, ...]: ...
213+
@overload
214+
def __add__(self, value: Tuple[_T, ...], /) -> Tuple[T_co | _T, ...]: ...
211215

212216
class function: pass
213217

@@ -224,7 +228,11 @@ def __rmul__(self, i: int) -> List[_T]: pass
224228
def __iter__(self) -> Iterator[_T]: pass
225229
def __len__(self) -> int: pass
226230
def __contains__(self, item: object) -> int: ...
227-
def __add__(self, x: List[_T]) -> List[_T]: ...
231+
@overload
232+
def __add__(self, value: List[_T], /) -> List[_T]: ...
233+
@overload
234+
def __add__(self, value: List[_S], /) -> List[_S | _T]: ...
235+
def __iadd__(self, value: Iterable[_T], /) -> List[_T]: ... # type: ignore[misc]
228236
def append(self, x: _T) -> None: pass
229237
def pop(self, i: int = -1) -> _T: pass
230238
def count(self, _T) -> int: pass

mypyc/test-data/irbuild-lists.test

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,32 @@ L0:
145145
x = r10
146146
return 1
147147

148+
[case testListAdd]
149+
from typing import List
150+
def f(a: List[int], b: List[int]) -> None:
151+
c = a + b
152+
[out]
153+
def f(a, b):
154+
a, b, r0, c :: list
155+
L0:
156+
r0 = PySequence_Concat(a, b)
157+
c = r0
158+
return 1
159+
160+
[case testListIAdd]
161+
from typing import List, Any
162+
def f(a: List[int], b: Any) -> None:
163+
a += b
164+
[out]
165+
def f(a, b):
166+
a :: list
167+
b :: object
168+
r0 :: list
169+
L0:
170+
r0 = PySequence_InPlaceConcat(a, b)
171+
a = r0
172+
return 1
173+
148174
[case testListMultiply]
149175
from typing import List
150176
def f(a: List[int]) -> None:

mypyc/test-data/irbuild-tuple.test

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,3 +384,37 @@ L3:
384384
L4:
385385
a = r1
386386
return 1
387+
388+
[case testTupleAdd]
389+
from typing import Tuple
390+
def f(a: Tuple[int, ...], b: Tuple[int, ...]) -> None:
391+
c = a + b
392+
d = a + (1, 2)
393+
def g(a: Tuple[int, int], b: Tuple[int, int]) -> None:
394+
c = a + b
395+
[out]
396+
def f(a, b):
397+
a, b, r0, c :: tuple
398+
r1 :: tuple[int, int]
399+
r2 :: object
400+
r3, d :: tuple
401+
L0:
402+
r0 = PySequence_Concat(a, b)
403+
c = r0
404+
r1 = (2, 4)
405+
r2 = box(tuple[int, int], r1)
406+
r3 = PySequence_Concat(a, r2)
407+
d = r3
408+
return 1
409+
def g(a, b):
410+
a, b :: tuple[int, int]
411+
r0, r1 :: object
412+
r2 :: tuple
413+
r3, c :: tuple[int, int, int, int]
414+
L0:
415+
r0 = box(tuple[int, int], a)
416+
r1 = box(tuple[int, int], b)
417+
r2 = PySequence_Concat(r0, r1)
418+
r3 = unbox(tuple[int, int, int, int], r2)
419+
c = r3
420+
return 1

mypyc/test-data/run-lists.test

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ print(g())
267267
7
268268

269269
[case testListOps]
270+
from typing import Any, cast
271+
from testutil import assertRaises
272+
270273
def test_slicing() -> None:
271274
# Use dummy adds to avoid constant folding
272275
zero = int()
@@ -289,6 +292,27 @@ def test_slicing() -> None:
289292
assert s[long_int:] == []
290293
assert s[-long_int:-1] == ["f", "o", "o", "b", "a"]
291294

295+
def in_place_add(l2: Any) -> list[Any]:
296+
l1 = [1, 2]
297+
l1 += l2
298+
return l1
299+
300+
def test_add() -> None:
301+
res = [1, 2, 3, 4]
302+
assert [1, 2] + [3, 4] == res
303+
with assertRaises(TypeError, 'can only concatenate list (not "tuple") to list'):
304+
assert [1, 2] + cast(Any, (3, 4)) == res
305+
l1 = [1, 2]
306+
id_l1 = id(l1)
307+
l1 += [3, 4]
308+
assert l1 == res
309+
assert id_l1 == id(l1)
310+
assert in_place_add([3, 4]) == res
311+
assert in_place_add((3, 4)) == res
312+
assert in_place_add({3, 4}) == res
313+
assert in_place_add({3: "", 4: ""}) == res
314+
assert in_place_add(range(3, 5)) == res
315+
292316
[case testOperatorInExpression]
293317

294318
def tuple_in_int0(i: int) -> bool:

mypyc/test-data/run-tuples.test

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ assert Record.__annotations__ == {
146146
}, Record.__annotations__
147147

148148
[case testTupleOps]
149-
from typing import Tuple, Final, List, Any, Optional
149+
from typing import Tuple, Final, List, Any, Optional, cast
150+
from testutil import assertRaises
150151

151152
def f() -> Tuple[()]:
152153
return ()
@@ -254,3 +255,9 @@ TUPLE: Final[Tuple[str, ...]] = ('x', 'y')
254255
def test_final_boxed_tuple() -> None:
255256
t = TUPLE
256257
assert t == ('x', 'y')
258+
259+
def test_add() -> None:
260+
res = (1, 2, 3, 4)
261+
assert (1, 2) + (3, 4) == res
262+
with assertRaises(TypeError, 'can only concatenate tuple (not "list") to tuple'):
263+
assert (1, 2) + cast(Any, [3, 4]) == res

0 commit comments

Comments
 (0)