diff --git a/python/python-psi-impl/resources/messages/PyPsiBundle.properties b/python/python-psi-impl/resources/messages/PyPsiBundle.properties
index 6e557ad5c9ff..1825ca92b96d 100644
--- a/python/python-psi-impl/resources/messages/PyPsiBundle.properties
+++ b/python/python-psi-impl/resources/messages/PyPsiBundle.properties
@@ -1373,6 +1373,7 @@ INSP.patterns.pattern.can.be.simplified=Pattern can be simplified
INSP.patterns.class.does.not.support.pattern.matching.with.positional.arguments=Class {0} does not support pattern matching with positional arguments
INSP.patterns.too.many.positional.patterns.expected=Too many positional patterns, expected {0}
INSP.patterns.attribute.already.specified.as.positional.pattern.at.position=Attribute ''{0}'' is already specified as positional pattern at position {1}
+INSP.patterns.not.a.class=Class pattern requires a class, but ''{0}'' can be ''{1}''
QFIX.simplify.as.pattern=Simplify 'as' pattern
QFIX.NAME.remove.element=Remove element
QFIX.remove.pattern=Remove pattern
diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPatternInspection.kt b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPatternInspection.kt
index b5cdabd85821..f947be839bc4 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPatternInspection.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyPatternInspection.kt
@@ -15,10 +15,7 @@ import com.jetbrains.python.psi.*
import com.jetbrains.python.psi.impl.PyBuiltinCache
import com.jetbrains.python.psi.impl.PyClassPatternImpl
import com.jetbrains.python.psi.impl.PyPsiUtils
-import com.jetbrains.python.psi.types.PyClassType
-import com.jetbrains.python.psi.types.PyTupleType
-import com.jetbrains.python.psi.types.PyTypeChecker
-import com.jetbrains.python.psi.types.TypeEvalContext
+import com.jetbrains.python.psi.types.*
class PyPatternInspection : PyInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
@@ -49,7 +46,20 @@ private class PyPatternInspectionVisitor(holder: ProblemsHolder, context: TypeEv
override fun visitPyClassPattern(node: PyClassPattern) {
- val classType = myTypeEvalContext.getType(node.classNameReference) as? PyClassType ?: return
+ val type = myTypeEvalContext.getType(node.classNameReference)
+ val types = PyTypeUtil.toStream(type).toList()
+ if (types.isNotEmpty() && types.none { PyTypeChecker.isUnknown(it, myTypeEvalContext) }) {
+ val invalidTypes = types.filter { it !is PyClassType || !it.isDefinition }
+ if (invalidTypes.isNotEmpty()) {
+ val invalidTypesUnion = PyUnionType.union(invalidTypes)
+ val invalidTypeName = PythonDocumentationProvider.getTypeName(invalidTypesUnion, myTypeEvalContext)
+ holder.problem(node.classNameReference,
+ PyPsiBundle.message("INSP.patterns.not.a.class", node.classNameReference.text, invalidTypeName)).register()
+ return
+ }
+ }
+
+ val classType = type as? PyClassType ?: return
val pyClass = classType.pyClass
if (pyClass.name in PyClassPattern.SPECIAL_BUILTINS) return
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyPatternInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyPatternInspectionTest.java
index 7f875e732b5c..6b81419d137f 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyPatternInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyPatternInspectionTest.java
@@ -323,6 +323,70 @@ def f(c):
""");
}
+ // PY-86019
+ public void testFunctionPattern() {
+ doTestByText("""
+ def f():
+ pass
+
+ match 1:
+ case f():
+ pass
+ """);
+ }
+
+ // PY-86019
+ public void testInstancePattern() {
+ doTestByText("""
+ x = 1
+ match 1:
+ case x():
+ pass
+ """);
+ }
+
+ // PY-86019
+ public void testUnionOfClassesPattern() {
+ doTestByText("""
+ class A: pass
+ class B: pass
+
+ def g(cond):
+ if cond:
+ c = A
+ else:
+ c = B
+ match 1:
+ case c():
+ pass
+ """);
+ }
+
+ // PY-86019
+ public void testUnionOfClassAndFunctionPattern() {
+ doTestByText("""
+ class A: pass
+ def f(): pass
+
+ def g(cond):
+ c = A if cond else f
+ match 1:
+ case c():
+ pass
+ """);
+ }
+
+ // PY-86019
+ public void testAnyPattern() {
+ doTestByText("""
+ from typing import Any
+ def g(c: Any):
+ match 1:
+ case c():
+ pass
+ """);
+ }
+
@NotNull
@Override
protected Class extends PyInspection> getInspectionClass() {