Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error messages for bad maker calls #294

Merged
merged 2 commits into from
Sep 23, 2024

Conversation

chiphogg
Copy link
Contributor

This covers situations where somebody calls a QuantityMaker, or
QuantityPointMaker, on a value that isn't a valid rep. (One of the
most common use cases is when the value is already a core Au type, a
Quantity or QuantityMaker, and the call is redundant.

The first approach is a blanket approach: we start enforcing the "valid
rep" definition that we had previously added. This already makes the
error messages a lot nicer and shorter.

We then go further for the most common use case of redundant maker
calls. By adding templated overloads to each maker for Quantity and
QuantityPoint, we can directly tell users what they did wrong. In
order to implement these overloads, we needed an AlwaysFalse utliity,
which we added along with unit tests.

Helps #288. We will follow up to close this out by updating the
troubleshooting guide.

This covers situations where somebody calls a `QuantityMaker`, or
`QuantityPointMaker`, on a value that isn't a valid rep.  (One of the
most common use cases is when the value is _already_ a core Au type, a
`Quantity` or `QuantityMaker`, and the call is redundant.

The first approach is a blanket approach: we start enforcing the "valid
rep" definition that we had previously added.  This already makes the
error messages a lot nicer and shorter.

We then go further for the most common use case of redundant maker
calls.  By adding templated overloads to each maker for `Quantity` and
`QuantityPoint`, we can directly tell users what they did wrong.  In
order to implement these overloads, we needed an `AlwaysFalse` utliity,
which we added along with unit tests.

Helps #288.  We will follow up to close this out by updating the
troubleshooting guide.
@chiphogg chiphogg requested a review from geoffviola September 21, 2024 01:45
@chiphogg
Copy link
Contributor Author

Here are the example changes to tests, for posterity.

Input code

TEST(Quantity, OfQuantityMakesNiceErrorMessage) {
    radians(radians);
    radians(radians(3.14));
    meters(meters_pt(15));
    meters_pt(meters_pt(51));
    meters_pt(meters(51));
}

Old error messages

In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:287:68: error: invalid operands to binary expression ('au::QuantityMaker<au::Radians>' and 'au::QuantityMaker<au::Radians>')
    friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() + std::declval<RepT>())>
                                              ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:489:33: note: in instantiation of template class 'au::Quantity<au::Radians, au::QuantityMaker<au::Radians>>' requested here
    constexpr Quantity<Unit, T> operator()(T value) const {
                                ^
au/code/au/au_test.cc:94:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Radians>::operator()<au::QuantityMaker<au::Radians>>' requested here
    radians(radians);
           ^
au/code/au/zero.hh:55:23: note: candidate function not viable: no known conversion from 'au::QuantityMaker<au::Radians>' to 'au::Zero' for 1st argument
inline constexpr Zero operator+(Zero, Zero) { return ZERO; }
                      ^
au/code/au/quantity.hh:623:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator+(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
               ^
au/code/au/quantity.hh:633:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator+(Quantity<U, R> q1, QLike q2) -> decltype(q1 + as_quantity(q2)) {
               ^
au/code/au/quantity.hh:667:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator+(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) + q2) {
               ^
au/code/au/quantity_point.hh:395:16: note: candidate template ignored: could not match 'QuantityPoint' against 'QuantityMaker'
constexpr auto operator+(QuantityPoint<UnitP, RepP> p, Quantity<UnitQ, RepQ> q) {
               ^
au/code/au/quantity_point.hh:400:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator+(Quantity<UnitQ, RepQ> q, QuantityPoint<UnitP, RepP> p) {
               ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:291:68: error: invalid operands to binary expression ('au::QuantityMaker<au::Radians>' and 'au::QuantityMaker<au::Radians>')
    friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() - std::declval<RepT>())>
                                              ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
au/code/au/zero.hh:56:23: note: candidate function not viable: no known conversion from 'au::QuantityMaker<au::Radians>' to 'au::Zero' for 1st argument
inline constexpr Zero operator-(Zero, Zero) { return ZERO; }
                      ^
au/code/au/quantity.hh:627:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator-(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
               ^
au/code/au/quantity.hh:637:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator-(Quantity<U, R> q1, QLike q2) -> decltype(q1 - as_quantity(q2)) {
               ^
au/code/au/quantity.hh:671:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator-(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) - q2) {
               ^
au/code/au/quantity_point.hh:405:16: note: candidate template ignored: could not match 'QuantityPoint' against 'QuantityMaker'
constexpr auto operator-(QuantityPoint<UnitP, R1> p, Quantity<UnitQ, RepQ> q) {
               ^
au/code/au/quantity_point.hh:410:16: note: candidate template ignored: could not match 'QuantityPoint' against 'QuantityMaker'
constexpr auto operator-(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
               ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:287:68: error: invalid operands to binary expression ('au::QuantityPoint<au::Meters, int>' and 'au::QuantityPoint<au::Meters, int>')
    friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() + std::declval<RepT>())>
                                              ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:489:33: note: in instantiation of template class 'au::Quantity<au::Meters, au::QuantityPoint<au::Meters, int>>' requested here
    constexpr Quantity<Unit, T> operator()(T value) const {
                                ^
au/code/au/au_test.cc:96:11: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::QuantityPoint<au::Meters, int>>' requested here
    meters(meters_pt(15));
          ^
au/code/au/quantity_point.hh:250:27: note: candidate function not viable: no known conversion from 'au::QuantityPoint<au::Meters, int>' to 'au::QuantityPoint<au::Meters, int>::Diff' (aka 'Quantity<au::Meters, int>') for 1st argument
    constexpr friend auto operator+(Diff d, QuantityPoint p) { return QuantityPoint{d + p.x_}; }
                          ^
au/code/au/quantity_point.hh:251:27: note: candidate function not viable: no known conversion from 'au::QuantityPoint<au::Meters, int>' to 'au::QuantityPoint<au::Meters, int>::Diff' (aka 'Quantity<au::Meters, int>') for 2nd argument
    constexpr friend auto operator+(QuantityPoint p, Diff d) { return QuantityPoint{p.x_ + d}; }
                          ^
au/code/au/zero.hh:55:23: note: candidate function not viable: no known conversion from 'au::QuantityPoint<au::Meters, int>' to 'au::Zero' for 1st argument
inline constexpr Zero operator+(Zero, Zero) { return ZERO; }
                      ^
au/code/au/quantity.hh:623:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
               ^
au/code/au/quantity.hh:633:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(Quantity<U, R> q1, QLike q2) -> decltype(q1 + as_quantity(q2)) {
               ^
au/code/au/quantity.hh:667:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) + q2) {
               ^
au/code/au/quantity_point.hh:395:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(QuantityPoint<UnitP, RepP> p, Quantity<UnitQ, RepQ> q) {
               ^
au/code/au/quantity_point.hh:400:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(Quantity<UnitQ, RepQ> q, QuantityPoint<UnitP, RepP> p) {
               ^
au/code/au/quantity_point.hh:80:88: error: invalid operands to binary expression ('au::Quantity<au::Meters, au::QuantityPoint<au::Meters, int>>' and 'au::Zero')
            decltype(std::declval<typename QuantityPoint<OtherUnit, OtherRep>::Diff>() +
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
au/code/au/quantity_point.hh:91:24: note: in instantiation of function template specialization 'au::QuantityPoint<au::Meters, au::QuantityPoint<au::Meters, int>>::should_enable_implicit_construction_from<au::Meters, au::QuantityPoint<au::Meters, int>>' requested here
        QuantityPoint::should_enable_implicit_construction_from<OtherUnit, OtherRep>()>;
                       ^
au/code/au/quantity_point.hh:107:33: note: in instantiation of template type alias 'EnableIfImplicitOkIs' requested here
              typename Enable = EnableIfImplicitOkIs<true, OtherUnit, OtherRep>>
                                ^
au/code/au/quantity_point.hh:108:15: note: in instantiation of default argument for 'QuantityPoint<au::Meters, au::QuantityPoint<au::Meters, int>>' required here
    constexpr QuantityPoint(QuantityPoint<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity_point.hh:287:16: note: while substituting deduced template arguments into function template 'QuantityPoint' [with OtherUnit = au::Meters, OtherRep = au::QuantityPoint<au::Meters, int>, Enable = (no value)]
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
               ^
au/code/au/au_test.cc:97:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::QuantityPoint<au::Meters, int>>' requested here
    meters_pt(meters_pt(51));
             ^
au/code/au/zero.hh:55:23: note: candidate function not viable: no known conversion from 'au::Quantity<au::Meters, au::QuantityPoint<au::Meters, int>>' to 'au::Zero' for 1st argument
inline constexpr Zero operator+(Zero, Zero) { return ZERO; }
                      ^
au/code/au/quantity_point.hh:250:27: note: candidate function not viable: no known conversion from 'Quantity<[...], au::QuantityPoint<au::Meters, int>>' to 'Quantity<[...], au::QuantityPoint<au::Meters, int>::Rep>' for 1st argument
    constexpr friend auto operator+(Diff d, QuantityPoint p) { return QuantityPoint{d + p.x_}; }
                          ^
au/code/au/quantity_point.hh:251:27: note: candidate function not viable: no known conversion from 'au::Quantity<au::Meters, au::QuantityPoint<au::Meters, int>>' to 'au::QuantityPoint<au::Meters, int>' for 1st argument
    constexpr friend auto operator+(QuantityPoint p, Diff d) { return QuantityPoint{p.x_ + d}; }
                          ^
au/code/au/quantity.hh:623:16: note: candidate template ignored: could not match 'Quantity<U2, R2>' against 'au::Zero'
constexpr auto operator+(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
               ^
au/code/au/quantity.hh:633:16: note: candidate template ignored: substitution failure [with U = au::Meters, R = au::QuantityPoint<au::Meters, int>, QLike = au::Zero]: no matching function for call to 'as_quantity'
constexpr auto operator+(Quantity<U, R> q1, QLike q2) -> decltype(q1 + as_quantity(q2)) {
               ^                                                       ~~~~~~~~~~~
au/code/au/quantity.hh:667:16: note: candidate template ignored: could not match 'Quantity<U, R>' against 'au::Zero'
constexpr auto operator+(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) + q2) {
               ^
au/code/au/quantity_point.hh:395:16: note: candidate template ignored: could not match 'QuantityPoint' against 'Quantity'
constexpr auto operator+(QuantityPoint<UnitP, RepP> p, Quantity<UnitQ, RepQ> q) {
               ^
au/code/au/quantity_point.hh:400:16: note: candidate template ignored: could not match 'QuantityPoint<UnitP, RepP>' against 'au::Zero'
constexpr auto operator+(Quantity<UnitQ, RepQ> q, QuantityPoint<UnitP, RepP> p) {
               ^
au/code/au/quantity.hh:371:24: note: candidate function not viable: requires 0 arguments, but 2 were provided
    constexpr Quantity operator+() const { return {+value_}; }
                       ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:19:
In file included from au/code/au/apply_magnitude.hh:17:
In file included from au/code/au/apply_rational_magnitude_to_integral.hh:19:
In file included from au/code/au/magnitude.hh:21:
au/code/au/stdx/utility.hh:100:65: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
    constexpr bool operator()(T t, U u) { return t < 0 ? true : std::make_unsigned_t<T>(t) < u; }
                                                                ^
au/code/au/stdx/utility.hh:46:12: note: in instantiation of member function 'au::stdx::CmpLessImpl<int, au::Quantity<au::Meters, int>>::operator()' requested here
    return CmpLessImpl<T, U>{}(t, u);
           ^
au/code/au/stdx/utility.hh:64:13: note: in instantiation of function template specialization 'au::stdx::cmp_less<int, au::Quantity<au::Meters, int>>' requested here
    return !cmp_less(t, u);
            ^
au/code/au/stdx/utility.hh:70:12: note: in instantiation of function template specialization 'au::stdx::cmp_greater_equal<int, au::Quantity<au::Meters, int>>' requested here
    return cmp_greater_equal(t, std::numeric_limits<R>::min()) &&
           ^
au/code/au/conversion_policy.hh:47:37: note: in instantiation of function template specialization 'au::stdx::in_range<au::Quantity<au::Meters, int>, int>' requested here
          stdx::bool_constant<stdx::in_range<Rep>(OVERFLOW_THRESHOLD)>,
                                    ^
au/code/au/stdx/type_traits.hh:36:25: note: in instantiation of template class 'au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>' requested here
struct conjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:38:32: note: (skipping 10 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
struct conjunction<B, Bn...> : std::conditional_t<bool(B::value), conjunction<Bn...>, B> {};
                               ^
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:19:
In file included from au/code/au/apply_magnitude.hh:17:
In file included from au/code/au/apply_rational_magnitude_to_integral.hh:19:
In file included from au/code/au/magnitude.hh:21:
au/code/au/stdx/utility.hh:105:70: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
    constexpr bool operator()(T t, U u) { return u < 0 ? false : t < std::make_unsigned_t<U>(u); }
                                                                     ^
au/code/au/stdx/utility.hh:46:12: note: in instantiation of member function 'au::stdx::CmpLessImpl<au::Quantity<au::Meters, int>, int>::operator()' requested here
    return CmpLessImpl<T, U>{}(t, u);
           ^
au/code/au/stdx/utility.hh:52:12: note: in instantiation of function template specialization 'au::stdx::cmp_less<au::Quantity<au::Meters, int>, int>' requested here
    return cmp_less(u, t);
           ^
au/code/au/stdx/utility.hh:58:13: note: in instantiation of function template specialization 'au::stdx::cmp_greater<int, au::Quantity<au::Meters, int>>' requested here
    return !cmp_greater(t, u);
            ^
au/code/au/stdx/utility.hh:71:12: note: in instantiation of function template specialization 'au::stdx::cmp_less_equal<int, au::Quantity<au::Meters, int>>' requested here
           cmp_less_equal(t, std::numeric_limits<R>::max());
           ^
au/code/au/conversion_policy.hh:47:37: note: in instantiation of function template specialization 'au::stdx::in_range<au::Quantity<au::Meters, int>, int>' requested here
          stdx::bool_constant<stdx::in_range<Rep>(OVERFLOW_THRESHOLD)>,
                                    ^
au/code/au/stdx/type_traits.hh:36:25: note: (skipping 11 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
struct conjunction<B> : B {};
                        ^
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:19:
In file included from au/code/au/apply_magnitude.hh:17:
In file included from au/code/au/apply_rational_magnitude_to_integral.hh:19:
au/code/au/magnitude.hh:519:43: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
    return {MagRepresentationOutcome::OK, static_cast<T>(1)};
                                          ^
au/code/au/magnitude.hh:534:29: note: in instantiation of function template specialization 'au::detail::get_value_result<au::Quantity<au::Meters, int>>' requested here
    constexpr auto result = get_value_result<T>(m);
                            ^
au/code/au/conversion_policy.hh:34:50: note: in instantiation of function template specialization 'au::get_value<au::Quantity<au::Meters, int>>' requested here
        return std::numeric_limits<Rep>::max() / get_value<Rep>(m) >= value;
                                                 ^
au/code/au/conversion_policy.hh:48:31: note: in instantiation of function template specialization 'au::can_scale_without_overflow<au::Quantity<au::Meters, int>>' requested here
          stdx::bool_constant<can_scale_without_overflow<Rep>(ScaleFactor{}, OVERFLOW_THRESHOLD)>> {
                              ^
au/code/au/stdx/type_traits.hh:36:25: note: in instantiation of template class 'au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>' requested here
struct conjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct conjunction<B, Bn...> : std::conditional_t<bool(B::value), conjunction<Bn...>, B> {};
                               ^
au/code/au/stdx/type_traits.hh:38:32: note: (skipping 9 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:20:
au/code/au/conversion_policy.hh:34:16: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
        return std::numeric_limits<Rep>::max() / get_value<Rep>(m) >= value;
               ^
au/code/au/conversion_policy.hh:48:31: note: in instantiation of function template specialization 'au::can_scale_without_overflow<au::Quantity<au::Meters, int>>' requested here
          stdx::bool_constant<can_scale_without_overflow<Rep>(ScaleFactor{}, OVERFLOW_THRESHOLD)>> {
                              ^
au/code/au/stdx/type_traits.hh:36:25: note: in instantiation of template class 'au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>' requested here
struct conjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct conjunction<B, Bn...> : std::conditional_t<bool(B::value), conjunction<Bn...>, B> {};
                               ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
au/code/au/stdx/type_traits.hh:44:25: note: in instantiation of template class 'au::stdx::conjunction<std::is_integral<int>, au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct disjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:46:32: note: (skipping 7 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
struct disjunction<B, Bn...> : std::conditional_t<bool(B::value), B, disjunction<Bn...>> {};
                               ^
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:20:
au/code/au/conversion_policy.hh:48:78: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
          stdx::bool_constant<can_scale_without_overflow<Rep>(ScaleFactor{}, OVERFLOW_THRESHOLD)>> {
                                                                             ^
au/code/au/stdx/type_traits.hh:36:25: note: in instantiation of template class 'au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>' requested here
struct conjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct conjunction<B, Bn...> : std::conditional_t<bool(B::value), conjunction<Bn...>, B> {};
                               ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
au/code/au/stdx/type_traits.hh:44:25: note: in instantiation of template class 'au::stdx::conjunction<std::is_integral<int>, au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct disjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:46:32: note: in instantiation of template class 'au::stdx::disjunction<au::stdx::conjunction<std::is_integral<int>, au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>>' requested here
struct disjunction<B, Bn...> : std::conditional_t<bool(B::value), B, disjunction<Bn...>> {};
                               ^
au/code/au/conversion_policy.hh:56:7: note: (skipping 6 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
    : stdx::disjunction<
      ^
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
9 errors generated.

New error messages

In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:119:5: error: static_assert failed due to requirement 'IsValidRep<au::QuantityMaker<au::Radians>>::value' "Rep must meet our requirements for a rep"
    static_assert(IsValidRep<Rep>::value, "Rep must meet our requirements for a rep");
    ^             ~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:498:33: note: in instantiation of template class 'au::Quantity<au::Radians, au::QuantityMaker<au::Radians>>' requested here
    constexpr Quantity<Unit, T> operator()(T value) const {
                                ^
au/code/au/au_test.cc:94:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Radians>::operator()<au::QuantityMaker<au::Radians>>' requested here
    radians(radians);
           ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:505:9: error: static_assert failed due to requirement 'is_not_already_a_quantity' "Input to QuantityMaker is already a Quantity"
        static_assert(is_not_already_a_quantity, "Input to QuantityMaker is already a Quantity");
        ^             ~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/au_test.cc:95:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Radians>::operator()<au::Radians, double>' requested here
    radians(radians(3.14));
           ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:511:9: error: static_assert failed due to requirement 'is_not_a_quantity_point' "Input to QuantityMaker is a QuantityPoint"
        static_assert(is_not_a_quantity_point, "Input to QuantityMaker is a QuantityPoint");
        ^             ~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/au_test.cc:96:11: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Meters, int>' requested here
    meters(meters_pt(15));
          ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:18:
au/code/au/quantity_point.hh:299:9: error: static_assert failed due to requirement 'is_not_already_a_quantity_point' "Input to QuantityPointMaker is already a QuantityPoint"
        static_assert(is_not_already_a_quantity_point,
        ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/au_test.cc:97:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Meters, int>' requested here
    meters_pt(meters_pt(51));
             ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:18:
au/code/au/quantity_point.hh:293:9: error: static_assert failed due to requirement 'is_not_a_quantity' "Input to QuantityPointMaker is a Quantity"
        static_assert(is_not_a_quantity, "Input to QuantityPointMaker is a Quantity");
        ^             ~~~~~~~~~~~~~~~~~
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Meters, int>' requested here
    meters_pt(meters(51));
             ^
5 errors generated.

Copy link
Contributor

@geoffviola geoffviola left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The errors look a lot clearer. The test cases contains all the errors. This should improve usability.

au/code/au/quantity.hh Outdated Show resolved Hide resolved
Co-authored-by: Geoffrey Viola <[email protected]>
@chiphogg chiphogg merged commit 3a4426a into main Sep 23, 2024
10 checks passed
@chiphogg chiphogg deleted the chiphogg/better-errors-q-of-q#288 branch September 23, 2024 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants