Skip to content

Commit f5fa85b

Browse files
authored
Fix duplicate Iter in type being cached. (#24)
Things like `ConcatTuples[tuple[int, str], tuple[int, str]]`
1 parent 85ffd4a commit f5fa85b

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

tests/test_type_eval.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,22 @@ def test_eval_iter_01():
665665
assert tuple(d) == ()
666666

667667

668+
type DuplicateTuple[T] = tuple[*[x for x in Iter[T]], *[x for x in Iter[T]]]
669+
type ConcatTupleWithSelf[T] = ConcatTuples[T, T]
670+
671+
672+
def test_eval_iter_02():
673+
# ensure iterating duplicate tuples can be iterated multiple times
674+
d = eval_typing(ConcatTuples[tuple[int, str], tuple[int, str]])
675+
assert d == tuple[int, str, int, str]
676+
677+
d = eval_typing(DuplicateTuple[tuple[int, str]])
678+
assert d == tuple[int, str, int, str]
679+
680+
d = eval_typing(ConcatTupleWithSelf[tuple[int, str]])
681+
assert d == tuple[int, str, int, str]
682+
683+
668684
def test_eval_length_01():
669685
d = eval_typing(Length[tuple[int, str]])
670686
assert d == Literal[2]

typemap/type_eval/_eval_typing.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import annotationlib
22

3+
import collections.abc
34
import contextlib
45
import contextvars
56
import dataclasses
@@ -231,7 +232,10 @@ def _eval_types(obj: typing.Any, ctx: EvalContext):
231232
ctx.resolved |= {x: x for x in child_ctx.known_recursive_types.keys()}
232233
ctx.known_recursive_types |= child_ctx.known_recursive_types
233234

234-
ctx.resolved[obj] = evaled
235+
# Don't cache iterators as they are stateful and can only be consumed once.
236+
# This is important for Iter results that may be used multiple times.
237+
if not isinstance(evaled, collections.abc.Iterator):
238+
ctx.resolved[obj] = evaled
235239
return evaled
236240

237241

0 commit comments

Comments
 (0)