Files
doslang-mirror/fec/tests/units
coolguy 38dddc234c implement: load the unit graph -- imports, cycles, bindings
The driver handled one file. It now loads the graph rooted at the entry file
and checks every unit in it.

The import root is derived rather than configured: a unit named `a.b` read
from `<root>/a/b.fe` fixes `<root>`, so a sibling `import c.d;` is looked for
at `<root>/c/d.fe`. That is enough for the fixtures and for any tree that
follows 8.1, and it means there is no path flag to get wrong yet.

Loading is depth-first with the chain of units currently open kept on a stack,
so meeting one again is a cycle rather than a revisit -- a unit reached twice
by different paths is loaded once. Cycles, imports with no source file, and two
imports claiming the same binding are all reported.

One thing this exposed: FeDiags held a single source buffer, so once a build
spanned several files every excerpt was drawn from whichever file was parsed
last. `cycle/b.fe:3` printed the text of a.fe. fe_diags_source switches it, and
loading and checking both set it per unit.

The cycle fixtures lost their line markers on purpose. Which import closes the
cycle depends on which file you enter from -- entering at a.fe reports b.fe,
entering at b.fe reports a.fe -- so pinning a line would pin an arbitrary half
of a symmetric pair. The message is pinned; the line is not.

units: missing, bindconf and cycle pass, on top of the identity cases.
146 -> 148 of 188. What is left in units/ needs cross-unit name resolution and
visibility: an importer still cannot see `util.answer`.
2026-08-17 03:54:43 +09:00
..

M8 fixtures

M8 is the first multi-unit milestone, so cases live in subdirectories. Each case is compiled separately with that directory on the import path.

Pass cases:

  • basic: public function across units.
  • pubfld: public type and public field across units.
  • dotted and alias: canonical dotted unit paths, last-segment binding, and explicit import aliases.
  • dotpriv: a dotted unit prefix does not grant access to another unit's private declarations.
  • errsame: two units use the same anonymous error.Name; the driver must assign one deterministic core.Error code.
  • errdet: the same anonymous error-name set appears in a different source/import order; generated fe_errors.h must be byte-identical to errsame modulo the intentionally different unit graph.

Fail cases:

  • privfn: private declaration access.
  • privfld: private field access.
  • missing: unresolved import.
  • cycle: cyclic imports.
  • unitbad: filename/unit-name mismatch.
  • badupper and badlong: DOS-safe lowercase, eight-character unit-segment limit.
  • bindconf: two imports with the same last-segment binding require an alias.
  • pubpriv: a public signature cannot expose a private nominal type.
  • errnom: nominal error cannot flow into core.Error via try.

They are not registered in src/ferrolang_vm/registry.py yet. M8 should add procedural checks for .fei creation/hash invalidation and deterministic fe_errors.h using these fixtures.

The M8 DOS gate must additionally construct two separate -I roots containing the same canonical unit and require an ambiguity error; repeat the case with two paths to the same canonical file and require deduplication. It must also verify that std.* resolves only from the built-in std root, ordinary user units never do, and that changing a private non-generic implementation preserves the dependent interface-cache hit. Those checks need temporary roots/cache inspection and deliberately remain procedural rather than encoding host paths in fixtures.