boolean (@NotNull PyClassType expected, @NotNull PyClassType actual, @NotNull MatchContext matchContext) { GenericSubstitutions substitutions = collectTypeSubstitutions(actual, matchContext.context); MatchContext protocolContext = new MatchContext(matchContext.context, new GenericSubstitutions(), matchContext.reversedSubstitutions); for (kotlin.Pair<PyTypedElement, List<RatedResolveResult>> pair : PyProtocolsKt.inspectProtocolSubclass(expected, actual, matchContext.context)) { final List<RatedResolveResult> subclassElements = pair.getSecond(); if (ContainerUtil.isEmpty(subclassElements)) { return false; } final PyType protocolElementType = dropSelfIfNeeded(expected, matchContext.context.getType(pair.getFirst()), matchContext.context); final boolean elementResult = StreamEx .of(subclassElements) .map(ResolveResult::getElement) .select(PyTypedElement.class) .map(matchContext.context::getType) .map(type -> dropSelfIfNeeded(actual, type, matchContext.context)) .map(type -> substitute(type, substitutions, matchContext.context)) .anyMatch( subclassElementType -> { boolean matched = match(protocolElementType, subclassElementType, protocolContext).orElse(true); if (!matched) return false; if (!(protocolElementType instanceof PyFunctionType) || !(subclassElementType instanceof PyFunctionType)) return matched; var protocolReturnType = ((PyFunctionType)protocolElementType).getReturnType(protocolContext.context); if (protocolReturnType instanceof PySelfType) { var subclassReturnType = ((PyFunctionType)subclassElementType).getReturnType(protocolContext.context); if (subclassReturnType instanceof PySelfType) return true; return match(actual, subclassReturnType, matchContext).orElse(true); } return matched; } ); if (!elementResult) { return false; } } if (expected instanceof PyCollectionType) { PyCollectionType genericSuperClass = findGenericDefinitionType(expected.getPyClass(), matchContext.context); if (genericSuperClass != null) { PyCollectionType concreteSuperClass = (PyCollectionType)substitute(genericSuperClass, protocolContext.mySubstitutions, protocolContext.context); assert concreteSuperClass != null; return matchGenericClassesParameterWise((PyCollectionType)expected, concreteSuperClass, matchContext); } } return true; }