@Nullable
  private static CauseItem findTypeCause(MemoryStateChange operandHistory, PsiType type, boolean isInstance) {
    PsiExpression operand = Objects.requireNonNull(operandHistory.getExpression());
    TypeConstraint wanted = TypeConstraints.instanceOf(type);
    PsiType operandType = operand.getType();
    if (operandType != null) {
      TypeConstraint constraint = TypeConstraints.instanceOf(operandType);
      String name = JavaAnalysisBundle.message("dfa.find.cause.object.kind.expression");
      if (operand instanceof PsiMethodCallExpression) {
        name = JavaAnalysisBundle.message("dfa.find.cause.object.kind.method.return");
      }
      else if (operand instanceof PsiReferenceExpression) {
        PsiElement target = ((PsiReferenceExpression)operand).resolve();
        if (target != null) {
          name = JavaElementKind.fromElement(target).subject();
        }
      }
      String explanation = constraint.getAssignabilityExplanation(wanted, isInstance, name);
      if (explanation != null) {
        if (constraint.equals(wanted)) {
          explanation = JavaAnalysisBundle.message("dfa.find.cause.type.known", name, constraint.toShortString());
        }
        return new CauseItem(explanation, operand);
      }
    }
    DfaValue operandValue = operandHistory.myTopOfStack;

    FactDefinition<TypeConstraint> fact = operandHistory.findFact(operandValue, FactExtractor.constraint());
    String explanation = fact.myFact.getAssignabilityExplanation(wanted, isInstance,
                                                                 JavaAnalysisBundle.message("dfa.find.cause.object.kind.generic"));
    while (explanation != null) {
      MemoryStateChange causeLocation = fact.myChange;
      if (causeLocation == null) break;
      MemoryStateChange prevHistory = causeLocation.getPrevious();
      if (prevHistory == null) break;
      fact = prevHistory.findFact(operandValue, FactExtractor.constraint());
      TypeConstraint prevConstraint = fact.myFact;
      String prevExplanation = prevConstraint.getAssignabilityExplanation(wanted, isInstance,
                                                                          JavaAnalysisBundle.message("dfa.find.cause.object.kind.generic"));
      if (prevExplanation == null) {
        if (causeLocation.myInstruction instanceof AssignInstruction && causeLocation.myTopOfStack == operandValue) {
          PsiExpression rExpression = ((AssignInstruction)causeLocation.myInstruction).getRExpression();
          if (rExpression != null) {
            MemoryStateChange rValuePush = causeLocation.findSubExpressionPush(rExpression);
            if (rValuePush != null) {
              CauseItem assignmentItem = createAssignmentCause((AssignInstruction)causeLocation.myInstruction, operandValue);
              assignmentItem.addChildren(findTypeCause(rValuePush, type, isInstance));
              return assignmentItem;
            }
          }
        }
        CauseItem causeItem = new CauseItem(explanation, operand);
        causeItem.addChildren(
          new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.type.is.known.from.place", operand.getText()), causeLocation));
        return causeItem;
      }
      explanation = prevExplanation;
    }
    return null;
  }
@Nullable
  private static CauseItem findTypeCause(MemoryStateChange operandHistory, PsiType type, boolean isInstance)