Skip to content

Commit 441bd07

Browse files
committed
🎨 Improve flow error messages
Problem: - Flow errors use a hacky technique to output useful information. Solution: - Use `stdx::ct_check`.
1 parent f68cd9c commit 441bd07

File tree

6 files changed

+68
-87
lines changed

6 files changed

+68
-87
lines changed

.github/workflows/asciidoctor-ghpages.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
- name: Checkout source
3636
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3737
- name: Setup Node.js
38-
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
38+
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
3939
with:
4040
node-version: 20
4141
- name: Install Mermaid

include/flow/graph_builder.hpp

Lines changed: 46 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -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) {
@@ -101,29 +80,20 @@ struct graph_builder {
10180
stdx::for_each(
10281
[&]<typename P>(P const &) {
10382
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.");
83+
constexpr auto error = stdx::ct_format<
84+
"The conditions on the sequence ({} >> "
85+
"{})[{}] are weaker than those on {}[{}] or "
86+
"{}[{}]. Specifically, the sequence is missing "
87+
"the predicate: {}">(
88+
CX_VALUE(lhs_t::ct_name),
89+
CX_VALUE(rhs_t::ct_name),
90+
CX_VALUE(Cond::ct_name),
91+
CX_VALUE(lhs_t::ct_name),
92+
CX_VALUE(lhs_t::condition.ct_name),
93+
CX_VALUE(rhs_t::ct_name),
94+
CX_VALUE(rhs_t::condition.ct_name),
95+
CX_VALUE(P));
96+
stdx::ct_check<false>.template emit<error>();
12797
}
12898
},
12999
node_ps);
@@ -133,6 +103,7 @@ struct graph_builder {
133103
edges);
134104
return g;
135105
}
106+
// NOLINTEND(readability-function-cognitive-complexity)
136107

137108
template <typename Node, typename Graph>
138109
[[nodiscard]] constexpr static auto is_source_of(Node const &node,
@@ -208,44 +179,43 @@ struct graph_builder {
208179
boost::mp11::mp_set_difference<mentioned_node_names_t,
209180
node_names_t>;
210181

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)>>{});
182+
constexpr auto error =
183+
stdx::ct_format<"One or more steps are referenced in the "
184+
"flow ({}) but not explicitly added with the "
185+
"* operator. The missing steps are: {}.">(
186+
CX_VALUE(Name),
187+
CX_VALUE(stdx::transform(
188+
[]<typename N>(N) {
189+
return stdx::ct_string_from_type(N{});
190+
},
191+
missing_nodes_t{})
192+
.join([](auto x, auto y) {
193+
using namespace stdx::literals;
194+
return x + ", "_cts + y;
195+
})));
196+
stdx::ct_check<false>.template emit<error>();
228197
}
229198

230199
if constexpr (stdx::tuple_size_v<node_names_t> !=
231200
stdx::tuple_size_v<decltype(node_names)>) {
232201
constexpr auto duplicates = stdx::transform(
233-
[](auto e) {
234-
return stdx::ct_string_from_type(stdx::get<0>(e));
235-
},
202+
[](auto e) { return stdx::get<0>(e); },
236203
stdx::filter<detail::is_duplicated>(stdx::gather(node_names)));
237204

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)>>{});
205+
constexpr auto error = stdx::ct_format<
206+
"One or more steps in the flow ({}) are explicitly added more "
207+
"than once using the * operator. The duplicate steps are: {}.">(
208+
CX_VALUE(Name),
209+
CX_VALUE(stdx::transform(
210+
[]<typename N>(N) {
211+
return stdx::ct_string_from_type(N{});
212+
},
213+
decltype(duplicates){})
214+
.join([](auto x, auto y) {
215+
using namespace stdx::literals;
216+
return x + ", "_cts + y;
217+
})));
218+
stdx::ct_check<false>.template emit<error>();
249219
}
250220
}
251221

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)