@Override
  public ExpectedTypeInfo @NotNull [] intersect(@NotNull ExpectedTypeInfo info) {
    ExpectedTypeInfoImpl info1 = (ExpectedTypeInfoImpl)info;

    if (myKind == TYPE_STRICTLY) {
      if (info1.myKind == TYPE_STRICTLY) {
        if (info1.myType.equals(myType)) return new ExpectedTypeInfoImpl[] {this};
      }
      else {
        return info1.intersect(this);
      }
    }
    else if (myKind == TYPE_OR_SUBTYPE) {
      if (info1.myKind == TYPE_STRICTLY) {
        if (myType.isAssignableFrom(info1.myType)) return new ExpectedTypeInfoImpl[] {info1};
      }
      else if (info1.myKind == TYPE_OR_SUBTYPE) {
        PsiType otherType = info1.myType;
        if (myType.isAssignableFrom(otherType)) return new ExpectedTypeInfoImpl[] {info1};
        else if (otherType.isAssignableFrom(myType)) return new ExpectedTypeInfoImpl[] {this};
      }
      else {
        return info1.intersect(this);
      }
    }
    else if (myKind == TYPE_OR_SUPERTYPE) {
      if (info1.myKind == TYPE_STRICTLY) {
        if (info1.myType.isAssignableFrom(myType)) return new ExpectedTypeInfoImpl[] {info1};
      }
      else if (info1.myKind == TYPE_OR_SUBTYPE) {
        if (info1.myType.isAssignableFrom(myType)) return new ExpectedTypeInfoImpl[] {this};
      }
      else if (info1.myKind == TYPE_OR_SUPERTYPE) {
        PsiType otherType = info1.myType;
        if (myType.isAssignableFrom(otherType)) return new ExpectedTypeInfoImpl[] {this};
        else if (otherType.isAssignableFrom(myType)) return new ExpectedTypeInfoImpl[] {info1};
      }
      else {
        return info1.intersect(this);
      }
    }


    //todo: the following cases are not implemented: SUPERxSUB, SUBxSUPER

    return ExpectedTypeInfo.EMPTY_ARRAY;
  }
@Override
  public ExpectedTypeInfo @NotNull [] intersect(@NotNull ExpectedTypeInfo info)