void (@Nullable PyType type, @NotNull TypeEvalContext context, @NotNull Generics generics, @NotNull Set<? super PyType> visited) { if (type instanceof PyTypeParameterType typeParameter) { generics.allTypeParameters.add(typeParameter); } if (visited.contains(type)) { return; } visited.add(type); if (type instanceof PyGenericType) { generics.typeVars.add((PyGenericType)type); } if (type instanceof PyTypeVarTupleType typeVarTupleType) { generics.typeVarTuples.add(typeVarTupleType); } // TODO Filter out PyParamSpecTypes representing actual lists of parameters, not type parameters declared via ParamSpec if (type instanceof PyParamSpecType) { generics.paramSpecs.add((PyParamSpecType)type); } // TODO These are not type parameters at all if (type instanceof PyConcatenateType) { generics.concatenates.add((PyConcatenateType)type); } if (type instanceof PySelfType) { generics.self = (PySelfType)type; } else if (type instanceof PyUnionType union) { for (PyType t : union.getMembers()) { collectGenerics(t, context, generics, visited); } } else if (type instanceof PyTupleType tuple) { final int n = tuple.isHomogeneous() ? 1 : tuple.getElementCount(); for (int i = 0; i < n; i++) { collectGenerics(tuple.getElementType(i), context, generics, visited); } } else if (type instanceof PyCollectionType collection) { for (PyType elementType : collection.getElementTypes()) { collectGenerics(elementType, context, generics, visited); } } else if (type instanceof PyCallableType callable && !(type instanceof PyClassLikeType)) { final List<PyCallableParameter> parameters = callable.getParameters(context); if (parameters != null) { for (PyCallableParameter parameter : parameters) { if (parameter != null) { collectGenerics(parameter.getType(context), context, generics, visited); } } } collectGenerics(callable.getReturnType(context), context, generics, visited); } else if (type instanceof PyUnpackedTupleType unpackedTupleType) { for (PyType elementType : unpackedTupleType.getElementTypes()) { collectGenerics(elementType, context, generics, visited); } } }