Skip to content

Commit 0bfa908

Browse files
authored
Merge pull request #637 from elbeno/ct-messages
🎨 Improve flow error messages with `STATIC_ASSERT`
2 parents 0842a1d + 91e6e6c commit 0bfa908

File tree

6 files changed

+65
-105
lines changed

6 files changed

+65
-105
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ include(cmake/string_catalog.cmake)
2525
add_versioned_package("gh:boostorg/mp11#boost-1.83.0")
2626
fmt_recipe(10.2.1)
2727
add_versioned_package("gh:intel/cpp-baremetal-concurrency#7c5b26c")
28-
add_versioned_package("gh:intel/cpp-std-extensions#5530b5d")
28+
add_versioned_package("gh:intel/cpp-std-extensions#73569fe")
2929
add_versioned_package("gh:intel/cpp-baremetal-senders-and-receivers#73d95bc")
3030

3131
add_library(cib INTERFACE)

include/flow/graph_builder.hpp

Lines changed: 43 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
#include <flow/detail/walk.hpp>
55
#include <flow/impl.hpp>
66

7-
#include <stdx/ct_format.hpp>
87
#include <stdx/ct_string.hpp>
98
#include <stdx/cx_multimap.hpp>
109
#include <stdx/cx_set.hpp>
1110
#include <stdx/cx_vector.hpp>
1211
#include <stdx/span.hpp>
12+
#include <stdx/static_assert.hpp>
1313
#include <stdx/tuple_algorithms.hpp>
1414
#include <stdx/type_traits.hpp>
1515
#include <stdx/utility.hpp>
@@ -52,31 +52,10 @@ template <typename T> using name_for = typename T::name_t;
5252
});
5353
}
5454

55-
template <typename Cond> struct sequence_conditions;
56-
57-
template <auto...> struct INFO_flow_name_;
58-
59-
template <auto...> struct INFO_step_a_name_;
60-
61-
template <auto...> struct INFO_step_a_condition_;
62-
63-
template <auto...> struct INFO_step_b_name_;
64-
65-
template <auto...> struct INFO_step_b_condition_;
66-
67-
template <auto...> struct INFO_sequence_condition_;
68-
69-
template <typename...> struct INFO_sequence_missing_predicate_;
70-
71-
template <typename...> constexpr bool ERROR_DETAILS_ = false;
72-
73-
template <auto...> struct INFO_missing_steps_;
74-
75-
template <auto...> struct INFO_duplicated_steps_;
76-
7755
template <stdx::ct_string Name,
7856
template <stdx::ct_string, std::size_t> typename Impl>
7957
struct graph_builder {
58+
// NOLINTBEGIN(readability-function-cognitive-complexity)
8059
template <typename Node, std::size_t N, std::size_t E>
8160
[[nodiscard]] constexpr static auto make_graph(auto const &nodes,
8261
auto const &edges) {
@@ -93,38 +72,26 @@ struct graph_builder {
9372

9473
using lhs_t = std::remove_cvref_t<decltype(lhs)>;
9574
using rhs_t = std::remove_cvref_t<decltype(rhs)>;
75+
using lhs_cond_t = std::remove_cvref_t<decltype(lhs.condition)>;
76+
using rhs_cond_t = std::remove_cvref_t<decltype(rhs.condition)>;
9677

9778
using edge_ps_t = decltype(Cond::predicates);
9879
auto node_ps = stdx::to_unsorted_set(stdx::tuple_cat(
9980
lhs_t::condition.predicates, rhs_t::condition.predicates));
10081

10182
stdx::for_each(
10283
[&]<typename P>(P const &) {
103-
if constexpr (not stdx::contains_type<edge_ps_t, P>) {
104-
static_assert(
105-
ERROR_DETAILS_<
106-
INFO_flow_name_<Name>,
107-
INFO_step_a_name_<lhs_t::ct_name>,
108-
INFO_step_a_condition_<
109-
lhs_t::condition.ct_name>,
110-
INFO_step_b_name_<rhs_t::ct_name>,
111-
INFO_step_b_condition_<
112-
rhs_t::condition.ct_name>,
113-
INFO_sequence_condition_<Cond::ct_name>,
114-
INFO_sequence_missing_predicate_<P>>,
115-
116-
"The conditions on this sequence "
117-
"(step_a >> step_b) are weaker than those on "
118-
"step_a and/or step_b. The sequence could be "
119-
"enabled while step_a and/or step_b is not. "
120-
"Specifically, the sequence is missing the "
121-
"predicate identified in "
122-
"`INFO_sequence_missing_predicate_`. TIP: "
123-
"Look for 'ERROR_DETAILS_` and `INFO_` in "
124-
"the compiler error message for details on "
125-
"the sequence, the step names, and the "
126-
"conditions.");
127-
}
84+
STATIC_ASSERT(
85+
(stdx::contains_type<edge_ps_t, P>),
86+
"The conditions on the sequence ({} >> {})[{}] are "
87+
"weaker than those on {}[{}] or {}[{}]. "
88+
"Specifically, the sequence is missing the "
89+
"predicate: {}",
90+
CX_VALUE(lhs_t::ct_name), CX_VALUE(rhs_t::ct_name),
91+
CX_VALUE(Cond::ct_name), CX_VALUE(lhs_t::ct_name),
92+
CX_VALUE(lhs_cond_t::ct_name),
93+
CX_VALUE(rhs_t::ct_name),
94+
CX_VALUE(rhs_cond_t::ct_name), CX_VALUE(P));
12895
},
12996
node_ps);
13097

@@ -133,6 +100,7 @@ struct graph_builder {
133100
edges);
134101
return g;
135102
}
103+
// NOLINTEND(readability-function-cognitive-complexity)
136104

137105
template <typename Node, typename Graph>
138106
[[nodiscard]] constexpr static auto is_source_of(Node const &node,
@@ -191,6 +159,15 @@ struct graph_builder {
191159
return std::optional<Output>{std::in_place, span_t{ordered_list}};
192160
}
193161

162+
template <typename T>
163+
constexpr static auto error_steps =
164+
stdx::transform([](auto N) { return stdx::ct_string_from_type(N); },
165+
T{})
166+
.join(stdx::ct_string{""}, [](auto x, auto y) {
167+
using namespace stdx::literals;
168+
return x + ", "_cts + y;
169+
});
170+
194171
constexpr static void check_for_missing_nodes(auto nodes,
195172
auto mentioned_nodes) {
196173
constexpr auto get_name = []<typename N>(N) ->
@@ -201,52 +178,24 @@ struct graph_builder {
201178
using node_names_t = decltype(stdx::to_sorted_set(node_names));
202179
using mentioned_node_names_t =
203180
decltype(stdx::to_sorted_set(mentioned_node_names));
204-
205-
if constexpr (not std::is_same_v<node_names_t,
206-
mentioned_node_names_t>) {
207-
using missing_nodes_t =
208-
boost::mp11::mp_set_difference<mentioned_node_names_t,
209-
node_names_t>;
210-
211-
constexpr auto missing_nodes = missing_nodes_t{};
212-
constexpr auto missing_nodes_ct_strings = stdx::transform(
213-
[]<typename N>(N) { return stdx::ct_string_from_type(N{}); },
214-
missing_nodes);
215-
216-
[&]<std::size_t... Is>(std::index_sequence<Is...>) {
217-
using error_details_t = INFO_missing_steps_<stdx::get<Is>(
218-
missing_nodes_ct_strings)...>;
219-
220-
static_assert(
221-
ERROR_DETAILS_<INFO_flow_name_<Name>, error_details_t>,
222-
"One or more steps are referenced in the flow but not "
223-
"explicitly added with the * operator. The "
224-
"beginning of this error shows you which steps are "
225-
"missing.");
226-
}(std::make_index_sequence<
227-
stdx::tuple_size_v<decltype(missing_nodes)>>{});
228-
}
229-
230-
if constexpr (stdx::tuple_size_v<node_names_t> !=
231-
stdx::tuple_size_v<decltype(node_names)>) {
232-
constexpr auto duplicates = stdx::transform(
233-
[](auto e) {
234-
return stdx::ct_string_from_type(stdx::get<0>(e));
235-
},
236-
stdx::filter<detail::is_duplicated>(stdx::gather(node_names)));
237-
238-
[&]<std::size_t... Is>(std::index_sequence<Is...>) {
239-
using error_details_t =
240-
INFO_duplicated_steps_<stdx::get<Is>(duplicates)...>;
241-
242-
static_assert(
243-
ERROR_DETAILS_<INFO_flow_name_<Name>, error_details_t>,
244-
"One or more steps are explicitly added more than once "
245-
"using the * operator. The beginning of this "
246-
"error shows you which steps are duplicated.");
247-
}(std::make_index_sequence<
248-
stdx::tuple_size_v<decltype(duplicates)>>{});
249-
}
181+
using missing_nodes_t =
182+
boost::mp11::mp_set_difference<mentioned_node_names_t,
183+
node_names_t>;
184+
STATIC_ASSERT(
185+
(std::is_same_v<node_names_t, mentioned_node_names_t>),
186+
"One or more steps are referenced in the flow ({}) but not "
187+
"explicitly added with the * operator. The missing steps are: {}.",
188+
CX_VALUE(Name), CX_VALUE(error_steps<missing_nodes_t>));
189+
190+
constexpr auto duplicates = stdx::transform(
191+
[](auto e) { return stdx::get<0>(e); },
192+
stdx::filter<detail::is_duplicated>(stdx::gather(node_names)));
193+
using duplicate_nodes_t = decltype(duplicates);
194+
STATIC_ASSERT(
195+
stdx::tuple_size_v<duplicate_nodes_t> == 0,
196+
"One or more steps in the flow ({}) are explicitly added more than "
197+
"once using the * operator. The duplicate steps are: {}.",
198+
CX_VALUE(Name), CX_VALUE(error_steps<duplicate_nodes_t>));
250199
}
251200

252201
template <typename Graph>

test/flow/fail/CMakeLists.txt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
1-
add_compile_fail_test(cyclic_flow.cpp LIBRARIES warnings cib)
2-
add_compile_fail_test(only_reference_added.cpp LIBRARIES warnings cib)
3-
add_compile_fail_test(mismatched_flow_runtime_conditional.cpp LIBRARIES
4-
warnings cib)
5-
add_compile_fail_test(node_explicitly_added_twice.cpp LIBRARIES warnings cib)
1+
add_compile_fail_test(cyclic_flow.cpp LIBRARIES cib)
2+
3+
function(add_formatted_errors_tests)
4+
add_compile_fail_test(only_reference_added.cpp LIBRARIES cib)
5+
add_compile_fail_test(mismatched_flow_runtime_conditional.cpp LIBRARIES cib)
6+
add_compile_fail_test(node_explicitly_added_twice.cpp LIBRARIES cib)
7+
endfunction()
8+
9+
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" AND ${CMAKE_CXX_COMPILER_VERSION}
10+
VERSION_GREATER_EQUAL 15)
11+
add_formatted_errors_tests()
12+
endif()
13+
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION}
14+
VERSION_GREATER_EQUAL 13.2)
15+
add_formatted_errors_tests()
16+
endif()

test/flow/fail/mismatched_flow_runtime_conditional.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <cib/cib.hpp>
22
#include <flow/flow.hpp>
33

4-
// EXPECT: The conditions on this sequence
4+
// EXPECT: The conditions on the sequence
55

66
namespace {
77
using namespace flow::literals;

test/flow/fail/node_explicitly_added_twice.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#include <cib/cib.hpp>
22
#include <flow/flow.hpp>
33

4-
// EXPECT: One or more steps are explicitly added more than once
4+
// EXPECT: are explicitly added more than once
55

66
namespace {
77
using namespace flow::literals;
88

99
constexpr auto a = flow::milestone<"a">();
1010

11-
struct TestFlowAlpha : public flow::service<> {};
11+
struct TestFlowAlpha : public flow::service<"alpha"> {};
1212

1313
struct FlowConfig {
1414
constexpr static auto config = cib::config(

test/flow/fail/only_reference_added.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#include <cib/cib.hpp>
22
#include <flow/flow.hpp>
33

4-
// EXPECT: One or more steps are referenced in the flow but not explicitly
4+
// EXPECT: One or more steps are referenced in the flow
55

66
namespace {
77
using namespace flow::literals;
88

99
constexpr auto a = flow::milestone<"a">();
1010

11-
struct TestFlowAlpha : public flow::service<> {};
11+
struct TestFlowAlpha : public flow::service<"alpha"> {};
1212

1313
struct FlowConfig {
1414
constexpr static auto config =

0 commit comments

Comments
 (0)