@@ -347,3 +347,73 @@ async def sleep(t: float) -> None: ...
347347def run(x: object) -> object: ...
348348
349349[typing fixtures/typing-full.pyi]
350+
351+ [case testRunAsyncRefCounting]
352+ import asyncio
353+ import gc
354+
355+ def assert_no_leaks(fn, max_new):
356+ asyncio.run(fn())
357+ gc.collect()
358+ old_objs = gc.get_objects()
359+ for i in range(10):
360+ asyncio.run(fn())
361+ gc.collect()
362+ new_objs = gc.get_objects()
363+ delta = len(new_objs) - len(old_objs)
364+ assert delta <= max_new, delta
365+
366+ async def concat_one(x: str) -> str:
367+ return x + "1"
368+
369+ async def foo(n: int) -> str:
370+ s = ""
371+ while len(s) < n:
372+ s = await concat_one(s)
373+ return s
374+
375+ def test_trivial() -> None:
376+ assert_no_leaks(lambda: foo(1000), 5)
377+
378+ async def make_list(a: list[int]) -> list[int]:
379+ await concat_one("foobar")
380+ return [a[0]]
381+
382+ async def spill() -> list[int]:
383+ a: list[int] = []
384+ for i in range(5):
385+ a = (await make_list(a + [1])) + a + (await make_list(a + [2]))
386+ return a
387+
388+ async def bar(n: int) -> None:
389+ for i in range(n):
390+ await spill()
391+
392+ def test_spilled() -> None:
393+ assert_no_leaks(lambda: bar(100), 2)
394+
395+ async def raise_deep(n: int) -> str:
396+ if n == 0:
397+ raise TypeError(str(n))
398+ else:
399+ return await raise_deep(n - 1)
400+
401+ async def maybe_raise(n: int) -> str:
402+ if n % 3 == 0:
403+ await raise_deep(10)
404+ return str(n)
405+
406+ async def exc(n: int) -> list[str]:
407+ a = []
408+ for i in range(n):
409+ try:
410+ a.append(str(int()) + await maybe_raise(n))
411+ except TypeError:
412+ a.append(str(int() + 5))
413+ return a
414+
415+ def test_exception() -> None:
416+ assert_no_leaks(lambda: exc(100), 2)
417+
418+ [file asyncio/__init__.pyi]
419+ def run(x: object) -> object: ...
0 commit comments