diff --git a/python/python-psi-impl/resources/messages/PyPsiBundle.properties b/python/python-psi-impl/resources/messages/PyPsiBundle.properties
index d7fa68071183..124daeb941f2 100644
--- a/python/python-psi-impl/resources/messages/PyPsiBundle.properties
+++ b/python/python-psi-impl/resources/messages/PyPsiBundle.properties
@@ -1239,6 +1239,8 @@ INSP.type.hints.typeIs.has.zero.parameters=User-defined TypeGuard or TypeIs func
INSP.type.hints.typeIs.does.not.match=Return type of TypeIs ''{0}'' is not consistent with the type of the first parameter ''{1}''
INSP.type.hints.self.use.in.staticmethod=Cannot use 'Self' in staticmethod
INSP.type.hints.self.use.outside.class=Cannot use 'Self' outside class
+INSP.type.hints.self.cannot.use.self.in.this.context=Cannot use 'Self' in this context
+INSP.type.hints.self.cannot.use.self.in.metaclass=Type 'Self' cannot be used in a metaclass
INSP.type.hints.self.use.for.self.parameter.with.self.annotation=Cannot use 'Self' if 'self' parameter is not 'Self' annotated
INSP.type.hints.self.use.for.cls.parameter.with.self.annotation=Cannot use 'Self' if 'cls' parameter is not 'Self' annotated
INSP.type.hints.type.var.tuple.must.always.be.unpacked=TypeVarTuple must always be unpacked
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 3ce8d73abb7d..f134cef17af4 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
@@ -201,6 +201,7 @@ class PyTypeHintsInspection : PyInspection() {
if (type is PyTypeParameterType && type.scopeOwner == null && !isInsideTypeParameterDefault(node)) {
registerProblem(node, PyPsiBundle.message("INSP.type.hints.unbound.type.variable"))
}
+ checkSelfType(node)
}
if (!insideTypeHint) {
@@ -231,6 +232,27 @@ class PyTypeHintsInspection : PyInspection() {
}
}
+ private fun checkSelfType(node: PyReferenceExpression) {
+ if (resolvesToAnyOfQualifiedNames(node, PyTypingTypeProvider.SELF, PyTypingTypeProvider.SELF_EXT)) {
+ val selfType = Ref.deref(PyTypingTypeProvider.getType(node, myTypeEvalContext)) as? PySelfType
+ if (selfType == null) { // we don't infer Self type outside a class
+ registerProblem(node, PyPsiBundle.message("INSP.type.hints.self.use.outside.class"))
+ return
+ }
+ else {
+ val argList = PsiTreeUtil.getParentOfType(node, PyArgumentList::class.java)
+ if (argList != null && argList.parent is PyClass) {
+ registerProblem(node, PyPsiBundle.message("INSP.type.hints.self.cannot.use.self.in.this.context"))
+ return
+ }
+ if (selfType.scopeClassType.getAncestorTypes(myTypeEvalContext)
+ .contains(PyBuiltinCache.getInstance(node).typeType?.toClass())) {
+ registerProblem(node, PyPsiBundle.message("INSP.type.hints.self.cannot.use.self.in.metaclass"))
+ }
+ }
+ }
+ }
+
private fun isGenericTypeArgument(node: PyReferenceExpression): Boolean {
var element: PyElement = node
var parentElement = element.parent
@@ -326,11 +348,6 @@ class PyTypeHintsInspection : PyInspection() {
}
}
- val classParent = PsiTreeUtil.getParentOfType(node, PyClass::class.java)
- if (classParent == null) {
- registerProblemForSelves(PyPsiBundle.message("INSP.type.hints.self.use.outside.class"))
- }
-
val functionParent = PsiTreeUtil.getParentOfType(node, PyFunction::class.java)
if (functionParent != null) {
if (PyAstFunction.Modifier.STATICMETHOD == functionParent.modifier && PyNames.NEW != functionParent.name) {
diff --git a/python/testData/typing/ignored.txt b/python/testData/typing/ignored.txt
index e173df7d1ade..012b120d1e47 100644
--- a/python/testData/typing/ignored.txt
+++ b/python/testData/typing/ignored.txt
@@ -26,7 +26,6 @@ generics_base_class.py
generics_paramspec_components.py
generics_paramspec_semantics.py
generics_self_attributes.py
-generics_self_usage.py
generics_syntax_infer_variance.py
generics_typevartuple_basic.py
generics_typevartuple_overloads.py
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeHintsInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeHintsInspectionTest.java
index 5783b26ad9b4..4e61a12a7ff9 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyTypeHintsInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeHintsInspectionTest.java
@@ -3156,6 +3156,43 @@ public class PyTypeHintsInspectionTest extends PyInspectionTestCase {
doMultiFileTest();
}
+ // PY-76832
+ public void testTypeSelfAsTypeArg() {
+ doTestByText("""
+ from typing import TypeAlias, Self
+ TupleSelf: TypeAlias = tuple[Self] # E
+ class A[T]: ...
+ a = A[Self]() # E
+ class B:
+ def __init__(self):
+ self.l: List[Self] = [] # OK
+ """);
+ }
+
+ // PY-76832
+ public void testTypeSelfInBaseClassTypeArgs() {
+ doTestByText("""
+ from typing import Self
+
+ class Bar[T]: ...
+ class Baz(Bar[Self]): ... # E
+ """);
+ }
+
+ // PY-76832
+ public void testTypeSelfInMetaclass() {
+ doTestByText("""
+ from typing import Self, Any
+
+ class MyMetaclass(type):
+ def __new__(cls, *args: Any) -> Self: # E
+ ...
+
+ def __mul__(cls, count: int) -> list[Self]: # E
+ ...
+ """);
+ }
+
// PY-84289
public void testExponentialAnalysisTimeWhenMapLookupKeyEqualsVariableName() {