PY-25989 PY-84544 Widen types during type parameters substitution

(cherry picked from commit 627673fc7ed27621df839a5c1d4d31e677ce7f8c)

GitOrigin-RevId: 07803c6243370d55df0d870e2e32b38170c1fb49
This commit is contained in:
Petr
2025-11-26 18:52:04 +00:00
committed by intellij-monorepo-bot
parent a1e73e339b
commit 241ba26253
4 changed files with 81 additions and 21 deletions
@@ -3359,4 +3359,33 @@ public class Py3TypeCheckerInspectionTest extends PyInspectionTestCase {
var: Template = Concrete()
""");
}
// PY-25989 PY-84544
public void testTypeVarWidening() {
myFixture.enableInspections(PyAssertTypeInspection.class);
doTestByText("""
from collections.abc import Iterable
from typing import assert_type
# PY-84544
def foo(iterable: Iterable[int] | Iterable[str]) -> None:
assert_type(next(iter(iterable)), int | str)
# PY-25989
assert_type(max(1, 2.6), float)
assert_type(max(2.6, 1), float)
max(1, <warning descr="Expected type 'int' (matched generic type 'SupportsRichComparisonT ≤: SupportsDunderLT[Any] | SupportsDunderGT[Any]'), got 'object' instead">object()</warning>)
def bar[T: int, str](v1: T, v2: T) -> T:
if (bool(input())):
return v1
return v2
_ = bar(1, <warning descr="Expected type 'int' (matched generic type 'T ≤: int'), got 'str' instead">"a"</warning>)
""");
}
}
@@ -1347,7 +1347,10 @@ public class PyTypeCheckerInspectionTest extends PyInspectionTestCase {
def accepts_anything(x: str) -> None:
pass
func(42, <warning descr="Expected type '(int) -> None' (matched generic type '(T) -> None'), got '(x: str) -> None' instead">accepts_anything</warning>)""")
# Bug: Expected error.
# `Callable[[str], None]` is assignable to `Callable[[int | str], None]`.
# Thus, substitution `T` -> `int | str` is considered valid.
func(42, accepts_anything)""")
);
}