public static Optional<SoyType> computeLowestCommonTypeArithmetic(SoyType t0, SoyType t1) {
    // If either of the types is an error type, return the error type
    if (t0.getKind() == Kind.ERROR || t1.getKind() == Kind.ERROR) {
      return Optional.of(ErrorType.getInstance());
    }
    // If either of the types isn't numeric or unknown, then this isn't valid for an arithmetic
    // operation.
    if (!isNumericOrUnknown(t0) || !isNumericOrUnknown(t1)) {
      return Optional.absent();
    }

    // Note: everything is assignable to unknown and itself.  So the first two conditions take care
    // of all cases but a mix of float and int.
    if (t0.isAssignableFrom(t1)) {
      return Optional.of(t0);
    } else if (t1.isAssignableFrom(t0)) {
      return Optional.of(t1);
    } else {
      // If we get here then we know that we have a mix of float and int.  In this case arithmetic
      // ops always 'upgrade' to float.  So just return that.
      return Optional.of(FloatType.getInstance());
    }
  }
public static Optional < SoyType > computeLowestCommonTypeArithmetic ( SoyType t0 , SoyType t1 ) { if ( t0 . getKind ( ) == Kind . ERROR || t1 . getKind ( ) == Kind . ERROR ) { return Optional . of ( ErrorType . getInstance ( ) ) ; } if ( ! isNumericOrUnknown ( t0 ) || ! isNumericOrUnknown ( t1 ) ) { return Optional . absent ( ) ; } if ( t0 . isAssignableFrom ( t1 ) ) { return Optional . of ( t0 ) ; } else if ( t1 . isAssignableFrom ( t0 ) ) { return Optional . of ( t1 ) ; } else { return Optional . of ( FloatType . getInstance ( ) ) ; } }
Compute the most specific type that is assignable from both t0 and t1, taking into account
arithmetic promotions - that is, converting int to float if needed.

@param t0 A type.
@param t1 Another type.
@return A type that is assignable from both t0 and t1 or absent if the types are not arithmetic
meaning a subtype of 'number' or unknown.