PY-64359 Upcast PyCollectionTypeImpl to Iterable to get its proper iterated item type

(cherry picked from commit 2366c4b215a3631d270cd69850291da38e70b2ec)

GitOrigin-RevId: 8175cdbea5ff6f05c5b1beaa0fa5fe21e03ec5cf
This commit is contained in:
evgeny.bovykin
2026-02-20 12:15:44 +00:00
committed by intellij-monorepo-bot
parent 68037d2f98
commit 587cdcf35a
4 changed files with 25 additions and 8 deletions
@@ -108,7 +108,16 @@ public class PyCollectionTypeImpl extends PyClassTypeImpl implements PyCollectio
@Override
public @Nullable PyType getIteratedItemType() {
// TODO: Select the parameter type that matches T in Iterable[T]
if (myElementTypes.size() >= 2) {
String iterableName = "typing.Iterable";
if (!iterableName.equals(getClassQName())) {
TypeEvalContext context = TypeEvalContext.codeInsightFallback(getPyClass().getProject());
PyType asIterable = PyTypeUtil.convertToType(this, iterableName, getPyClass(), context);
if (asIterable instanceof PyCollectionType collectionType) {
return collectionType.getIteratedItemType();
}
}
}
return ContainerUtil.getFirstItem(myElementTypes);
}
@@ -477,7 +477,7 @@ public class Py3TypeTest extends PyTestCase {
}
public void testYieldFromUnknownTuple() {
doTest("Any",
doTest("_T_co",
"""
def get_tuple() -> tuple:
pass
@@ -487,7 +487,7 @@ public class Py3TypeTest extends PyTestCase {
}
public void testYieldFromUnknownList() {
doTest("Any",
doTest("_T_co",
"""
def get_list() -> list:
pass
@@ -497,7 +497,7 @@ public class Py3TypeTest extends PyTestCase {
}
public void testYieldFromUnknownDict() {
doTest("Any",
doTest("_T_co",
"""
def get_dict() -> dict:
pass
@@ -507,7 +507,7 @@ public class Py3TypeTest extends PyTestCase {
}
public void testYieldFromUnknownSet() {
doTest("Any",
doTest("_T_co",
"""
def get_set() -> set:
pass
@@ -1693,7 +1693,7 @@ public class PyTypeTest extends PyTestCase {
// PY-20794
public void testIterateOverPureList() {
doTest("Any",
doTest("_T_co",
"""
l = None # type: list
for expr in l:
@@ -1703,7 +1703,7 @@ public class PyTypeTest extends PyTestCase {
// PY-20794
public void testIterateOverDictValueWithDefaultValue() {
doTest("Any",
doTest("Union[_T_co, Any]",
"""
d = None # type: dict
for expr in d.get('field', []):
@@ -2300,7 +2300,7 @@ public class PyTypeTest extends PyTestCase {
// PY-24364
public void testReassignedParameter() {
doTest("(entries: Any) -> Generator[Any, Any, None]",
doTest("(entries: Any) -> Generator[_T_co, Any, None]",
"""
def resort(entries):
entries = list(entries)
@@ -4255,5 +4255,13 @@ public class Py3TypeCheckerInspectionTest extends PyInspectionTestCase {
serial_number = property(_get_serial_number)
""");
}
// PY-64359
public void testTupleDictValues() {
doTestByText("""
def f(a: dict[str, int]):
b: tuple[int, ...] = tuple(a.values())
""");
}
}