From 07f3aab3055cbd3636190fd606aac804a4c0609f Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Mon, 1 Sep 2025 17:19:34 +0100 Subject: [PATCH 1/4] Fix stub --- mypyc/test-data/fixtures/ir.py | 4 ++-- mypyc/test-data/fixtures/typing-full.pyi | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mypyc/test-data/fixtures/ir.py b/mypyc/test-data/fixtures/ir.py index fb5512b77279..075a0eec28d2 100644 --- a/mypyc/test-data/fixtures/ir.py +++ b/mypyc/test-data/fixtures/ir.py @@ -243,7 +243,7 @@ def __add__(self, value: List[_S], /) -> List[_S | _T]: ... def __iadd__(self, value: Iterable[_T], /) -> List[_T]: ... # type: ignore[misc] def append(self, x: _T) -> None: pass def pop(self, i: int = -1) -> _T: pass - def count(self, _T) -> int: pass + def count(self, x: _T) -> int: pass def extend(self, l: Iterable[_T]) -> None: pass def insert(self, i: int, x: _T) -> None: pass def sort(self) -> None: pass @@ -365,7 +365,7 @@ def reversed(object: Sequence[_T]) -> Iterator[_T]: ... def id(o: object) -> int: pass # This type is obviously wrong but the test stubs don't have Sized anymore def len(o: object) -> int: pass -def print(*object) -> None: pass +def print(*args: object) -> None: pass def isinstance(x: object, t: object) -> bool: pass def iter(i: Iterable[_T]) -> Iterator[_T]: pass @overload diff --git a/mypyc/test-data/fixtures/typing-full.pyi b/mypyc/test-data/fixtures/typing-full.pyi index 8d89e4f93bc9..25aaaf700d05 100644 --- a/mypyc/test-data/fixtures/typing-full.pyi +++ b/mypyc/test-data/fixtures/typing-full.pyi @@ -11,10 +11,10 @@ from abc import abstractmethod, ABCMeta class GenericMeta(type): pass class _SpecialForm: - def __getitem__(self, index): ... + def __getitem__(self, index: Any) -> Any: ... class TypeVar: - def __init__(self, name, *args, bound=None): ... - def __or__(self, other): ... + def __init__(self, name: str, *args: Any, bound: Any = None): ... + def __or__(self, other: Any) -> Any: ... cast = 0 overload = 0 From 7640e9abf9386e491782bf50249b871b9ff26f1e Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 4 Sep 2025 16:22:26 +0100 Subject: [PATCH 2/4] Add annotations to tests --- mypyc/test-data/run-dunders.test | 38 +++++++++++++++++--------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/mypyc/test-data/run-dunders.test b/mypyc/test-data/run-dunders.test index ec992afbfbd1..634ac1a9a563 100644 --- a/mypyc/test-data/run-dunders.test +++ b/mypyc/test-data/run-dunders.test @@ -185,7 +185,7 @@ class SeqError: def __contains__(self, x: int) -> bool: raise RuntimeError() - def __len__(self): + def __len__(self) -> int: return -5 def any_seq_error() -> Any: @@ -595,16 +595,16 @@ def test_any_radd() -> None: assert d3 + e3 == 4 class F: - def __init__(self, v): + def __init__(self, v: Any): self.v = v - def __add__(self, x): + def __add__(self, x: Any) -> Any: if isinstance(x, int): return self.v + x return NotImplemented class G: - def __radd__(self, x): + def __radd__(self, x: Any) -> Any: if isinstance(x, F): return x.v + 1 if isinstance(x, str): @@ -627,12 +627,12 @@ def test_unannotated_radd() -> None: 1 + G() class H: - def __add__(self, x): + def __add__(self, x: Any) -> Any: if isinstance(x, int): return x + 1 return NotImplemented - def __radd__(self, x): + def __radd__(self, x: Any) -> Any: if isinstance(x, str): return 22 return NotImplemented @@ -647,37 +647,39 @@ def test_unannotated_add_and_radd_2() -> None: # TODO: Inheritance [case testDifferentReverseDunders] +from typing import Any + class C: # __radd__ and __rsub__ are tested elsewhere - def __rmul__(self, x): + def __rmul__(self, x: Any) -> int: return 1 - def __rtruediv__(self, x): + def __rtruediv__(self, x: Any) -> int: return 2 - def __rmod__(self, x): + def __rmod__(self, x: Any) -> int: return 3 - def __rfloordiv__(self, x): + def __rfloordiv__(self, x: Any) -> int: return 4 - def __rlshift__(self, x): + def __rlshift__(self, x: Any) -> int: return 5 - def __rrshift__(self, x): + def __rrshift__(self, x: Any) -> int: return 6 - def __rand__(self, x): + def __rand__(self, x: Any) -> int: return 7 - def __ror__(self, x): + def __ror__(self, x: Any) -> int: return 8 - def __rxor__(self, x): + def __rxor__(self, x: Any) -> int: return 9 - def __rmatmul__(self, x): + def __rmatmul__(self, x: Any) -> int: return 10 def test_reverse_dunders() -> None: @@ -803,10 +805,10 @@ def test_error() -> None: c += 'x' class BadInplaceAdd: - def __init__(self): + def __init__(self) -> None: self.x = 0 - def __iadd__(self, x): + def __iadd__(self, x: int) -> Any: self.x += x def test_in_place_operator_returns_none() -> None: From 625683024089e93d7ff76349a66ead634f404cc0 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 4 Sep 2025 16:53:48 +0100 Subject: [PATCH 3/4] Add annotations to test cases --- mypyc/test-data/run-singledispatch.test | 108 +++++++++++++++--------- 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/mypyc/test-data/run-singledispatch.test b/mypyc/test-data/run-singledispatch.test index a119c325984a..03b937261e22 100644 --- a/mypyc/test-data/run-singledispatch.test +++ b/mypyc/test-data/run-singledispatch.test @@ -4,9 +4,10 @@ [case testSpecializedImplementationUsed] from functools import singledispatch +from typing import Any @singledispatch -def fun(arg) -> bool: +def fun(arg: Any) -> bool: return False @fun.register @@ -19,11 +20,13 @@ def test_specialize() -> None: [case testSubclassesOfExpectedTypeUseSpecialized] from functools import singledispatch +from typing import Any + class A: pass class B(A): pass @singledispatch -def fun(arg) -> bool: +def fun(arg: Any) -> bool: return False @fun.register @@ -36,11 +39,13 @@ def test_specialize() -> None: [case testSuperclassImplementationNotUsedWhenSubclassHasImplementation] from functools import singledispatch +from typing import Any + class A: pass class B(A): pass @singledispatch -def fun(arg) -> bool: +def fun(arg: Any) -> bool: # shouldn't be using this assert False @@ -58,9 +63,10 @@ def test_specialize() -> None: [case testMultipleUnderscoreFunctionsIsntError] from functools import singledispatch +from typing import Any @singledispatch -def fun(arg) -> str: +def fun(arg: Any) -> str: return 'default' @fun.register @@ -72,7 +78,7 @@ def _(arg: int) -> str: return 'int' # extra function to make sure all 3 underscore functions aren't treated as one OverloadedFuncDef -def a(b): pass +def a(b: Any) -> Any: pass @fun.register def _(arg: list) -> str: @@ -86,10 +92,12 @@ def test_singledispatch() -> None: [case testCanRegisterCompiledClasses] from functools import singledispatch +from typing import Any + class A: pass @singledispatch -def fun(arg) -> bool: +def fun(arg: Any) -> bool: return False @fun.register def fun_specialized(arg: A) -> bool: @@ -101,13 +109,14 @@ def test_singledispatch() -> None: [case testTypeUsedAsArgumentToRegister] from functools import singledispatch +from typing import Any @singledispatch -def fun(arg) -> bool: +def fun(arg: Any) -> bool: return False @fun.register(int) -def fun_specialized(arg) -> bool: +def fun_specialized(arg: Any) -> bool: return True def test_singledispatch() -> None: @@ -116,12 +125,13 @@ def test_singledispatch() -> None: [case testUseRegisterAsAFunction] from functools import singledispatch +from typing import Any @singledispatch -def fun(arg) -> bool: +def fun(arg: Any) -> bool: return False -def fun_specialized_impl(arg) -> bool: +def fun_specialized_impl(arg: Any) -> bool: return True fun.register(int, fun_specialized_impl) @@ -132,13 +142,14 @@ def test_singledispatch() -> None: [case testRegisterDoesntChangeFunction] from functools import singledispatch +from typing import Any @singledispatch -def fun(arg) -> bool: +def fun(arg: Any) -> bool: return False @fun.register(int) -def fun_specialized(arg) -> bool: +def fun_specialized(arg: Any) -> bool: return True def test_singledispatch() -> None: @@ -147,9 +158,10 @@ def test_singledispatch() -> None: # TODO: turn this into a mypy error [case testNoneIsntATypeWhenUsedAsArgumentToRegister] from functools import singledispatch +from typing import Any @singledispatch -def fun(arg) -> bool: +def fun(arg: Any) -> bool: return False def test_argument() -> None: @@ -163,14 +175,15 @@ def test_argument() -> None: [case testRegisteringTheSameFunctionSeveralTimes] from functools import singledispatch +from typing import Any @singledispatch -def fun(arg) -> bool: +def fun(arg: Any) -> bool: return False @fun.register(int) @fun.register(str) -def fun_specialized(arg) -> bool: +def fun_specialized(arg: Any) -> bool: return True def test_singledispatch() -> None: @@ -179,11 +192,13 @@ def test_singledispatch() -> None: assert not fun([1, 2]) [case testTypeIsAnABC] +# mypy: allow-untyped-defs from functools import singledispatch from collections.abc import Mapping @singledispatch def fun(arg) -> bool: + # TODO: Adding an Any parameter annotation breaks the test case return False @fun.register @@ -241,6 +256,7 @@ def test_singledispatchmethod() -> None: [case testSingledispatchTreeSumAndEqual] from functools import singledispatch +from typing import cast class Tree: pass @@ -286,10 +302,10 @@ def build(n: int) -> Tree: return Leaf() return Node(n, build(n - 1), build(n - 1)) -def test_sum_and_equal(): +def test_sum_and_equal() -> None: tree = build(5) tree2 = build(5) - tree2.right.right.right.value = 10 + cast(Node, cast(Node, cast(Node, cast(Node, tree2).right).right).right).value = 10 assert calc_sum(tree) == 57 assert calc_sum(tree2) == 65 assert equal(tree, tree) @@ -354,7 +370,7 @@ def verify_typevarexpr(stub: TypeVarExpr, a: MaybeMissing[Any], b: List[str]) -> if False: yield None -def verify_list(stub, a, b) -> List[str]: +def verify_list(stub: Any, a: Any, b: Any) -> List[str]: """Helper function that converts iterator of errors to list of messages""" return list(err.msg for err in verify(stub, a, b)) @@ -368,31 +384,33 @@ def test_verify() -> None: [case testArgsInRegisteredImplNamedDifferentlyFromMainFunction] from functools import singledispatch +from typing import Any @singledispatch -def f(a) -> bool: +def f(a: Any) -> bool: return False @f.register def g(b: int) -> bool: return True -def test_singledispatch(): +def test_singledispatch() -> None: assert f(5) assert not f('a') [case testKeywordArguments] from functools import singledispatch +from typing import Any @singledispatch -def f(arg, *, kwarg: int = 0) -> int: +def f(arg: Any, *, kwarg: int = 0) -> int: return kwarg + 10 @f.register def g(arg: int, *, kwarg: int = 5) -> int: return kwarg - 10 -def test_keywords(): +def test_keywords() -> None: assert f('a') == 10 assert f('a', kwarg=3) == 13 assert f('a', kwarg=7) == 17 @@ -413,14 +431,14 @@ def f(arg: Any) -> Iterable[int]: def g(arg: str) -> Iterable[int]: return [0] -def test_iterables(): +def test_iterables() -> None: assert f(1) != [1] assert list(f(1)) == [1] assert f('a') == [0] [case testRegisterUsedAtSameTimeAsOtherDecorators] from functools import singledispatch -from typing import TypeVar +from typing import TypeVar, Any class A: pass class B: pass @@ -431,7 +449,7 @@ def decorator(f: T) -> T: return f @singledispatch -def f(arg) -> int: +def f(arg: Any) -> int: return 0 @f.register @@ -439,7 +457,7 @@ def f(arg) -> int: def h(arg: str) -> int: return 2 -def test_singledispatch(): +def test_singledispatch() -> None: assert f(1) == 0 assert f('a') == 2 @@ -450,12 +468,12 @@ from typing import Callable, Any class A: pass def decorator(f: Callable[[Any], int]) -> Callable[[Any], int]: - def wrapper(x) -> int: + def wrapper(x: Any) -> int: return f(x) * 7 return wrapper @singledispatch -def f(arg) -> int: +def f(arg: Any) -> int: return 10 @f.register @@ -464,17 +482,19 @@ def h(arg: str) -> int: return 5 -def test_singledispatch(): +def test_singledispatch() -> None: assert f('a') == 35 assert f(A()) == 10 [case testMoreSpecificTypeBeforeLessSpecificType] from functools import singledispatch +from typing import Any + class A: pass class B(A): pass @singledispatch -def f(arg) -> str: +def f(arg: Any) -> str: return 'default' @f.register @@ -485,20 +505,21 @@ def g(arg: B) -> str: def h(arg: A) -> str: return 'a' -def test_singledispatch(): +def test_singledispatch() -> None: assert f(B()) == 'b' assert f(A()) == 'a' assert f(5) == 'default' [case testMultipleRelatedClassesBeingRegistered] from functools import singledispatch +from typing import Any class A: pass class B(A): pass class C(B): pass @singledispatch -def f(arg) -> str: return 'default' +def f(arg: Any) -> str: return 'default' @f.register def _(arg: A) -> str: return 'a' @@ -509,7 +530,7 @@ def _(arg: C) -> str: return 'c' @f.register def _(arg: B) -> str: return 'b' -def test_singledispatch(): +def test_singledispatch() -> None: assert f(A()) == 'a' assert f(B()) == 'b' assert f(C()) == 'c' @@ -525,7 +546,7 @@ def a(arg: A) -> int: def _(arg: C) -> int: return 3 -def test_singledispatch(): +def test_singledispatch() -> None: assert f(B()) == 1 assert f(A()) == 2 assert f(C()) == 3 @@ -539,7 +560,7 @@ class B(A): pass class C(B): pass @singledispatch -def f(arg) -> int: +def f(arg: object) -> int: return 0 @f.register @@ -549,6 +570,7 @@ def g(arg: B) -> int: [case testOrderCanOnlyBeDeterminedFromMRONotIsinstanceChecks] from mypy_extensions import trait from functools import singledispatch +from typing import Any @trait class A: pass @@ -558,9 +580,8 @@ class AB(A, B): pass class BA(B, A): pass @singledispatch -def f(arg) -> str: +def f(arg: Any) -> str: return "default" - pass @f.register def fa(arg: A) -> str: @@ -570,18 +591,19 @@ def fa(arg: A) -> str: def fb(arg: B) -> str: return "b" -def test_singledispatch(): +def test_singledispatch() -> None: assert f(AB()) == "a" assert f(BA()) == "b" [case testCallingFunctionBeforeAllImplementationsRegistered] from functools import singledispatch +from typing import Any class A: pass class B(A): pass @singledispatch -def f(arg) -> str: +def f(arg: Any) -> str: return 'default' assert f(A()) == 'default' @@ -609,6 +631,7 @@ def test_final() -> None: [case testDynamicallyRegisteringFunctionFromInterpretedCode] from functools import singledispatch +from typing import Any class A: pass class B(A): pass @@ -616,7 +639,7 @@ class C(B): pass class D(C): pass @singledispatch -def f(arg) -> str: +def f(arg: Any) -> str: return "default" @f.register @@ -647,9 +670,10 @@ assert c(A()) == 'c' [case testMalformedDynamicRegisterCall] from functools import singledispatch +from typing import Any @singledispatch -def f(arg) -> None: +def f(arg: Any) -> None: pass [file register.py] from native import f @@ -667,7 +691,7 @@ import register from functools import singledispatch @singledispatch -def f(arg) -> str: +def f(arg: object) -> str: return 'default' [file register.py] From 5921022a8138100f69defb8838b44b2f96c1da25 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 5 Sep 2025 10:53:53 +0100 Subject: [PATCH 4/4] These were supposed to unannotated, so revert changes Also test using Any types as well, just in case. --- mypyc/test-data/run-dunders.test | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/mypyc/test-data/run-dunders.test b/mypyc/test-data/run-dunders.test index 634ac1a9a563..a3ec06763d75 100644 --- a/mypyc/test-data/run-dunders.test +++ b/mypyc/test-data/run-dunders.test @@ -545,6 +545,7 @@ def test_type_mismatch_fall_back_to_reverse() -> None: assert F()**G() == -6 [case testDundersBinaryNotImplemented] +# mypy: allow-untyped-defs from typing import Any, Union from testutil import assertRaises @@ -595,16 +596,16 @@ def test_any_radd() -> None: assert d3 + e3 == 4 class F: - def __init__(self, v: Any): + def __init__(self, v): self.v = v - def __add__(self, x: Any) -> Any: + def __add__(self, x): if isinstance(x, int): return self.v + x return NotImplemented class G: - def __radd__(self, x: Any) -> Any: + def __radd__(self, x): if isinstance(x, F): return x.v + 1 if isinstance(x, str): @@ -617,22 +618,35 @@ def test_unannotated_add() -> None: with assertRaises(TypeError, "unsupported operand type(s) for +: 'F' and 'str'"): o + 'x' + o2: Any = F(4) + assert o2 + 5 == 9 + with assertRaises(TypeError, "unsupported operand type(s) for +: 'F' and 'str'"): + o2 + 'x' + def test_unannotated_add_and_radd_1() -> None: o = F(4) assert o + G() == 5 + o2: Any = F(4) + assert o2 + G() == 5 + def test_unannotated_radd() -> None: assert 'x' + G() == 'a' with assertRaises(TypeError, "unsupported operand type(s) for +: 'int' and 'G'"): 1 + G() + o: Any = G() + assert 'x' + o == 'a' + with assertRaises(TypeError, "unsupported operand type(s) for +: 'int' and 'G'"): + 1 + o + class H: - def __add__(self, x: Any) -> Any: + def __add__(self, x): if isinstance(x, int): return x + 1 return NotImplemented - def __radd__(self, x: Any) -> Any: + def __radd__(self, x): if isinstance(x, str): return 22 return NotImplemented @@ -644,6 +658,12 @@ def test_unannotated_add_and_radd_2() -> None: with assertRaises(TypeError, "unsupported operand type(s) for +: 'int' and 'H'"): 1 + h + h2: Any = H() + assert h + 5 == 6 + assert 'x' + h == 22 + with assertRaises(TypeError, "unsupported operand type(s) for +: 'int' and 'H'"): + 1 + h + # TODO: Inheritance [case testDifferentReverseDunders]