flan/test/programs/pkgs/shape/shape.flan
Joseph Ferano c604911ecb A ring of imports is refused by name, not swallowed
Loading a package kept one table, keyed by real path, and used it for two
different questions. Already loaded meant "skip", which is right for the second
route of a diamond and wrong for a ring: a package that imported itself round a
chain met its own entry, contributed nothing, and appeared to work. The comment
said so and called it a feature.

It is not one. A ring has no package order, and a definite package order is what
the macro expander needs — every defmacro has to be compiled before anything
that calls it. So the chain currently being read is now carried separately from
the set already finished. A directory found in the first is a cycle and is
refused; a directory found only in the second is still the diamond's second
route and still a no-op.

The refusal names the ring — a -> b -> c -> a — and only the ring, not the route
that led to it. "There is a cycle" leaves the reader to find which three imports
it was.

pkgs now comes back dependencies-first, which is the topological order the
acyclic rule buys. The declaration list is left alone: check.ml collects every
top-level name before it checks any body, so declarations are order-independent
by construction and sorting them would be churn in the field every test reads.

The tests are a real tree rather than a second copy of pkg-shared. pkg-diamond
builds a shape/Box inside area/ and hands it to a function declared inside
draw/, which only type-checks if the bottom package was read once — two copies
of one struct are two types. What proves it is the numbers, not the compile.
2026-09-12 16:46:30 +07:00

13 lines
501 B
Plaintext

;;;; The bottom of the diamond: the one package both middles depend on.
;;;;
;;;; Box has to be one type. If this directory were read twice — once along
;;;; area/, once along draw/ — there would be two defstructs both qualified
;;;; shape/Box, and the checker would either refuse the collision or, worse,
;;;; unify nothing. That is the failure this tree exists to catch.
(defstruct Box [w i32 h i32])
(defn box [w i32 h i32] Box (Box {.w w .h h}))
(defn wide? [b Box] bool (> (.w b) (.h b)))