import 가 만든 binding 으로 다른 유닛의 선언에 닿는다. 호출, 구조체 리터럴,
값 참조 세 자리다. 시그니처의 타입은 그 시그니처가 쓰인 유닛에서 해석한다 --
호출한 쪽에서 해석하면 같은 이름이 다른 타입을 가리킨다.
pub 없는 선언과 필드는 자기 유닛 밖에서 보이지 않는다.
error.Name 은 구현된 적이 없었다. 기본 에러 집합 core.Error 의 멤버이고, 그
집합은 선언이 아니라 수집으로 채워지므로 변이 목록 없이 정체성만 갖는다.
units 34/34. dotpriv/main 은 위반이 있는 유닛을 import 하므로 받아들여질 수
없다 -- 마커를 붙이고 이유를 적었다.
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`.
The milestone structure had stopped describing the compiler and started
shaping it: m7.c, check_m7.c, tests/m2..m9, and a checker and emitter that had
each grown past 2,500 lines because there was nowhere else to put anything.
Restart from the pipeline instead.
What is left is the front end -- lexer, parser, types, ownership, semantic
analysis -- and the fixtures that describe it. The C backend, the DOSBox-X
runner, the milestone registry and the batch build are removed. The driver now
stops after semantic analysis; a code generator attaches where emit_c did.
Fixtures move from milestone directories to what they check:
parse/ grammar own/ ownership and borrowing
types/ type rules optional/ optionals and error unions
format/ formatting, try units/ units and visibility
generic/ generics pending-backend/
pending-backend/ holds the three fixtures that can only be checked by running
a program -- that the bounds check traps, that --no-checks removes it, and that
drops and defers actually fire, verified through a fake allocator. Those are
not front-end tests and are not pretending to be; they come back first when
there is a code generator.
tests/run.py replaces the DOSBox-X harness. It builds the front end with the
pinned Watcom's Windows-hosted driver and runs every fixture in about two
seconds, and it does something the old runner structurally could not: it reads
the `// ERROR:line:text` marker each fixture carries and checks the diagnostic
against it. Those markers have been in the tree all along, unverified, because
DOS could not redirect the compiler's stderr and only the exit code was ever
compared.
133/188 pass. The 55 failures are not regressions -- they are what was already
true and invisible:
- units (27) and generic (23): `import`, `comptime` and generic declarations
parse and are then dropped on the floor. No pass looks at them. The old
registry did not list these fixtures at all, so nothing said so.
- five in own/, optional/ and generic/: a marker disagrees with the diagnostic
about the line or the wording. Each is either a wrong marker or a wrong
diagnostic and has to be read individually.
Everything removed is in git history.