Example #1
0
// Perform the usual arithmetic conversions on `e1` and `e2`. This
// tries to find a common type for `e1` and `e2` and convert both
// expressions to that type.
//
// NOTE: In C++ lvalue-to-rvalue conversions are required on a
// per-expression basis, independently of converting to a common
// type. Also, non-user-defined types are unqualified prior to
// analysis. It would be easier if we found an absolute common
// type and then instantiated a declaration suitable for overload
// resolution. Maybe.
//
// TODO: Handle conversions for character types (or promote to a
// corresponding integer type?).
//
// TODO: How does bool work with this set of conversions? Promote
// bool to int?
//
// TODO: Can we unify this with the common type required by the
// conditional expression? Note that the arithmetic version converts
// to values, and the conditional expression can retain references.
Expr_pair
arithmetic_conversions(Context& cxt, Expr& e1, Expr& e2)
{
  // If the types are the same, no conversions are applied.
  if (is_equivalent(e1.type(), e2.type()))
    return {e1, e2};

  // If either operand has floating point type, convert to the type
  // with the greatest precision.
  //
  // TODO: Why isn't convert_to_common_float symmetric? This seems like
  // an issue.
  if (has_floating_point_type(e1))
    return convert_to_common_float(cxt, e2, e1);
  if (has_floating_point_type(e2))
    return convert_to_common_float(cxt, e1, e2);

  // If both operands have integer type, the following rules apply.
  if (has_integer_type(e1) && has_integer_type(e2))
    return convert_to_common_int(cxt, e1, e2);

  // TODO: No conversion from e1 to e2.
  error(cxt, "no usual arithmetic conversion of '{}' and '{}'", e1, e2);
  throw Type_error();
}
Example #2
0
// Assuming the type of e1 is untested and e2 has floating point
// type, convert to the most precise floating point type.
Expr_pair
convert_to_common_float(Context& cxt, Expr& e1, Expr& e2)
{
  Float_type& f2 = cast<Float_type>(e2.type());

  // If e1 has float type, convert to the most precise type.
  if (has_floating_point_type(e1)) {
    Float_type& f1 = cast<Float_type>(e1.type());
    if (f1.precision() < f2.precision()) {
      Expr& c = convert_to_wider_float(cxt, e1, f2);
      return {c, e2};
    }
    if (f2.precision() < f1.precision()) {
      Expr& c = convert_to_wider_float(cxt, e2, f1);
      return {e1, c};
    }
    lingo_unreachable();
  }

  // If e1 has integer type, convert to e2.
  if (has_integer_type(e1)) {
    Expr& c = convert_integer_to_float(cxt, e1, f2);
    return {c, e2};
  }

  error(cxt, "no floating point conversions for '{}' and '{}'", e1, e2);
  throw Type_error();
}
Example #3
0
// Perform the usual arithmetic conversions on `e1` and `e2`. This
// tries to find a common type for `e1` and `e2` and convert both
// expressions to that type.
//
// NOTE: In C++ lvalue-to-rvalue conversions are required on a
// per-expression basis, independently of converting to a common
// type. Also, non-user-defined types are unqualified prior to
// analysis. It would be easier if we found an absolute common
// type and then instantiated a declaration suitable for overload
// resolution. Maybe.
//
// TODO: Handle conversions for character types (or promote to a
// corresponding integer type?).
//
// TODO: How does bool work with this set of conversions? Promote
// bool to int?
//
// TODO: Can we unify this with the common type required by the
// conditional expression? Note that the arithmetic version converts
// to values, and the conditional expression can retain references.
Expr_pair
arithmetic_conversion(Expr& e1, Expr& e2)
{
  // If the types are the same, no conversions are applied.
  if (is_equivalent(e1.type(), e2.type()))
    return {e1, e2};

  // If either operand has floating point type, convert to the type
  // with the greatest precision.
  if (has_floating_point_type(e1))
    return convert_to_common_float(e2, e1);
  if (has_floating_point_type(e2))
    return convert_to_common_float(e1, e2);

  // If both oerands have integer type, the following rules apply.
  if (has_integer_type(e1) && has_integer_type(e2))
    return convert_to_common_int(e1, e2);

  // TODO: No conversion from e1 to e2.
  throw std::runtime_error("incompatible types");
}
Example #4
0
// Assuming the type of e1 is untested and e2 has floating point
// type, convert to the most precise floating point type.
Expr_pair
convert_to_common_float(Expr& e1, Expr& e2)
{
  Float_type& f2 = cast<Float_type>(e2.type());

  // If e1 has float type, convert to the most precise.
  if (has_floating_point_type(e1)) {
    Float_type& f1 = cast<Float_type>(e1.type());
    if (f1.precision() < f2.precision())
      return {convert_to_wider_float(e1, f2), e2};
    if (f2.precision() < f1.precision())
      return {e1, convert_to_wider_float(e2, f1)};
  }

  // If e1 has integer type, convert to e2.
  if (has_integer_type(e1)) {
    return {convert_integer_to_float(e1, f2), e2};
  }

  throw std::runtime_error("incompatible types");
}
Example #5
0
// A value of integer type can be converted to a value of a
// wider integer type.
//
// A value of type bool can be converted to integer s.t.
// false is 0 and true is 1.
//
// FIXME: An int-to-int conversion requires some form of sign
// extension. That depends on the destination type. Perhaps use
// different conversions for these values?
//
// Also use a different conversion for bool-to-int?
Expr&
convert_to_wider_integer(Expr& e, Integer_type& t)
{
  // A value of integer type can be converted...
  if (has_integer_type(e)) {
    Integer_type& et = cast<Integer_type>(e.type());
    // TODO: Be more precise about the conversion that's
    // actually going to happen. Especially, if we convert
    // sign and widen simultaneously.
    if (et.precision() < t.precision())
      return *new Integer_conv(t, e);
    else if (et.sign() != t.sign())
      return *new Integer_conv(t, e);
    else
      return e;
  }

  // A value of type bool can be converted...
  if (is<Boolean_type>(&e.type()))
    return *new Integer_conv(t, e);

  return e;
}