compiler: implement blank package name semantics

This commit is contained in:
2026-08-23 15:33:59 +09:00
parent e67b8e1bc4
commit 0b24b11d65
14 changed files with 2862 additions and 112 deletions

View File

@@ -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:88107,368394,437439`), the parser
accepts it in package syntax (`parser.go:397420,27512763`), and types2
rejects the retained node as `invalid package name _`
(`cmd/compile/internal/types2/check.go:336355`).
- **behavior directly implemented or asserted by pinned Go** — official
`test/blank1.go:131` asserts the blank-name error and later checker errors,
proving continuation. `internal/types/testdata/check/blank.go:15` asserts
only the blank-name error. `cmd/go/testdata/script/build_test_only.txt:118`
and `build_no_go.txt:130` 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:125180,248335`; public twin
`go/types/resolver.go:157190,263350`). 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