@NotNull
  private static @InspectionMessage String getSingleCalleeProblemMessage(@NotNull PyTypeCheckerInspection.AnalyzeArgumentResult argumentResult,
                                                                         @NotNull TypeEvalContext context) {
    final PyType actualType = argumentResult.getActualType();
    final PyType expectedType = argumentResult.getExpectedType();

    assert actualType != null; // see PyTypeCheckerInspection.Visitor.analyzeArgument()
    assert expectedType != null; // see PyTypeCheckerInspection.Visitor.analyzeArgument()

    final String actualTypeName = PythonDocumentationProvider.getTypeName(actualType, context);

    if (expectedType instanceof PyStructuralType) {
      final Set<String> expectedAttributes = ((PyStructuralType)expectedType).getAttributeNames();
      final Set<String> actualAttributes = getAttributes(actualType, context);

      if (actualAttributes != null) {
        final Sets.SetView<String> missingAttributes = Sets.difference(expectedAttributes, actualAttributes);
        String missingAttributeList = StringUtil.join(missingAttributes, s -> String.format("'%s'", s), ", ");
        return PyPsiBundle.message("INSP.type.checker.type.does.not.have.expected.attribute",
                                   actualTypeName, missingAttributes.size(), missingAttributeList);
      }
    }

    @Nullable PyType expectedTypeAfterSubstitution = argumentResult.getExpectedTypeAfterSubstitution();
    String expectedTypeName = PythonDocumentationProvider.getVerboseTypeName(expectedType, context);
    String expectedSubstitutedName = expectedTypeAfterSubstitution != null && !expectedTypeAfterSubstitution.equals(expectedType)
                                     ? PythonDocumentationProvider.getTypeName(expectedTypeAfterSubstitution, context)
                                     : null;

    if (PyProtocolsKt.matchingProtocolDefinitions(expectedType, actualType, context)) {
      if (expectedSubstitutedName != null) {
        return PyPsiBundle.message("INSP.type.checker.only.concrete.class.can.be.used.where.matched.protocol.expected",
                                   expectedSubstitutedName, expectedTypeName);
      }
      else {
        return PyPsiBundle.message("INSP.type.checker.only.concrete.class.can.be.used.where.protocol.expected", expectedTypeName);
      }
    }

    if (expectedSubstitutedName != null) {
      return PyPsiBundle.message("INSP.type.checker.expected.matched.type.got.type.instead", expectedSubstitutedName, expectedTypeName, actualTypeName);
    }
    else {
      return PyPsiBundle.message("INSP.type.checker.expected.type.got.type.instead", expectedTypeName, actualTypeName);
    }
  }
@NotNull
  private static @InspectionMessage String getSingleCalleeProblemMessage(@NotNull PyTypeCheckerInspection.AnalyzeArgumentResult argumentResult,
                                                                         @NotNull TypeEvalContext context)