diff --git a/python/python-psi-impl/resources/messages/PyPsiBundle.properties b/python/python-psi-impl/resources/messages/PyPsiBundle.properties
index 4a716d5e3b2a..1af93b912fab 100644
--- a/python/python-psi-impl/resources/messages/PyPsiBundle.properties
+++ b/python/python-psi-impl/resources/messages/PyPsiBundle.properties
@@ -1162,7 +1162,7 @@ INSP.type.hints.typed.dict.is.not.allowed.as.a.bound.for.a.type.var=TypedDict is
INSP.type.hints.generics.should.be.specified.through.square.brackets=Generics should be specified through square brackets
INSP.type.hints.cannot.inherit.from.plain.generic=Cannot inherit from plain 'Generic'
INSP.type.hints.cannot.inherit.from.generic.multiple.times=Cannot inherit from 'Generic[...]' multiple times
-INSP.type.hints.some.type.variables.are.not.listed.in.generic=Some type variables ({0}) are not listed in ''Generic[{1}]''
+INSP.type.hints.generic.or.protocol.should.list.all.type.variables=''Generic[...]'' or ''Protocol[...]'' should list all type variables ({0})
INSP.type.hints.illegal.literal.parameter='Literal' may be parameterized with literal ints, byte and unicode strings, bools, Enum values, None, other literal types, or type aliases to other literal types
INSP.type.hints.parameters.to.generic.must.all.be.type.variables=Parameters to 'Generic[...]' must all be type variables
INSP.type.hints.parameters.to.generic.must.all.be.unique=Parameters to 'Generic[...]' must all be unique
diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyTypeHintsInspection.kt b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyTypeHintsInspection.kt
index 013a3f8a0f56..413d92c39687 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyTypeHintsInspection.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyTypeHintsInspection.kt
@@ -57,6 +57,8 @@ class PyTypeHintsInspection : PyInspection() {
private class Visitor(holder: ProblemsHolder, context: TypeEvalContext) : PyInspectionVisitor(holder, context) {
private val genericQName = QualifiedName.fromDottedString(PyTypingTypeProvider.GENERIC)
+ private val protocolQName = QualifiedName.fromDottedString(PyTypingTypeProvider.PROTOCOL)
+ private val protocolExtQName = QualifiedName.fromDottedString(PyTypingTypeProvider.PROTOCOL_EXT)
override fun visitPyCallExpression(node: PyCallExpression) {
super.visitPyCallExpression(node)
@@ -830,14 +832,9 @@ class PyTypeHintsInspection : PyInspection() {
.mapNotNull { it.name }
.joinToString(", ")
- val genericTypeVarsNames = genericTypeVars
- .asSequence()
- .mapNotNull { it.name }
- .joinToString(", ")
-
registerProblem(cls.superClassExpressionList,
- PyPsiBundle.message("INSP.type.hints.some.type.variables.are.not.listed.in.generic",
- nonGenericTypeVarsNames, genericTypeVarsNames),
+ PyPsiBundle.message("INSP.type.hints.generic.or.protocol.should.list.all.type.variables",
+ nonGenericTypeVarsNames),
ProblemHighlightType.GENERIC_ERROR)
}
}
@@ -859,7 +856,9 @@ class PyTypeHintsInspection : PyInspection() {
val operand = superSubscription.operand
val generic =
operand is PyReferenceExpression &&
- genericQName in PyResolveUtil.resolveImportedElementQNameLocally(operand)
+ PyResolveUtil.resolveImportedElementQNameLocally(operand).any {
+ it in listOf(genericQName, protocolQName, protocolExtQName)
+ }
val index = superSubscription.indexExpression
val parameters = (index as? PyTupleExpression)?.elements ?: arrayOf(index)
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeHintsInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeHintsInspectionTest.java
index 59794a911b05..de0ee9643eb2 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyTypeHintsInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeHintsInspectionTest.java
@@ -209,17 +209,20 @@ public class PyTypeHintsInspectionTest extends PyInspectionTestCase {
// PY-28227
public void testGenericCompleteness() {
doTestByText("""
- from typing import Generic, TypeVar, Iterable
+ from typing import Generic, TypeVar, Iterable, Protocol
T = TypeVar('T')
S = TypeVar('S')
- class C(Generic[T], Iterable[S]):
+ class C(Generic[T], Iterable[S]):
+ pass
+
+ class P(Iterable[S], Protocol[T]):
pass
B = Generic
D = T
- class A(B[D], Iterable[S]):
+ class A(B[D], Iterable[S]):
pass
class E(Generic[T], Iterable[T]):
@@ -229,7 +232,8 @@ public class PyTypeHintsInspectionTest extends PyInspectionTestCase {
pass
class G(Iterable[T]):
- pass""");
+ pass
+ """);
}
// PY-31147