public Conversion findCompatibleConversion(DataType fromType, DataType toType) {
    if (fromType.isCompatibleWith(toType)) {
      return new Conversion(fromType, toType);
    }

    return null;
  }
  public Conversion findConversion(DataType fromType, DataType toType, boolean isImplicit) {
    Conversion result = findCompatibleConversion(fromType, toType);
    if (result == null) {
      int score = Integer.MAX_VALUE;
      for (Conversion conversion : getConversions(fromType)) {
        if ((!isImplicit || conversion.isImplicit())
            && (conversion.getToType().isSuperTypeOf(toType)
                || conversion.getToType().isGeneric())) {
          // Lower score is better. If the conversion matches the target type exactly, the score is
          // 0.
          // If the conversion is generic, the score is 1 (because that will be instantiated to an
          // exact match)
          // If the conversion is a super type, it should only be used if an exact match cannot be
          // found.
          // If the score is equal to an existing, it indicates a duplicate conversion
          int newScore =
              conversion.getToType().equals(toType)
                  ? 0
                  : (conversion.getToType().isGeneric() ? 1 : 2);
          if (newScore < score) {
            result = conversion;
            score = newScore;
          } else if (newScore == score) {
            throw new IllegalArgumentException(
                String.format(
                    "Ambiguous implicit conversion from %s to %s or %s.",
                    fromType.toString(),
                    result.getToType().toString(),
                    conversion.getToType().toString()));
          }
        }
      }
    }

    if (result == null) {
      // If both types are lists, attempt to find a conversion between the element types
      if (fromType instanceof ListType && toType instanceof ListType) {
        result = findListConversion((ListType) fromType, (ListType) toType);
      }

      // If both types are intervals, attempt to find a conversion between the point types
      if (fromType instanceof IntervalType && toType instanceof IntervalType) {
        result = findIntervalConversion((IntervalType) fromType, (IntervalType) toType);
      }
    }

    return result;
  }