@Override
    public void visitPolyadicExpression(@NotNull PsiPolyadicExpression expr) {
      PsiExpression[] operands = expr.getOperands();
      final int index = Arrays.asList(operands).indexOf(myExpr);
      if (index < 0) return; // broken syntax

      IElementType op = expr.getOperationTokenType();
      PsiExpression anotherExpr = index > 0 ? operands[0] : 1 < operands.length ? operands[1] : null;

      if (myForCompletion && index == 0) {
        if (op == JavaTokenType.EQEQ || op == JavaTokenType.NE) {
          ContainerUtil.addIfNotNull(myResult, getEqualsType(anotherExpr));
        }
        if (op == JavaTokenType.LT || op == JavaTokenType.LE ||
            op == JavaTokenType.GT || op == JavaTokenType.GE) {
          PsiType anotherType = anotherExpr != null ? anotherExpr.getType() : null;
          if (anotherType != null) {
            myResult.add(createInfoImpl(PsiTypes.doubleType(), anotherType));
          }
        }
        final MyParentVisitor visitor = new MyParentVisitor(expr, true, myClassProvider, myVoidable, myUsedAfter, myMaxCandidates);
        myExpr = (PsiExpression)myExpr.getParent();
        expr.getParent().accept(visitor);
        myResult.addAll(visitor.myResult);
        if (!(expr.getParent() instanceof PsiExpressionList)) {
          myResult.replaceAll(
            info -> createInfoImpl(info.getType(), info.getKind(), info.getDefaultType(), TailTypes.noneType(), info.getCalledMethod(),
                                   ((ExpectedTypeInfoImpl)info)::getExpectedName
            ));
        }
        return;
      }

      PsiType anotherType = anotherExpr != null ? anotherExpr.getType() : null;

      if (op == JavaTokenType.MINUS ||
          op == JavaTokenType.ASTERISK ||
          op == JavaTokenType.DIV ||
          op == JavaTokenType.PERC ||
          op == JavaTokenType.LT ||
          op == JavaTokenType.GT ||
          op == JavaTokenType.LE ||
          op == JavaTokenType.GE) {
        if (anotherType != null) {
          myResult.add(createInfoImpl(PsiTypes.doubleType(), anotherType));
        }
      }
      else if (op == JavaTokenType.PLUS) {
        if (anotherType == null || anotherType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
          PsiClassType objectType = PsiType.getJavaLangObject(expr.getManager(), expr.getResolveScope());
          myResult.add(createInfoImpl(objectType, anotherType != null ? anotherType : objectType));
        }
        else if (PsiTypes.doubleType().isAssignableFrom(anotherType)) {
          myResult.add(createInfoImpl(PsiTypes.doubleType(), anotherType));
        }
      }
      else if (op == JavaTokenType.EQEQ || op == JavaTokenType.NE) {
        ContainerUtil.addIfNotNull(myResult, getEqualsType(anotherExpr));
      }
      else if (op == JavaTokenType.LTLT || op == JavaTokenType.GTGT || op == JavaTokenType.GTGTGT) {
        if (anotherType != null) {
          myResult.add(createInfoImpl(PsiTypes.longType(), ExpectedTypeInfo.TYPE_BETWEEN, PsiTypes.shortType(), TailTypes.noneType()));
        }
      }
      else if (op == JavaTokenType.OROR || op == JavaTokenType.ANDAND) {
        myResult.add(createInfoImpl(PsiTypes.booleanType(), ExpectedTypeInfo.TYPE_STRICTLY, PsiTypes.booleanType(), TailTypes.noneType()));
      }
      else if (op == JavaTokenType.OR || op == JavaTokenType.XOR || op == JavaTokenType.AND) {
        if (anotherType != null) {
          ExpectedTypeInfoImpl info;
          if (PsiTypes.booleanType().equals(anotherType)) {
            info = createInfoImpl(anotherType, ExpectedTypeInfo.TYPE_STRICTLY, anotherType, TailTypes.noneType());
          }
          else {
            info = createInfoImpl(PsiTypes.longType(), anotherType);
          }
          myResult.add(info);
        }
      }
    }
@Override
    public void visitPolyadicExpression(@NotNull PsiPolyadicExpression expr)