Optional<Boolean> (@NotNull PyClassType expected, @NotNull PyClassType actual, @NotNull MatchContext matchContext) { if (expected.equals(actual)) { return Optional.of(true); } final TypeEvalContext context = matchContext.context; if (expected.isDefinition() ^ actual.isDefinition() && !PyProtocolsKt.isProtocol(expected, context)) { if (!expected.isDefinition() && actual.isDefinition()) { final PyClassLikeType metaClass = actual.getMetaClassType(context, true); return Optional.of(metaClass != null && match((PyType)expected, metaClass.toInstance(), matchContext).orElse(true)); } return Optional.of(false); } if (expected instanceof PyTupleType && actual instanceof PyTupleType) { return match((PyTupleType)expected, (PyTupleType)actual, matchContext); } if (expected instanceof PyLiteralType) { return Optional.of(actual instanceof PyLiteralType && PyLiteralType.Companion.match((PyLiteralType)expected, (PyLiteralType)actual)); } if (actual instanceof PyTypedDictType) { final PyTypedDictType.TypeCheckingResult matchResult = PyTypedDictType.Companion.checkTypes(expected, (PyTypedDictType)actual, context, null); if (matchResult != null) return Optional.of(matchResult.getMatch()); } if (expected instanceof PyLiteralStringType) { return Optional.of(PyLiteralStringType.Companion.match((PyLiteralStringType)expected, actual)); } final PyClass superClass = expected.getPyClass(); final PyClass subClass = actual.getPyClass(); if (!subClass.isSubclass(superClass, context) && PyProtocolsKt.isProtocol(expected, context)) { return Optional.of(matchProtocols(expected, actual, matchContext)); } if (expected instanceof PyCollectionType) { return Optional.of(match((PyCollectionType)expected, actual, matchContext)); } if (matchClasses(superClass, subClass, context)) { if (expected instanceof PyTypingNewType && !expected.equals(actual) && superClass.equals(subClass)) { return Optional.of(actual.getAncestorTypes(context).contains(expected)); } return Optional.of(true); } return Optional.empty(); }