diff --git a/runtime/flan_dyn.h b/runtime/flan_dyn.h index 3d58cb4..6a82133 100644 --- a/runtime/flan_dyn.h +++ b/runtime/flan_dyn.h @@ -3,12 +3,21 @@ * This header is not compiled into a program. The build embeds the runtime's * .c files as strings and hands each one to clang on its own, with no include * path (see [Build.compile_c]), so runtime/flan_dyn.c declares everything it - * defines and this file declares it a second time. That second copy is not - * held honest by hand the way a repeated escape table would be: it is made - * mechanical, because test/dyn_ops.c includes this header and names every - * function below, so a signature that drifts from the implementation is a - * link error in `dune test` rather than a surprise at someone else's call - * site. + * defines and this file declares it a second time. What keeps that second + * copy honest is partial, and the exact shape of it is worth writing down + * rather than overclaiming: test/dyn_ops.c includes this header and calls + * most of what it declares, so a name that is spelled one way here and + * another way in flan_dyn.c fails to link in `dune test`. + * + * Two holes in that. A signature that drifts while the name stays is not + * caught at all — C links on names and not on types, so a changed parameter + * or return type compiles on both sides and goes wrong at the call site + * instead of failing the build. And five of the names below are never + * referenced by dyn_ops.c — [flan_dyn_map_get], [flan_dyn_map_set], + * [flan_dyn_map_contains], [flan_dyn_is_nil] and [flan_dyn_need_not_nil] — + * so not even the rename check reaches them. Calling those five from + * dyn_ops.c would close the second hole; nothing available from here closes + * the first. * * Who reads it: the compiler lane, which emits calls to these names, and the * C tests. The whole of the boundary is here. What is behind it — the value