compiler: implement blank package name semantics
This commit is contained in:
@@ -6982,8 +6982,11 @@ test-runtime gap:
|
||||
with official anchors in
|
||||
[`internal/types/testdata/check/blank.go`](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/blank.go#L1-L5)
|
||||
and [`test/blank1.go`](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/blank1.go#L1-L10).
|
||||
Direct production, imported, and test-only probes were rejected identically
|
||||
by both WW stages. This candidate was aligned.
|
||||
Direct production, imported, and test-only probes were rejected by both WW
|
||||
stages, but only through the loader's generic `invalid or missing package
|
||||
clause`; the direct compilers also produced different syntax-recovery
|
||||
streams. Equal rejection was not semantic alignment. The gap was different
|
||||
and is completed in section 11.56.
|
||||
- **Import:** pinned `unusedImports` requires every nonblank import binding to
|
||||
be used
|
||||
([`cmd/compile/internal/types2/resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)); official
|
||||
@@ -10354,11 +10357,11 @@ a raw source and does not trigger the non-directory test-source omission in
|
||||
- **directly measured WW behavior** — direct `SIGTERM` of either driver while a
|
||||
selected warm build is blocked in compilation is an inherited lifecycle
|
||||
non-effect, not part of the classifier change. Both stages terminate with
|
||||
shell status 143, reap the complete owned process group, and preserve the
|
||||
prior public output and committed semantic bytes, but the existing directory
|
||||
machinery leaves three request-private `.new` files. That independently
|
||||
verified cleanup gap remains open and this slice does not describe it as
|
||||
fixed.
|
||||
shell status 143 and preserve the prior public output and committed semantic
|
||||
bytes, but leave the directly spawned compiler alive and exactly three
|
||||
fixed-name `.new` files. A later persistent request rejects the existing
|
||||
`.unit.new`. That independently verified supervision/cleanup gap remains open
|
||||
and this slice does not describe it as fixed.
|
||||
- **directly measured WW behavior** — Cstage and WWstage agree byte-for-byte
|
||||
on status, stdout, stderr, diagnostics, public output, and every semantic
|
||||
artifact for selected success and failure rows. Complete
|
||||
@@ -10852,6 +10855,319 @@ every other package name remain ordinary.
|
||||
remains `3`; no action descriptor, cache/result record, transaction marker,
|
||||
manifest, database, or lock is added.
|
||||
|
||||
### 11.56 Implemented blank declared package-name checking
|
||||
|
||||
The exact declared name in `package _;` is now valid package-clause syntax and
|
||||
an invalid package name. Loaders retain the clause, its imports, and an
|
||||
otherwise coherent source family long enough to construct the applicable
|
||||
ordinary action; the compiler checker then reports exactly
|
||||
`invalid package name _` at the underscore token and continues checking that
|
||||
source. The underscore is accepted only in this package-name grammar slot. It
|
||||
does not become an ordinary identifier, import alias, qualifier, canonical
|
||||
package name, or successful exported identity.
|
||||
|
||||
#### Pinned authority, tests, and applicability
|
||||
|
||||
The sole authority is official Go 1.26.5 at commit
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- **behavior directly implemented or asserted by pinned Go** — the compiler
|
||||
scanner admits `_` to identifier scanning, dispatches it through the name
|
||||
path, and returns it as a name token; the parser accepts and stores that token
|
||||
in the package-name position
|
||||
([`cmd/compile/internal/syntax/scanner.go`, lines 88–107](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner.go#L88-L107),
|
||||
[368–394](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner.go#L368-L394),
|
||||
and
|
||||
[437–439](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner.go#L437-L439),
|
||||
[`parser.go`, lines 397–420](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/parser.go#L397-L420)
|
||||
and
|
||||
[2751–2763](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/parser.go#L2751-L2763)).
|
||||
The types2 checker rejects the retained node as `invalid package name _`
|
||||
and continues file initialization
|
||||
([`cmd/compile/internal/types2/check.go`, lines 336–355](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/check.go#L336-L355));
|
||||
syntax errors prevent types2 from running
|
||||
([`cmd/compile/internal/noder/noder.go`, lines 45–77](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/noder.go#L45-L77),
|
||||
[`irgen.go`, lines 23–99](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/irgen.go#L23-L99)).
|
||||
- **behavior directly implemented or asserted by pinned Go** — `go/build`
|
||||
reads `_` without declaration-error parsing, classifies production and test
|
||||
roles, and records imports before cmd/go builds package actions
|
||||
([`go/build/read.go`, lines 55–56](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/read.go#L55-L56),
|
||||
[187–198](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/read.go#L187-L198),
|
||||
and
|
||||
[265–340](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/read.go#L265-L340),
|
||||
[`go/build/build.go`, lines 931–1039](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L931-L1039)).
|
||||
Named files use one synthetic package loader
|
||||
([`cmd/go/internal/load/pkg.go`, lines 3244–3315](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L3244-L3315));
|
||||
test synthesis augments production with internal-test files rather than
|
||||
treating them as unrelated packages
|
||||
([`cmd/go/internal/load/test.go`, lines 175–226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L175-L226)).
|
||||
- **behavior directly implemented or asserted by pinned Go** —
|
||||
[`test/blank1.go`, lines 1–31](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/blank1.go#L1-L31)
|
||||
asserts the blank-name error plus later checker errors, directly proving
|
||||
continued checking.
|
||||
[`internal/types/testdata/check/blank.go`, lines 1–5](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/blank.go#L1-L5)
|
||||
separately asserts only the blank-name error. Official role controls
|
||||
[`build_test_only.txt`, lines 1–18](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_test_only.txt#L1-L18)
|
||||
and
|
||||
[`build_no_go.txt`, lines 1–30](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_no_go.txt#L1-L30)
|
||||
anchor the surrounding test-only selection rules. The pinned repository has
|
||||
no official cmd/go test matrix for named, multiple, mixed,
|
||||
test-only, artifact, rollback, concurrency, or interruption forms of
|
||||
`package _`; those are WW-native proofs, not attributed to an absent Go
|
||||
script.
|
||||
- **behavior directly implemented or asserted by pinned Go** — after primary
|
||||
syntax succeeds, types2 validates the imported package object's name before
|
||||
consulting a local alias. Name `_` reports
|
||||
`could not import PATH (invalid package name: "_")` at the import path;
|
||||
an empty name instead quotes the actual empty value as
|
||||
`invalid package name: ""`. The resolver
|
||||
installs and caches a path-leaf-named fake package, marks the occurrence
|
||||
used, and continues checking
|
||||
([`cmd/compile/internal/types2/resolver.go`, lines 125–180 and 248–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L125-L180)).
|
||||
The public checker twin implements the same rule
|
||||
([`go/types/resolver.go`, lines 157–190 and 263–350](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L157-L190)).
|
||||
- No official pinned test directly supplies an imported `Package` whose name
|
||||
is `_`. The two primary-source blank-name tests above do not assert this
|
||||
importer-result validation. Its imported-interface matrix is therefore
|
||||
WW-native proof grounded in the pinned resolver implementation, not a claim
|
||||
about absent official testdata.
|
||||
- **behavior derived from the pinned implementation** — the diagnostic owns
|
||||
the underscore position, normally line 1 column 9, and belongs after source
|
||||
loading, graph construction, complete-file syntax, and dependency-eligible
|
||||
producer ordering. WW has the same explicit package clause, blank token,
|
||||
syntax/check split, package families, imports, and package actions, so the
|
||||
rule applies without adding modules, manifests, registries, generalized
|
||||
imports, or a new identity model.
|
||||
|
||||
Before this slice, **directly measured WW behavior** was a generic positioned
|
||||
`invalid or missing package clause` from both public stages before any
|
||||
producer. Direct Cstage `w6c` emitted four package-clause recovery diagnostics
|
||||
while WWstage `w6c_ww` emitted three. A visible named `_test.ww` ordinary build
|
||||
was rejected at its header instead of being validated and omitted. These facts
|
||||
were a real package/build/test/import difference despite stage-equal public
|
||||
rejection. After the primary-source parser/checker repair and before the
|
||||
imported-interface completion, **directly measured WW behavior** also accepted
|
||||
an owner-matched hand-authored `.wwi` declaring `package _;`: default,
|
||||
explicit, and blank controls accepted and published usable semantic facts, and
|
||||
the explicit alias control produced successful byte-identical Cstage/WWstage
|
||||
assembly and interface output. Ordinary producers could not create that
|
||||
metadata, but direct `--import` and caller-owned persistent interfaces made the
|
||||
gap externally observable.
|
||||
|
||||
#### Semantic ownership
|
||||
|
||||
Primary package-slot syntax and marker positions remain owned by the C/WW
|
||||
parser twins `cmd/wcc/parse.c` and `lib/ww/syntax/parse.ww`; primary and
|
||||
imported blank-name checker diagnostics and fake-package resolution are owned
|
||||
by `cmd/wcc/check.c` and `selfhost/cmd/wcc/check.ww`. Imported export-data
|
||||
materialization, four-state package metadata, primary-rooted reachability,
|
||||
owner filtering, recovery qualifier assignment, and delayed concatenation are
|
||||
owned by `cmd/w6c/main.c` and `selfhost/cmd/w6c/main.ww`. Exact import-path
|
||||
token positions are private `N_USE` state owned by `cmd/wcc/ww.h`,
|
||||
`lib/ww/syntax/ast.ww`, both parser twins, and
|
||||
`lib/ww/syntax/decl.ww`.
|
||||
|
||||
The public drivers and package coordinator already supply canonical direct
|
||||
interface arguments and inherit the validation without edits. No loader,
|
||||
assembler, archiver, linker, runtime, package-identity, or import-syntax owner
|
||||
changes in this completion. This complete ownership replaces the earlier
|
||||
transitional assumption that the slice had only four syntax/checker owners.
|
||||
|
||||
#### Four-axis behavior and phase order
|
||||
|
||||
- **Build:** an eligible blank production source passes the loader, contributes
|
||||
its ordinary package action and import closure, and fails in checker entry.
|
||||
A visible literal named `_test.ww` still follows section 11.51: after its
|
||||
header and contiguous imports are valid, ordinary build omits it before body
|
||||
parsing or action construction, including when the declared name is `_`.
|
||||
`ww run` retains its earlier MainOnly boundary: a blank root is not `main`,
|
||||
so a successfully loaded root is rejected before any producer or compiler.
|
||||
- **Test:** an all-blank production, internal-test, or honest test-only family
|
||||
reaches its applicable test-package compiler action and fails there. A valid
|
||||
production `p` plus blank test `_`, or blank production `_` plus unrelated
|
||||
`p`/`p_test`, remains a coordinator family mismatch before tools. Existing
|
||||
raw/directory `FAIL` placement, compile-only empty stdout, and directory
|
||||
`-S` CLI-shape diagnostics are unchanged; no failed blank product runs.
|
||||
- **Package:** `_` is retained only as a declared source-family observation.
|
||||
It is not canonical identity. In an all-blank selected action, the checker
|
||||
emits one positioned BlankPkgName diagnostic per retained source marker in
|
||||
deterministic source-section order and continues later checking. Mixed
|
||||
declared names retain loader conflict precedence.
|
||||
- **Import:** a valid contiguous import in a blank source is a normal source
|
||||
occurrence and graph edge. Missing or invalid recursive dependencies can
|
||||
therefore fail before the parent checker. An ordinary blank source provider
|
||||
cannot publish a successful interface or archive. A reached hand-authored or
|
||||
corrupted `.wwi` that declares `_` is nevertheless parsed and defensively
|
||||
rejected by the consuming compiler; an unused interface is inert. Default,
|
||||
explicit, and blank aliases cannot mask the invalid provider name.
|
||||
Visibility, vendor, cycle, and initialization rules do not change.
|
||||
|
||||
The complete observable phase order is: source eligibility and loader-visible
|
||||
header/family checks; recursive import loading; MainOnly rejection for `run`;
|
||||
eligible dependency producers for build/test or a run root that passed
|
||||
MainOnly; the parent compiler's complete-file syntax; BlankPkgName checking;
|
||||
reached imported-package validation; later checker diagnostics; then existing
|
||||
driver/coordinator failure trailers.
|
||||
Consequently malformed contiguous imports precede graph construction, a
|
||||
missing dependency can suppress both a later body syntax error and
|
||||
BlankPkgName, and full-file syntax suppresses checker diagnostics. A blank run
|
||||
root never starts even valid dependency producers because MainOnly is earlier.
|
||||
|
||||
#### Test graph, actions, and identity boundaries
|
||||
|
||||
A production-only blank package under `ww test` has one ordinary production
|
||||
compiler action. Production `_` plus a same-package `_test.ww` also declared
|
||||
`_` forms one internal-test family: its augmented action owns both source sets,
|
||||
and `sep_recompile_for_test` substitutes it throughout the product closure, so
|
||||
the separate production node is not independently compiled for that product.
|
||||
One compiler invocation reports one BlankPkgName per retained marker. A
|
||||
test-only blank `_test.ww` forms one test-only internal action and reports once.
|
||||
A blank production plus the actually related external name `__test` passes
|
||||
family classification, but its blank production dependency fails before the
|
||||
external action, generated main, link, or runtime can complete.
|
||||
|
||||
Direct raw files retain `__root.*`; dotted directories and providers retain
|
||||
their canonical dotted package/import/action/artifact identities; production,
|
||||
internal, external, recompiled, support, and generated-main actions retain
|
||||
their existing distinctions. Physical paths, parents, source spellings, and
|
||||
symlink targets remain loader or diagnostic observations. No successful
|
||||
ordinary producer `.wwi` can advertise `_`; a supplied or corrupted `.wwi`
|
||||
that does is invalid input, not an alternate symbol, publication, or
|
||||
persistence identity.
|
||||
|
||||
#### Imported `.wwi` validation, reachability, and recovery
|
||||
|
||||
The rules in this subsection are **behavior derived from the pinned
|
||||
implementation** for WW's supported source-like export-data channel. They do
|
||||
not claim an official imported-blank fixture that does not exist.
|
||||
|
||||
Every sorted `--import CANONICAL FILE.wwi` is first read, owner-checked, and
|
||||
syntax-parsed into its own standalone AST. Interface read, owner, syntax, and
|
||||
structural import-map errors keep their existing precedence. The compiler then
|
||||
syntax-parses the primary input. Any primary syntax error returns before
|
||||
imported-package semantic validation, so it is never accompanied by the
|
||||
broken-import diagnostic.
|
||||
|
||||
After successful primary parsing and import-map application, compiler test
|
||||
mode materializes any required support `N_USE` before resolution. The node has
|
||||
the primary owner/source ID, is marked used, uses visible name `test` or the
|
||||
collision-safe reserved `__wwtest`, and is positioned at the generated primary
|
||||
root because no source path token exists. An existing equivalent primary
|
||||
occurrence prevents duplication. When no support interface is supplied, the
|
||||
node retains the established raw external-support fallback; a supplied
|
||||
blank-named support interface is validated like every source import. Reserved
|
||||
`__wwtest` preserves its compiler-selected visible spelling after valid
|
||||
resolution but cannot skip provider-name validation. Existing
|
||||
`--test-target-package` roots already require a primary occurrence and add no
|
||||
second node.
|
||||
|
||||
A metadata-only pass classifies each represented canonical package as valid,
|
||||
missing, conflicting, or invalid; invalid means its one nonconflicting real
|
||||
declared name is exactly `_`. Compiler-private placeholder packages remain
|
||||
valid recovery metadata. Reachability is seeded only by canonical primary and
|
||||
compiler-required `N_USE.usepath` occurrences, then reaches a fixed point over
|
||||
standalone interface lists. An imported use contributes an edge only when its
|
||||
owning canonical package is already reached and valid. Interface containers,
|
||||
arbitrary embedded origins, and invalid, missing, conflicting, or unreachable
|
||||
owners are never roots or traversal sources.
|
||||
|
||||
Before binding or concatenation, each standalone list is filtered to nodes
|
||||
whose canonical owner is both reached and valid. Invalid-owner, unreachable,
|
||||
and ownerless hand-authored facts are discarded. Thus an unused invalid
|
||||
interface is wholly inert even when it contains an embedded valid-origin
|
||||
section that imports the invalid path: it emits no diagnostic, installs no
|
||||
declaration or scope, contributes no output or serialized fact, and leaves an
|
||||
otherwise valid primary byte-equivalent to the no-interface control. If the
|
||||
primary independently reaches that valid origin, its retained import can then
|
||||
reach and diagnose the invalid provider. Binding runs on those filtered lists
|
||||
and the primary list before the lists are concatenated, so unreachable
|
||||
internal uses cannot manufacture missing, conflict, or invalid effects.
|
||||
|
||||
Every retained occurrence resolving to an invalid provider is marked used and
|
||||
records declared provider name `_`. A nonblank occurrence receives a recovery
|
||||
package binding using its explicit alias or, by default, the final component of
|
||||
the canonical dotted path; a blank occurrence installs no visible binding.
|
||||
The fake package has an empty scope. Qualified value, call, and type gateways
|
||||
therefore recover as the error type without missing-member,
|
||||
unknown-type/export, or calling-nonfunction cascades, while a lexically closer
|
||||
value binding still shadows the recovery qualifier normally.
|
||||
|
||||
At checker entry, immediately after primary BlankPkgName diagnostics, the
|
||||
first retained invalid occurrence of each canonical path emits exactly
|
||||
`could not import PATH (invalid package name: "_")`; later occurrences of the
|
||||
same path are deduplicated, while distinct paths diagnose in retained
|
||||
occurrence order. Independent checker diagnostics continue afterward.
|
||||
Deduplication uses canonical dotted path because WW has no Go source-directory
|
||||
import-key component. Default, explicit, and blank alias forms all position
|
||||
this diagnostic at the path's first identifier, never at an explicit alias.
|
||||
The existing alias-or-path first-spec position remains unchanged for every
|
||||
other binding diagnostic. Full parsing, imports-only parsing, and named-source
|
||||
header parsing all retain both position families.
|
||||
|
||||
Public persistent build and test actions consume the same supported interface
|
||||
channel. If a reached caller-owned committed `.wwi` is corrupted to declare
|
||||
`package _;`, the consumer compiler fails after primary syntax and resolution;
|
||||
that action's assembler and downstream archive, link, retention, or runtime do
|
||||
not complete. A package-action failure prevents generated main; a generated-main
|
||||
action that is itself the consumer performs the same validation before its own
|
||||
assembly. Raw, production, internal, external, test-only, generated-main, `-c`,
|
||||
and applicable `-S` consumer actions use the same rule. A same-named `.ww` file
|
||||
remains an import decoy rather than a provider. An
|
||||
unreferenced corrupt interface remains inert and does not invalidate or alter
|
||||
the consumer. A failing direct compiler returns status 1 with empty stdout;
|
||||
public test presentation retains its existing running `FAIL` and
|
||||
package-trailer rules, while compile-only and assembly-only forms retain empty
|
||||
stdout.
|
||||
|
||||
#### Artifacts, rollback, concurrency, parity, and formats
|
||||
|
||||
The failed primary blank action and a consumer rejecting a reached blank-named
|
||||
interface emit neither compiler assembly nor `.wwi`, so their downstream
|
||||
assembler, archiver, linker, test harness, and user runtime do not run. Valid
|
||||
dependencies or test support that precede either failure may execute their
|
||||
ordinary producers, but request rollback removes every request-owned stage and
|
||||
commits no failed generation, public product, retained test binary, unit,
|
||||
interface, assembly, object, archive, executable, stamp, or status. Direct
|
||||
named `-o`/`-I` outputs, public outputs, retained tests, and committed semantic
|
||||
bytes remain byte-identical. Restoring the exact valid source or `.wwi` bytes
|
||||
uses the existing content-identity reuse path; invalid bytes never publish a
|
||||
replacement consumer generation. Reached interface bytes already participate
|
||||
through the existing compiler input and invalidation rules; semantic validation
|
||||
adds no graph, action, or persistence key. A build-omitted named `_test.ww`
|
||||
contributes no action or invalidation key.
|
||||
|
||||
Blank-package state, imported metadata, reachability sets, deduplication, and
|
||||
fake bindings are compiler/checker-process-local. Independent concurrent
|
||||
requests cannot share diagnostics, graph state, staging, or cleanup. Normal
|
||||
failure is waited and rolled back through the existing transaction owner and
|
||||
leaves no anonymous descriptor, `.new`, `.old`, `.install`, `.wwtxn.*`,
|
||||
capture, result, request scratch, or child.
|
||||
Direct `w6c` and `w6c_ww`, and public `ww` and `ww_ww`, agree on status,
|
||||
stdout, exact path-token positions and diagnostic order, fake recovery,
|
||||
output absence, prior-byte preservation, and every comparable semantic
|
||||
dependency artifact. Producer provenance remains the established intentional
|
||||
stage difference.
|
||||
|
||||
No signal-supervision behavior changed. Direct external `SIGTERM` during a
|
||||
blocked persistent compilation still preserves prior committed/public bytes
|
||||
but can leave the spawned compiler and fixed-name `.new` staging that poisons a
|
||||
later request. That independently verified gap remains open and is not claimed
|
||||
fixed by normal BlankPkgName rollback.
|
||||
|
||||
No serialized representation changed. The full parser changes only the
|
||||
in-memory position of a blank package marker to the underscore token; outer
|
||||
file/header/import-only markers and valid package markers keep their former
|
||||
positions. Each twin's private in-memory `Node` gains only
|
||||
`usepathfile/usepathline/usepathcol`; AST enum values, AST printing, `.wwi`
|
||||
schema, build workdir format `18`, test workdir format `19`, and semantic
|
||||
storage format `3` remain unchanged. No cache, result record, manifest, action
|
||||
descriptor, transaction marker, database, or lock is added. This closes one
|
||||
coherent semantic slice across all four axes;
|
||||
it does not complete the remaining suffix-first run front, multiple named
|
||||
source packages, shared test-process state and failure topology, RE2-compatible
|
||||
flat `-run`, finite special-source handling, or external-driver interruption
|
||||
recovery.
|
||||
|
||||
## 12. Candidate architectures and hard-gate decision
|
||||
|
||||
Five candidates were developed as coherent systems, not as feature bins.
|
||||
|
||||
106
docs/spec.md
106
docs/spec.md
@@ -273,7 +273,8 @@ does not return (e.g. a call to `abort`).
|
||||
|
||||
```
|
||||
SourceFile = PackageClause { ImportDecl } { TopDecl } .
|
||||
PackageClause = "package" ident ";" .
|
||||
PackageClause = "package" PackageName ";" .
|
||||
PackageName = ident .
|
||||
ImportDecl = "import" ( ImportPath | ImportName ImportPath ) ";" .
|
||||
ImportName = ident .
|
||||
ImportPath = ident { "." ident } .
|
||||
@@ -285,6 +286,101 @@ ImportPath = ident { "." ident } .
|
||||
use the related `p_test`, and the actions remain separate even though one
|
||||
canonical directory owns their test product. The declared name need not equal
|
||||
the directory name or the final component of its canonical import identity.
|
||||
- The discard identifier `_` is syntactically valid as `PackageName`, but it
|
||||
is never a valid declared package name. A complete source with
|
||||
`package _;` reaches checker initialization, which reports exactly
|
||||
`invalid package name _` at the underscore token and continues checking the
|
||||
retained file. The package-clause parser admits the discard token only in
|
||||
this grammar slot; no other identifier position is broadened. A malformed or
|
||||
missing package name remains a parser error, and any complete-file syntax
|
||||
error prevents this checker diagnostic.
|
||||
|
||||
Loading may retain `_` transiently to compare declared source families,
|
||||
record imports, and construct the applicable action, but it is not canonical
|
||||
package, import, graph, action, symbol, `.wwi`, artifact, publication, or
|
||||
persistence identity. Direct sources retain `__root`; dotted directories
|
||||
and providers retain their dotted identities. Selected files with distinct
|
||||
declared names remain a loader/family conflict. In an all-blank action the
|
||||
checker emits one blank-name diagnostic per retained package marker in
|
||||
deterministic source order.
|
||||
|
||||
Observable ordering is source eligibility and loader-visible header/family
|
||||
validation, recursive import loading, the `ww run` main-package check,
|
||||
eligible dependency producers, complete parent-source parsing, then the
|
||||
blank-name, reached imported-package, and later checker diagnostics. Thus
|
||||
missing or invalid imports may precede the parent check; a blank run root is
|
||||
not `main` and starts no producer; and a full-source syntax error suppresses
|
||||
the blank-name error. An
|
||||
ordinary blank source provider cannot publish an interface or archive for an
|
||||
importer. A supplied or caller-corrupted `.wwi` can nevertheless contain
|
||||
that spelling and is defensively validated when reached.
|
||||
|
||||
Import interfaces are read, owner-checked, and syntax-parsed as separate
|
||||
lists before the primary source is parsed. Interface structural errors keep
|
||||
their existing precedence, but a primary syntax error returns before
|
||||
imported-package semantic checking and therefore suppresses every
|
||||
blank-provider import diagnostic. After successful primary syntax, compiler
|
||||
test mode first materializes its required `test` or collision-safe
|
||||
`__wwtest` support occurrence unless an equivalent primary occurrence
|
||||
exists. With no matching interface that occurrence retains the external
|
||||
support fallback; with a matching interface its provider name is validated,
|
||||
and the reserved spelling does not bypass the check.
|
||||
|
||||
Each represented canonical interface package is classified as valid,
|
||||
missing, conflicting, or invalid, where invalid means one nonconflicting
|
||||
real declared name `_`. Imported-interface reachability is rooted only at
|
||||
canonical uses in the primary and compiler-required lists. A reached valid
|
||||
interface owner may contribute its imported uses transitively; an invalid,
|
||||
missing, conflicting, unreachable, or ownerless section may not. Before
|
||||
interface facts are bound or merged, every declaration and use whose owner
|
||||
is not both reached and valid is discarded. An unused invalid interface is
|
||||
therefore wholly inert, even when it embeds a valid-origin section that
|
||||
imports the invalid path: it emits no diagnostic, installs no scope or
|
||||
declaration, changes no output, and is byte-equivalent to supplying no such
|
||||
interface. If primary source separately reaches that valid origin, its
|
||||
retained edge may legitimately reach and diagnose the invalid provider.
|
||||
|
||||
A retained use of an invalid provider is marked used. A nonblank use receives
|
||||
a fake empty-scope package binding under its explicit alias or, without one,
|
||||
the canonical path leaf; a blank use creates no visible binding. This
|
||||
recovery prevents qualified values, calls, and types from producing
|
||||
missing-member, unknown-type, export, or calling-nonfunction cascades.
|
||||
Ordinary lexical shadowing of a nonblank recovery alias still applies.
|
||||
|
||||
Immediately after primary blank-name diagnostics, the first retained use of
|
||||
each invalid canonical path reports exactly
|
||||
`could not import PATH (invalid package name: "_")`; later uses of that path
|
||||
are deduplicated, distinct paths retain occurrence order, and independent
|
||||
checker errors continue. Default, explicit, and blank import forms all
|
||||
position this error at the path's first identifier rather than at the alias.
|
||||
Canonical path, source spelling, alias, declared provider name, owner marker,
|
||||
placeholder, edge, and binding remain separate facts. A physical `.wwi`
|
||||
path is observation metadata and a same-named `.ww` file remains an import
|
||||
decoy.
|
||||
|
||||
Ordinary `ww build` still omits a valid visible literal `*_test.ww` after
|
||||
header loading, so `package _;` in that omitted role has no action or
|
||||
diagnostic. Under `ww test`, production plus a same-package blank test forms
|
||||
one augmented internal-test action; the test recompile substitutes for the
|
||||
separate production node and one compiler invocation diagnoses every
|
||||
retained blank marker. A test-only blank source has one test-package action.
|
||||
Mixed valid/blank production and test names retain family-mismatch
|
||||
precedence, and no failed blank product reaches generated main, link, or
|
||||
runtime.
|
||||
|
||||
Normal blank-package failure publishes no assembly, interface, object,
|
||||
archive, executable, retained test, or new semantic generation. Existing
|
||||
request rollback removes owned stages and preserves prior public and
|
||||
committed bytes; a public build or test consuming a reached corrupted
|
||||
committed interface likewise publishes no replacement consumer generation,
|
||||
retained test, or downstream artifact. Exact valid-interface restoration
|
||||
follows ordinary reuse. Independent requests share no blank-name,
|
||||
reachability, deduplication, or fake-binding state. Cstage and WWstage have
|
||||
the same path-positioned diagnostic stream and artifact outcome. The private
|
||||
in-memory AST adds only path-position fields; AST enum/printing, `.wwi`
|
||||
schema, build workdir format 18, test workdir format 19, and semantic storage
|
||||
format 3 do not change. External driver interruption is unchanged; the fixed
|
||||
`.new` residue and later persistent request poisoning remain open.
|
||||
- Each source file has one contiguous import section immediately after its
|
||||
package clause. Once a non-import top-level declaration begins, a later
|
||||
`import` is rejected as `imports must appear before other declarations`.
|
||||
@@ -643,10 +739,10 @@ ImportPath = ident { "." ident } .
|
||||
interruption preserve existing directory contents and remove only
|
||||
request-created prefixes and stages. Direct external `SIGTERM` of a build
|
||||
driver is a verified-open exception: both stages preserve public and
|
||||
committed work bytes and reap their process group, but may leave `.new`
|
||||
staging files that make a later persistent-work request reject until those
|
||||
files are removed. A non-directory output retains the single-product
|
||||
file/archive rule.
|
||||
committed work bytes, but leave the directly spawned compiler alive and
|
||||
exactly three fixed-name `.new` staging files; the existing `.unit.new`
|
||||
makes a later persistent-work request reject. A non-directory output retains
|
||||
the single-product file/archive rule.
|
||||
If a lone
|
||||
command's synthesized default basename already names a directory, loading
|
||||
and graph validation complete and the build rejects before tools without
|
||||
|
||||
@@ -339,6 +339,146 @@ Build workdir format remains 18, test workdir format remains 19, and semantic
|
||||
storage format remains 3; no test-result cache, schema, action descriptor,
|
||||
transaction marker, or lock is introduced.
|
||||
|
||||
The blank declared package name has a different contract from documentation
|
||||
suppression. The sole authority is official Go 1.26.5 at commit
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- **behavior directly implemented or asserted by pinned Go** — the compiler
|
||||
scanner admits and dispatches `_` through its name path
|
||||
(`cmd/compile/internal/syntax/scanner.go:88–107,368–394,437–439`), the parser
|
||||
accepts it in package syntax (`parser.go:397–420,2751–2763`), and types2
|
||||
rejects the retained node as `invalid package name _`
|
||||
(`cmd/compile/internal/types2/check.go:336–355`).
|
||||
- **behavior directly implemented or asserted by pinned Go** — official
|
||||
`test/blank1.go:1–31` asserts the blank-name error and later checker errors,
|
||||
proving continuation. `internal/types/testdata/check/blank.go:1–5` asserts
|
||||
only the blank-name error. `cmd/go/testdata/script/build_test_only.txt:1–18`
|
||||
and `build_no_go.txt:1–30` are surrounding source-role controls.
|
||||
- The official tree contains no cmd/go blank-name matrix for named, multiple,
|
||||
mixed, imported, test-only, action, artifact, rollback, concurrency, or
|
||||
interruption cases; the focused WW package observer owns those proofs.
|
||||
- **behavior directly implemented or asserted by pinned Go** — types2
|
||||
validates an importer-supplied package object before applying its local
|
||||
alias. Provider name `_` emits
|
||||
`could not import PATH (invalid package name: "_")` at the source import
|
||||
path, caches a path-leaf-named fake package, marks the use, and continues
|
||||
(`cmd/compile/internal/types2/resolver.go:125–180,248–335`; public twin
|
||||
`go/types/resolver.go:157–190,263–350`). An empty provider name quotes the
|
||||
actual empty value instead.
|
||||
- No official pinned test directly supplies an imported `Package` named `_`.
|
||||
**behavior derived from the pinned implementation** — the
|
||||
imported-interface rows are WW-native proof of applying those resolver
|
||||
semantics to WW's supported source-like interface channel.
|
||||
|
||||
The slice is not owned only by the four primary parser/checker files. The two
|
||||
`w6c` command fronts own test-support materialization, imported-package
|
||||
metadata, reachability/filtering, fake qualifier assignment, and delayed AST
|
||||
concatenation; the checker twins own deduplicated diagnostics and empty-scope
|
||||
fake recovery; the AST/parser twins own the independent path-token position.
|
||||
The package coordinator and public drivers exercise the same interface channel
|
||||
without redefining package or action identity.
|
||||
|
||||
The coordinator treats `_` as a syntactically loaded declared name, not a
|
||||
generic missing-clause error. A production-only blank package under `ww test`
|
||||
selects its one ordinary production compiler action and fails there. Blank
|
||||
production plus a same-package blank `_test.ww` selects one augmented internal
|
||||
test action containing both source sets. `sep_recompile_for_test` substitutes
|
||||
that action for the separate production node throughout the product closure,
|
||||
so it is compiled once and emits one `invalid package name _` per retained
|
||||
source marker in deterministic unit order. A test-only blank `_test.ww` forms
|
||||
one test-only internal action and reports once. Valid production `p` plus blank
|
||||
test `_`, or blank production `_` plus an unrelated `p` or `p_test`, keeps the
|
||||
existing family-mismatch rejection before tools. Blank production plus the
|
||||
actually related external name `__test` passes family classification, but the
|
||||
production dependency fails before the external action, support/generated
|
||||
main, link, or runtime completes.
|
||||
|
||||
The observable test phase order is selected-source validation and package/test
|
||||
family classification, recursive import loading, eligible dependency and
|
||||
support producers, complete parent-source parsing, blank-name checking,
|
||||
imported-package validation, later checker diagnostics, and the
|
||||
existing package failure trailer. A missing or invalid dependency may
|
||||
therefore suppress both a later body syntax diagnostic and BlankPkgName; a
|
||||
complete-file syntax error suppresses checker diagnostics.
|
||||
Raw and directory running requests keep their established command-owned
|
||||
`FAIL\n` placement, while `-c` and applicable `-S` paths retain empty stdout.
|
||||
Directory `-S` option-shape errors remain earlier than source selection. No
|
||||
blank product begins a test or user runtime.
|
||||
|
||||
The imported-interface observer uses the supported repeatable
|
||||
`w6c -c --import PATH FILE.wwi` channel and its public persistent build/test
|
||||
equivalent. Each compiler first read/owner/syntax-checks sorted standalone
|
||||
interfaces, then parses primary source. Primary syntax failure precedes
|
||||
imported-package semantic validation. After successful primary syntax, `-T`
|
||||
materializes a missing compiler-required `test` or collision-safe `__wwtest`
|
||||
use in the primary list before resolution. It is marked used and rooted at the
|
||||
generated primary file position. With no matching import it keeps the existing
|
||||
external-support fallback; with a matching blank-named interface it receives
|
||||
the ordinary invalid-provider diagnostic. Existing explicit test-target roots
|
||||
already have a primary occurrence and are not duplicated.
|
||||
|
||||
The observer requires metadata classification as valid, missing, conflicting,
|
||||
or invalid, followed by reachability seeded solely by canonical primary and
|
||||
compiler-required uses. Only a reached valid interface owner may contribute
|
||||
transitive imports. Before binding and delayed concatenation, invalid-owner,
|
||||
unreachable, and ownerless standalone facts are removed. The unused-interface
|
||||
control includes a mixed-origin invalid interface whose embedded valid origin
|
||||
imports the bad path: because that origin is not independently rooted, the
|
||||
whole interface is inert and the primary outputs equal the no-interface
|
||||
control. A companion primary-reached origin proves that legitimate traversal
|
||||
does reach and diagnose the bad provider.
|
||||
|
||||
For every retained bad use, default, explicit, and blank aliases all validate
|
||||
the provider name. Nonblank uses receive an explicit-alias or canonical-path-
|
||||
leaf fake binding with empty scope; blank uses install none. All are marked
|
||||
used. Qualified value/call/type recovery produces no missing-member,
|
||||
unknown-type, export, or calling-nonfunction cascade, while lexical shadowing
|
||||
still applies. One canonical bad path emits one diagnostic despite repeated
|
||||
occurrences; two paths emit one each in retained order, and an independent
|
||||
checker diagnostic follows. Every source-created form points at the path's
|
||||
first identifier, not the explicit alias. The compiler-generated support use
|
||||
uses its generated root position because no path token exists.
|
||||
|
||||
Public proof corrupts a caller-owned committed provider `.wwi`, then exercises
|
||||
build and test consumers through the existing canonical interface action.
|
||||
Reached corruption fails the affected compiler action before its assembler and
|
||||
downstream archive, link, retention, or runtime. A package-action failure
|
||||
prevents generated main; a generated-main action that is itself the consumer
|
||||
performs the same validation before its assembly. A same-named `.ww` file is
|
||||
still an import decoy. Raw, production, internal, external, test-only,
|
||||
generated-main, `-c`, and applicable `-S` shapes share the same validation.
|
||||
Prior public, retained, and semantic bytes survive, invalid bytes cannot commit
|
||||
a replacement consumer, and restoring valid interface bytes follows ordinary
|
||||
reuse. An unreferenced corrupt interface remains inert and causes no
|
||||
invalidation.
|
||||
|
||||
The package-name token does not alter production/internal/external/recompiled,
|
||||
support, or generated-main identities. Direct actions retain `__root`, dotted
|
||||
actions retain dotted identity, and no successful ordinary producer interface
|
||||
can advertise a blank provider. A supplied or corrupted interface that does is
|
||||
invalid consumer input. A failed primary blank action or reached invalid
|
||||
interface consumer emits no assembly or interface, so its assembler, archiver,
|
||||
linker, generated main, harness, and runtime do not run; earlier valid
|
||||
dependency/support producers may run normally. Request rollback removes owned
|
||||
stages and commits no failed unit, interface, assembly, object, archive, binary,
|
||||
status, retained output, or tool stamp. Warm prior public and semantic bytes
|
||||
remain unchanged, exact source/interface restoration uses ordinary reuse, and
|
||||
concurrent requests keep parser/checker reachability, deduplication, fake
|
||||
bindings, and cleanup independent.
|
||||
|
||||
Direct `w6c`/`w6c_ww` and public `ww`/`ww_ww` are required to agree on status,
|
||||
stdout, exact path-token positions and diagnostic order, fake recovery, output
|
||||
absence, and prior-byte preservation for the full role/import matrix. The
|
||||
syntax/check change adds no test-process topology, test-result cache, schema,
|
||||
action descriptor, or stored identity. Private in-memory `N_USE` nodes gain
|
||||
only path-position fields; AST enum/printing and `.wwi` serialization are
|
||||
unchanged. Build workdir format remains 18, test workdir format remains 19, and
|
||||
semantic storage format remains 3. Normal checker failure leaves no anonymous
|
||||
descriptor, adjacent stage, request residue, or child. External-driver SIGTERM
|
||||
supervision is unchanged: the known orphan compiler, fixed `.new` staging, and
|
||||
later persistent-request poisoning remain open and are not credited to this
|
||||
slice.
|
||||
|
||||
An existing local directory whose requested build basename ends `.ww`
|
||||
(including a visible `_test.ww` symlink to a directory) remains a directory
|
||||
package, not a raw named test source. WWstage `ww build` now uses the same
|
||||
@@ -1144,8 +1284,15 @@ timeout policy in this architecture.
|
||||
|
||||
## Open driver work
|
||||
|
||||
None; directory-package `-c` and `-o` now have the applicable Go 1.26.5
|
||||
retention, naming, fan-out, execution, and publication behavior.
|
||||
Directory-package `-c` and `-o` have the applicable Go 1.26.5 retention,
|
||||
naming, fan-out, execution, and publication behavior. Direct external SIGTERM
|
||||
of either driver during blocked persistent compilation remains open: prior
|
||||
public and committed semantic bytes survive, but the directly spawned compiler
|
||||
can survive with three fixed-name `.new` stages, and a later persistent request
|
||||
then rejects the existing `.unit.new`. The required repair is driver-owned
|
||||
child-process-group supervision and normal request rollback before re-raising
|
||||
the original signal; blind removal of `.new` files cannot distinguish foreign
|
||||
or concurrent stages.
|
||||
|
||||
## Validation policy
|
||||
|
||||
|
||||
Reference in New Issue
Block a user