// 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(); }
// 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(); }
// 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"); }
// 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"); }