List<PyTypeParameterType> (@NotNull PyClass cls, @NotNull Context context) { if (!isGeneric(cls, context.getTypeContext())) { return Collections.emptyList(); } if (cls.getTypeParameterList() != null) { List<PyTypeParameter> typeParameters = cls.getTypeParameterList().getTypeParameters(); return StreamEx.of(typeParameters) .map(typeParameter -> getTypeParameterTypeFromTypeParameter(typeParameter, context)) .nonNull() .toList(); } // See https://mypy.readthedocs.io/en/stable/generics.html#defining-sub-classes-of-generic-classes List<PySubscriptionExpression> parameterizedSuperClassExpressions = ContainerUtil.filterIsInstance(PyClassElementType.getSuperClassExpressions(cls), PySubscriptionExpression.class); PySubscriptionExpression genericAsSuperClass = ContainerUtil.find(parameterizedSuperClassExpressions, s -> { return resolveToQualifiedNames(s.getOperand(), context.myContext).contains(GENERIC); }); return StreamEx.of(genericAsSuperClass != null ? Collections.singletonList(genericAsSuperClass) : parameterizedSuperClassExpressions) .peek(expr -> { PsiFile containingFile = expr.getContainingFile(); if (containingFile instanceof PyExpressionCodeFragment) { containingFile.putUserData(FRAGMENT_OWNER, cls); } }) .map(PySubscriptionExpression::getIndexExpression) .flatMap(e -> { final PyTupleExpression tupleExpr = as(e, PyTupleExpression.class); return tupleExpr != null ? StreamEx.of(tupleExpr.getElements()) : StreamEx.of(e); }) .nonNull() .map(e -> getType(e, context)) .map(Ref::deref) .flatMap(type -> { PyTypeChecker.Generics typeParams = PyTypeChecker.collectGenerics(type, context.myContext); return StreamEx.<PyType>of(typeParams.getTypeVars()).append(typeParams.getTypeVarTuples()).append(StreamEx.of(typeParams.getParamSpecs())); }) .select(PyTypeParameterType.class) .distinct() .toList(); }