ww imports: require imports before declarations
This commit is contained in:
@@ -8246,6 +8246,187 @@ this presentation rule does not change.
|
||||
No persisted-byte contract changed. Build workdir format remains `18`, test
|
||||
workdir format remains `19`, and semantic storage format remains `3`.
|
||||
|
||||
### 11.41 Implemented source-file import-section ordering
|
||||
|
||||
Every eligible WW source now has one contiguous import section immediately
|
||||
after its package clause. Once an ordinary top-level declaration begins, the
|
||||
first `import` in a later section is rejected as
|
||||
`imports must appear before other declarations`. The parser continues for
|
||||
recovery: consecutive imports in that late section do not repeat the ordering
|
||||
diagnostic, while another ordinary declaration followed by another import
|
||||
starts a separately diagnosed late section.
|
||||
|
||||
This is a source-file syntax rule, not a new import form. Existing unquoted
|
||||
dotted default, explicit-alias, and blank imports are unchanged. Existing
|
||||
aggregate module/reset boundaries and each constituent package clause begin a
|
||||
new source section. The boundary bookkeeping remains parser metadata rather
|
||||
than package, import, graph, action, artifact, symbol, `.wwi`, publication, or
|
||||
persistence identity.
|
||||
|
||||
#### Pinned Go evidence and fact classification
|
||||
|
||||
The sole authority is official Go 1.26.5 at commit
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- `syntax.(*parser).fileOrNil` states the source-file grammar as a package
|
||||
clause, zero or more imports, and then zero or more top-level declarations.
|
||||
Its recovery loop accepts a later import only to continue parsing and emits
|
||||
exactly `imports must appear before other declarations` when the preceding
|
||||
declaration was not an import
|
||||
([`cmd/compile/internal/syntax/parser.go`, lines 397–428](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/parser.go#L397-L428)).
|
||||
- The public parser first consumes the initial import section, then applies the
|
||||
same predecessor check while parsing the rest of the file
|
||||
([`go/parser/parser.go`, method `(*parser).parseFile`, lines 2887–2923](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2887-L2923)).
|
||||
- Official types testdata requires one diagnostic for a late import followed by
|
||||
contiguous imports, then another diagnostic when an ordinary declaration
|
||||
separates a second late section
|
||||
([`internal/types/testdata/fixedbugs/issue43190.go`, lines 5–30](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/fixedbugs/issue43190.go#L5-L30)).
|
||||
|
||||
Those grammar branches, diagnostic text, error-recovery behavior, and testdata
|
||||
assertions are **behavior directly implemented or asserted by pinned Go**.
|
||||
That the state belongs to one source parser, resets at WW's existing aggregate
|
||||
source boundaries, and must reject before import-graph construction is
|
||||
**behavior derived from the pinned implementation**.
|
||||
|
||||
The rule honestly applies to WW's model because it orders declaration classes
|
||||
WW already implements. It requires no quoted, grouped, dot, or generalized
|
||||
import syntax; module or manifest identity; registry, lock, cache, database,
|
||||
CAS, or network resolution; or source-level build expression.
|
||||
|
||||
#### Fresh four-axis audit and direct pre-fix measurements
|
||||
|
||||
The bounded audit examined all four permanent axes against the pinned checkout
|
||||
before selecting this import difference:
|
||||
|
||||
- **Go-like build:** pinned linker method
|
||||
`(*ErrorReporter).errorUnresolved` gives unresolved `main.main` a dedicated
|
||||
error
|
||||
([`cmd/link/internal/ld/errors.go`, lines 29–67](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L29-L67)),
|
||||
asserted by `TestUndefinedRelocErrors` and its source fixture
|
||||
([`cmd/link/internal/ld/ld_test.go`, lines 19–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L19-L45),
|
||||
[`testdata/issue10978/main.go`, lines 5–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/testdata/issue10978/main.go#L5-L27)).
|
||||
Both WW stages rejected a selected declared-`main` package without an entry,
|
||||
using empty stdout and the same linker/driver diagnostics. This applicable
|
||||
control was aligned.
|
||||
- **Go-like test:** pinned `testFlags` explicitly permits known test flags
|
||||
before and after the package list and implements the transition between
|
||||
package operands and flags
|
||||
([`cmd/go/internal/test/testflag.go`, lines 219–345](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L219-L345));
|
||||
official `test_flag.txt` asserts both placements
|
||||
([lines 1–4](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_flag.txt#L1-L4)).
|
||||
In both WW stages, `-run selected` before or after a directory operand ran
|
||||
exactly the same one of two registered tests and produced identical output.
|
||||
This applicable control was aligned for WW's supported option set.
|
||||
- **Go-like package:** pinned `MultiplePackageError` and directory scanning
|
||||
reject two eligible declarations with different package names
|
||||
([`go/build/build.go`, lines 538–549](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L549)
|
||||
and [lines 939–967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L967)),
|
||||
asserted by `TestMultiplePackageImport`
|
||||
([`go/build/build_test.go`, lines 105–133](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L133)).
|
||||
Both WW stages rejected a `first`/`second` directory before tools with the
|
||||
identical positioned diagnostic. This applicable control was aligned.
|
||||
- **Go-like import:** a command source declared a helper, then imported
|
||||
`audit.dep`, then used that package from `main`. Both WW stages exited 0,
|
||||
emitted empty build output, produced byte-identical executables (SHA-256
|
||||
`f28892147ab0ae283dff5ceea7114dbc81142ed48cb9088ee7fb8294a5ce44cd`),
|
||||
and those executables exited 42. Corresponding owner unit, interface,
|
||||
assembly, object, archive, and initializer bytes were stage-identical. A
|
||||
same-package test source with the same late-import shape ran successfully in
|
||||
both stages with identical 251-byte stdout (SHA-256
|
||||
`3c42fa9840f485fb21b5b5318a13b89abfe29e94b530db00779262368f4fbeba`)
|
||||
and empty stderr. This acceptance was the selected difference.
|
||||
|
||||
The WW statuses, streams, runtime exits, and artifact hashes are **directly
|
||||
measured WW behavior**. The cited implementation and testdata facts are
|
||||
**behavior directly implemented or asserted by pinned Go**. Applying their
|
||||
per-file ordering state to WW's existing dotted declarations is **behavior
|
||||
derived from the pinned implementation**.
|
||||
|
||||
#### Ownership and final four-axis behavior
|
||||
|
||||
`parseimports` and `parsefile` in `cmd/wcc/parse.c`, with their semantic twins
|
||||
in `lib/ww/syntax/parse.ww`, are the only production owners. Each keeps one
|
||||
parser-local `previmport` bit. A normal import following a non-import reports
|
||||
the pinned diagnostic, then sets the bit so adjacent imports remain one
|
||||
recovery section. Any ordinary declaration clears it. The existing
|
||||
module-path, module-reset, and package-clause boundaries set it for a new
|
||||
source section.
|
||||
|
||||
The imports-only pass is used by public driver loading and therefore rejects a
|
||||
selected or imported late source before graph and producer construction. The
|
||||
full parser independently gives direct `w6c`/`w6c_ww` input and aggregate units
|
||||
the same rule. The only tracked compatibility fixture that deliberately put a
|
||||
declaration before its import was reordered; it still proves file-scoped import
|
||||
binding and declaration installation order with byte-identical Cstage/WWstage
|
||||
artifacts, without asserting the rejected syntax.
|
||||
|
||||
- **Go-like build:** selected and imported late sources now fail during parser
|
||||
loading, before compiler, assembler, archiver, linker, output planning side
|
||||
effects, or runtime. Missing-target resolution does not replace the earlier
|
||||
syntax error. Valid import-first commands still build, publish, and run.
|
||||
- **Go-like test:** late imports in production, same-package test,
|
||||
external-test, and test-only sources fail before variant actions, generated
|
||||
main, test binary, runtime, accounting, or retained publication. The
|
||||
directory command emits its existing attributable final `FAIL\n`. A valid
|
||||
import-first test retains and runs normally.
|
||||
- **Go-like package:** source eligibility and package-clause classification
|
||||
remain earlier owners. Wrong-platform sources produce no ordering error;
|
||||
selected package-name conflicts retain their coordinator diagnostic.
|
||||
Declared names and command/test family classification are unchanged.
|
||||
- **Go-like import:** a file can no longer introduce a qualifier or side-effect
|
||||
edge after ordinary declarations. Valid imports retain their exact source
|
||||
spelling, declared-name qualifier, file scope, contextual/vendor resolution,
|
||||
canonical identity, visibility checks, cycle checks, and initialization
|
||||
edges.
|
||||
|
||||
Direct post-fix `w6c` and `w6c_ww`, and public `ww build`/`ww_ww build`, reject
|
||||
the measured source with empty stdout and byte-identical 149-byte stderr
|
||||
(SHA-256
|
||||
`791ac87ab0aa2c91228f863ae80a8815aa83edf78c4996c5f11191193e3e4240`).
|
||||
The diagnostic points to the late import at line 7, column 1. Directory tests
|
||||
emit byte-identical `FAIL\n` stdout (SHA-256
|
||||
`4f8e9e45f8a9e1843b81eaf3bdf52a6b778d415d23bf985774a9d34a43f69bd5`)
|
||||
and byte-identical 314-byte stderr (SHA-256
|
||||
`82ec52b26eaff053f475ce0773b7aee902e734cd87dc100848aee3772063f5b1`),
|
||||
with no test body or accounting. A direct three-import recovery probe emits
|
||||
exactly two stage-identical ordering diagnostics: one for the first of two
|
||||
contiguous late imports and one after the intervening declaration.
|
||||
|
||||
Loading and fixed-target filename selection otherwise do not change. An
|
||||
excluded `_windows.ww` or `_windows_test.ww` file contributes no parse,
|
||||
package, import, graph, action, artifact, diagnostic, or invalidation state.
|
||||
For valid files, graph nodes, action dependencies and scheduling, compiler and
|
||||
linker arguments, initialization, runtime behavior, result ordering, and
|
||||
publication remain unchanged. A package canonically named `domain.dep` may
|
||||
still declare `renamed`; its importer uses `renamed.Name`, and its unit/export
|
||||
remain owned by `domain.dep`.
|
||||
|
||||
Cold rejection creates no work artifact, output, capture, or adjacent scratch.
|
||||
A warm source reordered into the invalid form preserves the complete committed
|
||||
unit/interface/assembly/object/archive/initializer generation, tool vouchers,
|
||||
stamp, and public executable byte for byte. Exact restoration reuses the
|
||||
committed producers and republishes the same executable. Because rejection
|
||||
occurs before a producer or test child, producer failure, runtime failure,
|
||||
signals, timeout, interruption, and process-group cleanup acquire no new path;
|
||||
their existing owners remain authoritative. Concurrent valid and invalid
|
||||
requests use independent parser state, workdirs, captures, and outputs. No
|
||||
`.new`, `.install`, `.wwtxn.*`, cold scratch, test process, or capture residue
|
||||
survives the observed failure boundaries.
|
||||
|
||||
The WW-native `imports_precede_other_top_level_declarations` observer proves
|
||||
direct compiler parity, exact recovery-section counts, selected and imported
|
||||
build rejection, syntax-before-resolution precedence, all directory test
|
||||
source variants, wrong-platform exclusion, valid runtime behavior, declared
|
||||
name versus canonical identity, cold/warm persistence and rollback, restored
|
||||
reuse, concurrent isolation, diagnostic equality, retained executable equality,
|
||||
and intermediate artifact-byte equality. The C parser unit and the existing
|
||||
`sepimport` observer separately pin the imports-only AST recovery and valid
|
||||
file-scoped binding regression.
|
||||
|
||||
Rejected source creates no persisted byte contract, while valid source bytes
|
||||
are unchanged. Build workdir format remains `18`, test workdir format remains
|
||||
`19`, and semantic storage format remains `3`.
|
||||
|
||||
## 12. Candidate architectures and hard-gate decision
|
||||
|
||||
Five candidates were developed as coherent systems, not as feature bins.
|
||||
|
||||
11
docs/spec.md
11
docs/spec.md
@@ -257,6 +257,17 @@ 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.
|
||||
- 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`.
|
||||
Parsing continues for recovery: consecutive imports in that late section
|
||||
produce one ordering diagnostic, while another ordinary declaration followed
|
||||
by another import starts a separately diagnosed late section. Existing
|
||||
aggregate module/reset boundaries and constituent package clauses reset this
|
||||
parser state per source; they do not relax the rule within a source or become
|
||||
package/import identity.
|
||||
A filename excluded by the target-selection rule below reaches no parser and
|
||||
therefore cannot contribute an ordering diagnostic or import edge.
|
||||
- Directory source eligibility uses Go 1.26.5 filename suffix semantics for
|
||||
WW's fixed `linux/amd64` target. In the basename stem before the first dot, a
|
||||
final `_test` token is ignored for platform matching. A final known OS or
|
||||
|
||||
@@ -402,6 +402,19 @@ directory entry order. A recursive pattern omits a directory with no eligible
|
||||
source, while an explicit wrong-target-only build rejects it as having no WW
|
||||
package source. There is no source-level build-expression or user-tag mode.
|
||||
|
||||
Within every eligible production, same-package test, external-test, or
|
||||
test-only source, the package clause is followed by one contiguous import
|
||||
section and then ordinary top-level declarations. A later import is a parser
|
||||
error, `imports must appear before other declarations`. The imports-only load
|
||||
pass diagnoses the first import in each separated late section before graph or
|
||||
producer construction; the full parser gives direct compiler input the same
|
||||
result. Consequently an invalid test source creates no variant, generated main,
|
||||
test binary, runtime process, accounting, retained output, or new persistent
|
||||
generation. The directory command retains its existing attributable final
|
||||
`FAIL\n`. Wrong-target files remain excluded before this rule and contribute no
|
||||
diagnostic. This ordering state is per source and never package, import,
|
||||
variant, action, artifact, publication, or persistence identity.
|
||||
|
||||
After that eligibility boundary and the coordinator's required package-clause
|
||||
classification and production `@test` validation parses, the delegated loader
|
||||
performs selected-basename Go 1.26.5 simple-fold preflight before its graph
|
||||
|
||||
Reference in New Issue
Block a user