Skip to main content

Module recursion

Module recursion 

Source
Expand description

The aggregates of a type graph that sit on a cycle.

A dump emitter inlines a member’s statements into its owner’s, and a type graph with a cycle has no finite inline expansion: the CORBA C++ emitter followed recursive-mutual’s A → sequence<B> → B → sequence<A> until the Rust stack ran out, and the C and Fast DDS emitters shared the walk and the crash. The types this module names are emitted as functions instead, and the expansion calls them where it would have unrolled them.

§Which walks ask, and which two did not

Three emitters carry the answer: crate::dump, crate::dump_cpp and crate::corba_cpp’s dump half, each of which emits one function per aggregate named here and calls it in place of the expansion.

Two ran past it and followed the cycle instead, measured on 2026-08-31 over recursive-mutual — both reached “has overflowed its stack” and SIGABRT:

  • corba_java::dump_at. The C++ half of that same file was given the machinery; the Java half was not.
  • dump_ros::emit. Its comment named ros_idl as the gate, and ros_idl does refuse a recursive type — but wireprobe-dump --ros is a separate process invocation and no gate on this function.

Neither has a shape to emit a function into — a Java method body and a C block inside the ROS decode template — and neither column takes a recursive type at all, so both now refuse one by name, in the words corba_idl and ros_idl already use for it. A refusal is a cell that says why; a stack overflow is a cell that measured nothing.

The fill emitters do not ask, and do not need to: a fill walk follows the sample, and a recursive type has finite samples because the sequence that closes its cycle is eventually empty. That is a termination argument rather than a bound, and it is the sample’s nesting that bounds them.

Functions§

recursive_aggregates
The aggregates reachable from root that sit on a cycle, in first-visit order.