test: prove package initialization semantics
This commit is contained in:
11
Makefile
11
Makefile
@@ -349,7 +349,7 @@ $(PACKAGE_TEST_BIN): $(PACKAGE_TEST_SRC) $(WWTEST_BIN) \
|
||||
test-package: $(PACKAGE_TEST_BIN) $(WWTEST_BIN) $(BIN)/ww $(BIN)/ww_ww \
|
||||
$(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6a_ww \
|
||||
$(BIN)/w6l $(BIN)/w6l_ww $(LIB)/libwwrt.a
|
||||
@WW_PACKAGE_REPO=$(CURDIR) $(CURDIR)/$(PACKAGE_TEST_BIN)
|
||||
@WW_PACKAGE_REPO=$(CURDIR) $(CURDIR)/$(PACKAGE_TEST_BIN) -timeout-ms=120000
|
||||
|
||||
# ---- directories -------------------------------------------------------
|
||||
$(BIN) $(LIB) $(OBJ)/wcc $(OBJ)/ww $(OBJ)/wwdump $(OBJ)/w6c $(OBJ)/w6a $(OBJ)/w6l $(OBJ)/rt:
|
||||
@@ -384,10 +384,17 @@ BYTEID_WW_TARGETS = $(BYTEID_WW_TESTS:%=wwtest/%)
|
||||
# export arguments, link rejects), NOT byteid suites: they run under
|
||||
# test-compiler beside the surviving residual carriers.
|
||||
SEP_WW_TESTS = test/sep/sepbuild_test.ww test/sep/sepimport_test.ww \
|
||||
test/sep/seplink_test.ww test/sep/sepscratch_test.ww \
|
||||
test/sep/seplink_test.ww test/sep/sepinit_test.ww \
|
||||
test/sep/sepscratch_test.ww \
|
||||
test/sep/septest_test.ww test/sep/m3sep_test.ww \
|
||||
test/sep/localbuild_test.ww test/sep/importdir_test.ww
|
||||
SEP_WW_TARGETS = $(SEP_WW_TESTS:%=wwtest/%)
|
||||
SEP_LIMITEXEC_BIN = $(BIN)/sep-limitexec
|
||||
|
||||
$(SEP_LIMITEXEC_BIN): test/sep/limitexec.c | $(BIN)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
wwtest/test/sep/sepinit_test.ww: $(SEP_LIMITEXEC_BIN)
|
||||
# Ww-native lib env/OS arranger observers: the env contracts of the
|
||||
# lib/os and lib/dirs suites (getenv cohorts, XDG cohorts, the dirs
|
||||
# too-long abort) need per-row env construction ww cannot self-arrange
|
||||
|
||||
@@ -3078,11 +3078,13 @@ binding is identical before reusing its compile action. A different binding is
|
||||
a deterministic package-resolution failure for the roots that reach it, rather
|
||||
than a first-root-wins build.
|
||||
|
||||
A production action failure blocks exactly the roots that reach it. A
|
||||
root-local compile or link failure does not suppress a successfully built
|
||||
sibling product: the command records completion per product, and the
|
||||
coordinator can run and report successful siblings while attributing each
|
||||
missing product as a build failure. The single union build and completed test
|
||||
A production action failure is attributed to exactly the roots that reach it,
|
||||
but the complete command is one publication transaction. The driver may
|
||||
continue enough of the already validated plan to retain deterministic action
|
||||
and product diagnostics, but one failed producer, linker, status stage, or
|
||||
commit suppresses every new action voucher, tool record, product, and status
|
||||
from that request. The coordinator therefore runs no sibling test binary from
|
||||
a rejected union build. After one successful union build, the completed test
|
||||
products share the coordinator's existing `-j` process bound; captured output
|
||||
is still emitted only in byte-sorted directory/package order.
|
||||
|
||||
@@ -3153,11 +3155,11 @@ compiler-owned dispatcher with empty output is reported as `[no tests]`.
|
||||
|
||||
Persistent workdirs keep a global driver/compiler/assembler/stamp identity and
|
||||
per-action committed units. When that global identity is stale, the command
|
||||
first removes every old `.unit.ww` voucher while leaving artifacts recoverable.
|
||||
It can then commit the new identity even if one root fails: successful actions
|
||||
have freshly committed units, whereas failed or no-longer-requested actions
|
||||
cannot be reused. A retry therefore recompiles the failed action without
|
||||
discarding unchanged canonical packages built for independent products.
|
||||
forces every requested action cold while preserving the complete old generation
|
||||
as rollback state. New tool records, artifacts, units, products, statuses, and
|
||||
the new stamp become visible only in the request-wide commit after every product
|
||||
has staged successfully. A rejected request leaves the old generation
|
||||
byte-identical, and a retry cannot reuse any uncommitted work from the rejection.
|
||||
|
||||
Warm reuse compares the staged owner-only unit, committed artifacts, and the
|
||||
actual bytes of each direct dependency export. A changed shared dependency is
|
||||
@@ -4176,12 +4178,13 @@ succeeds; a rejected request therefore leaves neither directory behind.
|
||||
|
||||
Resolution, identity collision checks, contextual legality, dependency-failure
|
||||
propagation, cycles, command kind, publication paths, and action closures all
|
||||
finish before cold scratch acquisition, product status removal, stale-voucher
|
||||
invalidation, tool identity records, producer execution, publication, or
|
||||
runtime execution. A request whose every product is already invalid returns
|
||||
without acquiring scratch; independent valid sibling products retain the
|
||||
existing isolated-build behavior. A forbidden warm request leaves committed
|
||||
vouchers, status files, tool records, and products byte-unchanged.
|
||||
finish before cold scratch acquisition, tool identity staging, producer
|
||||
execution, publication, or runtime execution. A request whose every product is
|
||||
already invalid returns without acquiring scratch. If a later producer or
|
||||
product fails, otherwise viable siblings may have been produced only into the
|
||||
same transaction; none is committed or executed. A forbidden or otherwise
|
||||
rejected warm request leaves committed vouchers, status files, tool records,
|
||||
and products byte-unchanged.
|
||||
|
||||
This is only manifest-free local source-tree behavior. It does not implement
|
||||
Go modules, module vendor mode, `go.mod`, `vendor/modules.txt`, importcfg, build
|
||||
@@ -4557,20 +4560,15 @@ qualifier or canonical dependency. A package-scope declaration collides with
|
||||
an equal import binding from any contributing file, matching Go's reconciliation
|
||||
of package and file scopes. Conflicting production package clauses remain a
|
||||
loader-owned deterministic error before producers. Compiler-owned scope or use
|
||||
errors may invoke the compiler, but the driver removes that action's staged
|
||||
`.new` unit/export/assembly/object/archive files instead of renaming them. No
|
||||
completion/status marker is written, and no publication occurs after a failed
|
||||
compile. If an artifact rename itself fails after an earlier rename has
|
||||
published part of a new generation, the driver removes every committed unit
|
||||
voucher as well as the remaining staged files. Before the first artifact
|
||||
rename, it must successfully remove the workdir identity stamp; failure is a
|
||||
pre-commit rejection that leaves the prior artifact generation untouched. The
|
||||
stamp remains absent after any partial commit, and later actions in that
|
||||
invocation cannot take the freshness shortcut. Each non-reusable action also
|
||||
loses its old unit voucher before its producers run. The next request must
|
||||
therefore rebuild the incomplete action set and reconsider direct importers; a
|
||||
partly replaced `.wwi` or a failed importer can never make an old importer
|
||||
voucher look fresh.
|
||||
errors may invoke the compiler, but every action artifact remains staged under
|
||||
an adjacent `.new` name. No completion/status marker is written and no product
|
||||
is published after a failed compile. Once every action and product has staged,
|
||||
the driver preserves each existing destination under a request-owned backup,
|
||||
installs the complete new generation, and rolls all installed destinations back
|
||||
if any installation fails. Unit vouchers and the global stamp are transaction
|
||||
members rather than early invalidation markers. Thus a rejected or interrupted
|
||||
request leaves the previous committed generation byte-identical and removes all
|
||||
remaining stages; a mixed `.wwi`/object/archive generation is never reusable.
|
||||
|
||||
Package kind follows the declaration. `package main`, not a path component,
|
||||
marks a command. A path ending in `main` remains importable when it declares a
|
||||
@@ -4690,8 +4688,8 @@ The behavior follows pinned official Go 1.26.5 source at commit
|
||||
[`cmd/go/internal/test/test.go`, lines 1133–1226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1226)).
|
||||
|
||||
Section 11.19 completes ordinary explicit aliases while retaining dotted,
|
||||
unquoted paths. Grouped, quoted, dot, and blank imports remain deliberately
|
||||
unimplemented.
|
||||
unquoted paths. Section 11.20 adds blank side-effect imports without adding a
|
||||
name. Grouped, quoted, and dot imports remain deliberately unimplemented.
|
||||
|
||||
The focused native observer
|
||||
`declared_name_identity_and_file_import_scope` generates every tree
|
||||
@@ -4820,19 +4818,21 @@ Go's leaf comparison: a binding equal to the path leaf says `imported and not
|
||||
used`; any other binding, including an unusual default declared name, says
|
||||
`imported as <name> and not used`.
|
||||
|
||||
`_` is rejected at parse time as `blank import alias _ is not implemented`.
|
||||
Grouped imports, quoted paths, dot imports, and blank imports are deliberately
|
||||
deferred rather than partially implemented.
|
||||
`_` selects the no-binding side-effect mode completed in section 11.20. It is
|
||||
never an ordinary effective qualifier and therefore neither collides with
|
||||
another `_` occurrence nor receives an unused diagnostic. Grouped imports,
|
||||
quoted paths, and dot imports remain deliberately deferred.
|
||||
|
||||
#### Graph, export, artifact, and persistence identity
|
||||
|
||||
The imports-only parser and full parser share one import-spec routine and retain
|
||||
alias and dotted path separately. Both drivers sort and resolve occurrences by
|
||||
the dotted spelling, perform contextual internal and nearest-first vendor checks
|
||||
at every real site, and intern the expanded canonical action. `sepbind` and
|
||||
`--import-map` continue to mean source dotted spelling to expanded vendor
|
||||
identity; neither contains the alias. Repeated occurrences remain separate
|
||||
scope facts but form one sorted canonical edge/action.
|
||||
ordinary alias, blank mode, and dotted path separately. Both drivers sort and
|
||||
resolve occurrences by the dotted spelling, perform contextual internal and
|
||||
nearest-first vendor checks at every real site, and intern the expanded
|
||||
canonical action. `sepbind` and `--import-map` continue to mean source dotted
|
||||
spelling to expanded vendor identity; neither contains the alias or `_`.
|
||||
Repeated occurrences remain separate file facts but form one sorted canonical
|
||||
edge/action.
|
||||
|
||||
The compiler independently reads the direct dependency's declared name. It
|
||||
installs the explicit alias when present or that declared name otherwise, while
|
||||
@@ -4877,7 +4877,7 @@ unchanged semantic bytes stop reverse rebuilding.
|
||||
Parser, identity, alias, declaration, binding, and scope failures occur before
|
||||
publication. Compiler-owned failures may start the compiler, but staged unit,
|
||||
interface, assembly, object, archive, voucher, stamp, status, and product state
|
||||
is discarded or invalidated under section 11.18's partial-commit protocol.
|
||||
is discarded under section 11.20's request transaction.
|
||||
|
||||
#### Stage and observer ownership
|
||||
|
||||
@@ -4896,11 +4896,300 @@ artifact, `.wwi`, and rejection-state matrix. The existing
|
||||
`declared_name_identity_and_file_import_scope` observer owns default-versus-
|
||||
stable-alias invalidation and propagation. Existing directory, command-test,
|
||||
vendor, recursive, exact-argv, link-closure, persistent-workdir, and
|
||||
partial-commit observers retain their broader variant and action ownership.
|
||||
request-transaction observers retain their broader variant and action ownership.
|
||||
Every applicable proof runs Cstage and WWstage from independent cold roots and
|
||||
compares diagnostics, normalized tool arguments, artifacts, binaries, and
|
||||
runtime output.
|
||||
|
||||
### 11.20 Implemented blank side-effect imports and package initialization
|
||||
|
||||
WW now completes the third file-local import mode and the package
|
||||
initialization path needed to give it meaning:
|
||||
|
||||
```ww
|
||||
import acme.codec; // qualifier from the dependency declaration
|
||||
import stable acme.codec; // explicit file-local qualifier stable
|
||||
import _ acme.codec; // no qualifier; initialization side effect only
|
||||
```
|
||||
|
||||
A blank occurrence retains its dotted source spelling, owning file, line,
|
||||
column, source section, and resolved canonical action, but creates no source
|
||||
binding and is exempt from unused-import checking. It exposes neither
|
||||
`wire.Name`, `codec.Name`, nor bare `Name`. Resolution always uses
|
||||
`acme.codec`, never `_`: missing-package, self-import, cycle, final-`internal`,
|
||||
nearest-first vendor, vendor-spelling, and imported-`main` checks run at every
|
||||
blank site exactly as they do for a named occurrence. A vendored blank import
|
||||
therefore keeps a source-to-expanded-identity `--import-map`; `_` enters no
|
||||
map, action key, task symbol, artifact, voucher, stamp, variant, or link input.
|
||||
|
||||
Repeated blank imports of one path, in one file or several files, are valid.
|
||||
A blank occurrence may coexist with the default binding or any explicit alias
|
||||
of the same path. Every named occurrence remains independently subject to its
|
||||
ordinary duplicate-binding and usage rules. All occurrences survive in the
|
||||
owner unit and per-site validation data, while their package-wide union still
|
||||
forms one sorted canonical dependency edge, one package action, and one direct
|
||||
compiler export input.
|
||||
|
||||
#### Pinned Go evidence
|
||||
|
||||
The reference is official Go 1.26.5 at commit
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- `ast.ImportSpec` keeps an optional local `Name`, including `_`, independent
|
||||
from `Path`, and the parser reads that optional name before the path
|
||||
([`go/ast/ast.go`, lines 908–915 and 939–955](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/ast/ast.go#L908-L955),
|
||||
[`go/parser/parser.go`, lines 2509–2546](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2509-L2546)).
|
||||
Function parsing treats `init` as an ordinary syntactic function name; its
|
||||
special meaning is assigned later
|
||||
([`go/parser/parser.go`, lines 2784–2842](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2784-L2842)).
|
||||
- `go/types` creates an import object for each occurrence, inserts no binding
|
||||
for `_`, exempts `_` from unused checking, and keeps a valid `init` function
|
||||
out of package scope while checking its body and signature
|
||||
([`go/types/decl.go`, lines 16–33](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/decl.go#L16-L33),
|
||||
[`go/types/resolver.go`, lines 103–124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L103-L124),
|
||||
[lines 279–350](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L279-L350),
|
||||
[lines 400–433](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L400-L433),
|
||||
[lines 701–716](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L701-L716)).
|
||||
The production compiler equivalent is
|
||||
[`cmd/compile/internal/types2/resolver.go`, lines 90–111](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L90-L111),
|
||||
[lines 264–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L264-L335),
|
||||
[lines 416–444](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L416-L444)
|
||||
and
|
||||
[lines 706–721](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L721).
|
||||
- Official import testdata accepts repeated blanks and blank plus default or
|
||||
explicit named imports of the same path, while diagnosing only the unused
|
||||
named occurrences
|
||||
([`internal/types/testdata/check/importdecl0/importdecl0a.go`, lines 9–31 and 43–52](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L9-L52)).
|
||||
Multiple valid init declarations, invalid signatures, and direct
|
||||
invisibility are pinned by
|
||||
[`test/init.go`, lines 12–18](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/init.go#L12-L18),
|
||||
[`test/noinit.go`, lines 315–326](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/noinit.go#L315-L326),
|
||||
[`internal/types/testdata/check/decls0.go`, lines 40–46](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/decls0.go#L40-L46),
|
||||
and
|
||||
[`decls1.go`, lines 141–146](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/decls1.go#L141-L146).
|
||||
- After constants, variable initialization chooses the declaration with the
|
||||
fewest unresolved variable dependencies and uses source order as its tie;
|
||||
references through functions are dependencies. Cycle reporting is
|
||||
deterministic, and graph removal continues so later independent cycles are
|
||||
also diagnosed
|
||||
([`go/types/initorder.go`, lines 19–185 and 226–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/initorder.go#L19-L335),
|
||||
[`cmd/compile/internal/types2/initorder.go`, lines 16–182 and 223–332](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/initorder.go#L16-L332)).
|
||||
Source ties and calls are exercised by
|
||||
[`go/types/api_test.go`, lines 1408–1619](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/api_test.go#L1408-L1619),
|
||||
with cycle ordering in
|
||||
[`internal/types/testdata/check/init0.go`, lines 22–89](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/init0.go#L22-L89).
|
||||
- The compiler first attempts static initialization and serializes remaining
|
||||
ordered assignments into a compiler-generated init function. It then emits
|
||||
one package task whose dependency tasks are separate `R_INITORDER`
|
||||
relocations and whose payload is an ordered function-pointer list
|
||||
([`cmd/compile/internal/staticinit/sched.go`, lines 34–145](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/staticinit/sched.go#L34-L145),
|
||||
[`cmd/compile/internal/noder/writer.go`, lines 2717–2773](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/writer.go#L2717-L2773),
|
||||
[`cmd/compile/internal/noder/reader.go`, lines 3288–3345](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/reader.go#L3288-L3345),
|
||||
[lines 3389–3416](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/reader.go#L3389-L3416),
|
||||
[`cmd/compile/internal/pkginit/init.go`, lines 20–145](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/pkginit/init.go#L20-L145)).
|
||||
The requested historical `cmd/compile/internal/walk/init.go` path does not
|
||||
exist at this tag; the noder, `staticinit`, and `pkginit` files above are the
|
||||
active implementation.
|
||||
- The linker schedules ready tasks by canonical task symbol and emits each
|
||||
exactly once, and the runtime executes those tasks before user main
|
||||
([`cmd/link/internal/ld/inittask.go`, lines 19–39 and 104–180](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/inittask.go#L19-L180),
|
||||
[`cmd/link/internal/ld/heap.go`, lines 56–99](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/heap.go#L56-L99),
|
||||
[`runtime/proc.go`, lines 203–290](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/runtime/proc.go#L203-L290),
|
||||
[lines 8049–8124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/runtime/proc.go#L8049-L8124)).
|
||||
The `issue31636` packages exercise imports written out of order, while the
|
||||
linker queue above—not that fixture's stale comment—pins lexical ready-task
|
||||
order
|
||||
([`test/fixedbugs/issue31636.dir/main.go`, lines 7–17](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/issue31636.dir/main.go#L7-L17)).
|
||||
- `go/build` specifies sorted directory presentation; its default path obtains
|
||||
byte-sorted names and then classifies production, internal-test, and
|
||||
external-test files/imports separately
|
||||
([`go/build/build.go`, lines 108–111 and 193–207](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L108-L207),
|
||||
[`os/dir.go`, lines 109–125](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/dir.go#L109-L125),
|
||||
[`go/build/build.go`, lines 948–1040](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L948-L1040),
|
||||
[lines 1061–1063](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1061-L1063),
|
||||
[lines 1512–1518](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1512-L1518)).
|
||||
The test loader constructs and rewrites canonical internal, external, and
|
||||
generated-main variants before work actions. In the internal variant it
|
||||
presents the already-sorted production category first and the already-sorted
|
||||
internal-test category second, rather than globally sorting the merge; its
|
||||
effective-test-cycle rule is pinned by
|
||||
[`cmd/go/internal/load/test.go`, lines 85–101, 175–293, and 421–550](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L550)
|
||||
and
|
||||
[`cmd/go/testdata/script/list_test_cycle.txt`, lines 1–20](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/list_test_cycle.txt#L1-L20).
|
||||
Compile/link action ownership remains canonical in
|
||||
[`cmd/go/internal/work/action.go`, lines 437–455, 628–708, and 919–1068](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L1068),
|
||||
while `go test` rejects a bad test graph before creating those actions
|
||||
([`cmd/go/internal/test/test.go`, lines 1185–1226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1185-L1226)).
|
||||
- Unified export data separates public objects from private bodies/init data;
|
||||
a blank import declaration serializes no declaration, and import readers
|
||||
consume the semantic package export independently of that local spelling
|
||||
([`cmd/compile/internal/noder/unified.go`, lines 314–353](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/unified.go#L314-L353),
|
||||
[lines 463–570](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/unified.go#L463-L570),
|
||||
[`cmd/compile/internal/noder/writer.go`, lines 2742–2749](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/writer.go#L2742-L2749),
|
||||
[`cmd/compile/internal/importer/ureader.go`, lines 41–62](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/importer/ureader.go#L41-L62)).
|
||||
Together with the resolver's omission from package scope, that public/private
|
||||
split is why another package cannot select `pkg.init`.
|
||||
- Loader import checks, build-root action ownership, direct compiler import
|
||||
inputs, and transitive linker inputs remain per canonical package rather
|
||||
than per local import name
|
||||
([`cmd/go/internal/load/pkg.go`, lines 787–805](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L787-L805),
|
||||
[`cmd/go/internal/work/build.go`, lines 519–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L519-L558),
|
||||
[`cmd/go/internal/work/exec.go`, lines 864–884](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L864-L884),
|
||||
[lines 1592–1653](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1592-L1653),
|
||||
[`cmd/go/internal/work/gc.go`, lines 136–177](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/gc.go#L136-L177),
|
||||
[lines 590–672](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/gc.go#L590-L672)).
|
||||
|
||||
#### Declaration and package-variable semantics
|
||||
|
||||
`fn init() void = { ... };` is a special initializer declaration. It must have
|
||||
a body, no parameters, no result, no `export`, and no attribute. Multiple valid
|
||||
declarations are accepted in one file and across files. No declaration of
|
||||
another kind may claim `init`; a rejected non-function form is not inserted
|
||||
into scope, so later references still fail lookup. A valid init retains its
|
||||
file, source section, and position, but is never installed as a callable
|
||||
declaration: `init()` and `pkg.init` fail lookup, it is absent from `.wwi`, and
|
||||
it cannot affect canonical package identity.
|
||||
|
||||
Mutable package-level `let` is WW's Go-variable analogue. An initializer that
|
||||
the existing static-data emitter can represent remains static. Every other
|
||||
otherwise valid expression—including calls, allocation, and supported nested
|
||||
array, struct, tuple, and slice values—is evaluated once by a hidden
|
||||
package-owned helper and assigned to zero-backed package storage. Runtime slice
|
||||
literals use canonical writable backing storage rather than escaping a helper
|
||||
stack. `def` and `const` retain their existing compile-time/static rules and are
|
||||
not broadened by this implementation.
|
||||
|
||||
The checker orders all initialized mutable lets by their checked declaration
|
||||
dependencies. References through package functions are transparent edges.
|
||||
Among remaining declarations, the one with the fewest unresolved dependencies
|
||||
wins and original declaration order breaks ties. Files arrive byte-sorted
|
||||
inside each loader category; a combined internal-test variant presents its
|
||||
production category before its internal-test category, and declarations retain
|
||||
source order inside each file. A cycle is
|
||||
reported on the same deterministic walk as the pinned type checkers; removal
|
||||
continues to expose later independent cycles, but any cycle suppresses all init
|
||||
lowering and publication. Runtime variable assignments execute in that order,
|
||||
then every special init function executes in owner-file/source order.
|
||||
|
||||
Each semantic package action owns one hidden task symbol:
|
||||
|
||||
```text
|
||||
__ww..pkg.p.<canonical-path>.v<variant>.r<role>.init
|
||||
```
|
||||
|
||||
The reversible empty-owner form is likewise variant/role qualified. Neither a
|
||||
declared package name, default qualifier, explicit alias, blank spelling, path
|
||||
leaf, physical directory, request ordinal, nor output name contributes to this
|
||||
symbol. Compiler argv supplies it with
|
||||
`--package-init-symbol <symbol>`. Only an executable command root or generated
|
||||
test main additionally receives `--init-dispatch-symbol __ww..dispatch`, and
|
||||
its compiler-generated entry calls that dispatcher before source `main` or the
|
||||
generated test main body.
|
||||
|
||||
#### Product graph, variants, artifacts, and persistence
|
||||
|
||||
Before any producer, the driver forms the effective reachable graph for each
|
||||
product, including internal-test replacement, and rejects a cycle introduced by
|
||||
that replacement. It repeatedly chooses the byte-lexically smallest ready
|
||||
canonical path, then variant and role, while blocking every importer on its
|
||||
dependencies. The resulting root-owned dispatcher calls each effective package
|
||||
task exactly once. Thus dependencies precede importers, a shared diamond task
|
||||
runs once per product, independent ties ignore source import order and linker
|
||||
argv order, and the root task completes before user main or tests.
|
||||
|
||||
An ordinary library object/archive contains its hidden task but building the
|
||||
library does not execute it. An executable or generated-main root archive has
|
||||
two deterministic members, `pkg.o/` followed by `init.o/`; the second member is
|
||||
the root-owned dispatcher. Dependency archives remain ordinary `pkg.o/`
|
||||
archives. Both driver stages stream member bytes through the same bounded
|
||||
transfer buffer instead of retaining archive-sized allocations. Existing
|
||||
linker archive fixpoint extraction pulls the dispatcher and
|
||||
all referenced package tasks without a new linker format or free-floating
|
||||
artifact. Logical linker argv is still the canonical root archive followed by
|
||||
the reachable archive closure and runtime/native inputs; no `.wwi`, alias,
|
||||
blank spelling, or dispatcher sidecar appears.
|
||||
|
||||
Production, production-plus-internal-test, external `_test`, test support, and
|
||||
generated main retain separate action identities. An internal product replaces
|
||||
the colocated production task with its combined variant and includes test-only
|
||||
blank edges/init declarations exactly once. An external product initializes
|
||||
ordinary production and its production dependencies before the external task.
|
||||
Support is an ordinary dependency task; generated main owns only the final
|
||||
dispatcher call and cannot duplicate a tested task. Test-file-only imports,
|
||||
runtime lets, and init functions never enter production. A blank import cannot
|
||||
bypass imported-`main` rejection, including through vendor expansion.
|
||||
|
||||
`.wwi` contains neither blank-only spelling, init declarations/bodies, hidden
|
||||
variable helpers, slice backing symbols, package tasks, nor dispatcher facts.
|
||||
It continues to encode only semantic exported declarations and their canonical
|
||||
reachable type/constant facts. Consequently an init-body-only edit rebuilds the
|
||||
owning object/archive and relinks affected products, while unchanged `.wwi`
|
||||
bytes prevent importer recompilation. Adding or removing a blank edge rebuilds
|
||||
the owning source action and changes exactly the affected reachable dispatcher;
|
||||
a dispatcher-only change rebuilds the root `init.o/` member/archive without
|
||||
recompiling an unchanged root source object. Reverse propagation stops at the
|
||||
first regenerated byte-identical semantic export.
|
||||
|
||||
The owner source voucher remains `<action>.unit.ww`; a linked product root also
|
||||
owns `<root>.init.unit.ww` for its dispatcher unit, `.init.s`, `.init.o`, and
|
||||
two-member archive. Current persistent formats are build 17 and test 16. Warm
|
||||
consumers select a dependency's staged `.wwi.new` or `.a.new` when that exact
|
||||
action changed in the same request. All action artifacts, init artifacts, tool
|
||||
identity copies, stamp, library/executable publications, and test statuses are
|
||||
then one rollback-capable request transaction. No destination changes unless
|
||||
every product stages successfully; a compiler, checker, init-order,
|
||||
dispatcher, assembler, archiver, linker, allocation, status, or installation
|
||||
failure removes remaining stages and restores the complete prior generation.
|
||||
Before scratch acquisition or producer execution, `lstat`-style no-follow
|
||||
checks reserve every action, tool, product, interface, status, and rollback
|
||||
name; a dangling staging or backup symlink is an occupied structural conflict
|
||||
and is never followed or removed. A committed dispatcher voucher must itself
|
||||
be a regular file before it can authorize reuse. Compiler assembly and
|
||||
interface bytes are first generated through anonymous files with checked full
|
||||
writes and then published as their own rollback group. A non-regular compiler
|
||||
destination is rejected before preservation, and installation—not cleanup of
|
||||
a recoverable old backup—is the commit point. Cold rejection removes the exact
|
||||
request-owned scratch tree. Stale init code, stale closure metadata, and mixed
|
||||
committed generations therefore cannot be reused.
|
||||
|
||||
#### Stage and observer ownership
|
||||
|
||||
The shared syntax AST, C parser, and WW parser own blank/init facts and source
|
||||
positions. Both imports-only driver scans resolve the dotted path and retain
|
||||
per-site legality; neither treats `_` as an alias. The C and WW checkers own
|
||||
special-init validation, invisibility, mutable-let dependency ordering, cycle
|
||||
diagnostics, and runtime lowering. The interface writers omit initialization
|
||||
implementation; the code generators emit static storage, runtime helpers,
|
||||
package tasks, canonical slice backings, and the entry dispatcher call. The two
|
||||
drivers own task identity, effective test graphs, global dispatcher ordering,
|
||||
exact direct compiler inputs, archive membership, link closure, persistence,
|
||||
and the request transaction. The assemblers consume the dynamically sized
|
||||
canonical symbols. Both linkers are unchanged and use their existing iterative
|
||||
archive extraction. `internal/wwpackage` and `cmd/wwtest` retain package/test
|
||||
classification and execution coordination; they do not parse imports, invent
|
||||
tasks, or call init manually.
|
||||
|
||||
The focused native `test/sep/sepinit_test.ww` observer generates every source
|
||||
tree temporarily and proves runtime let/init order, dependency chains,
|
||||
diamonds, independent lexical ties, aggregate and allocation initialization,
|
||||
multiple-cycle diagnostics, special-init rejection, test-variant isolation,
|
||||
canonical task/dispatcher/archive bytes, init-only invalidation, and warm
|
||||
invalid-init rollback across independent Cstage and WWstage roots. Direct and
|
||||
recursive test legs compare variant dispatcher/archive bytes and observable
|
||||
production-dependency order; exact task counts include support and generated
|
||||
main. Rejection rows compare complete normalized diagnostics and prove cold
|
||||
scratch absence. The observer also uses a repository-built `setrlimit` launcher
|
||||
to find one shared bounded-memory ceiling at which both drivers fail before a
|
||||
producer, and proves no-follow atomic rejection of dangling driver staging and
|
||||
compiler rollback names, non-regular compiler destinations, and compiler
|
||||
output-write failures. The extended
|
||||
`explicit_import_alias_binding_modes` observer owns repeated blank/default/
|
||||
alias/file-scope combinations and no-binding/unused behavior. Existing
|
||||
internal, vendor, imported-command, recursive, exact-argv, link-closure,
|
||||
persistent-workdir, rejection-state, byte-identity, and bootstrap observers own
|
||||
their unchanged broader boundaries. Grouped imports, quoted imports, and dot
|
||||
imports remain deliberately unimplemented.
|
||||
|
||||
## 12. Candidate architectures and hard-gate decision
|
||||
|
||||
Five candidates were developed as coherent systems, not as feature bins.
|
||||
|
||||
59
docs/spec.md
59
docs/spec.md
@@ -246,7 +246,8 @@ does not return (e.g. a call to `abort`).
|
||||
```
|
||||
SourceFile = PackageClause { ImportDecl } { TopDecl } .
|
||||
PackageClause = "package" ident ";" .
|
||||
ImportDecl = "import" ( ImportPath | ident ImportPath ) ";" .
|
||||
ImportDecl = "import" ( ImportPath | ImportName ImportPath ) ";" .
|
||||
ImportName = ident .
|
||||
ImportPath = ident { "." ident } .
|
||||
```
|
||||
|
||||
@@ -263,8 +264,18 @@ ImportPath = ident { "." ident } .
|
||||
Neither form exposes an imported declaration as a bare `Name`; ordinary
|
||||
unqualified lookup remains limited to lexical, builtin, and same-package
|
||||
declarations.
|
||||
- `import _ acme.codec;` is a blank side-effect import. The lone `_` creates no
|
||||
qualifier, exposes no bare declaration, and is never diagnosed as unused.
|
||||
It is nevertheless a real import occurrence: resolution and all missing,
|
||||
self-import, cycle, `internal`, vendor, and imported-command checks use the
|
||||
dotted path, and the dependency participates in executable and test package
|
||||
initialization. Repeated blank occurrences and blank plus default/explicit
|
||||
named occurrences of one path are valid; every named occurrence remains
|
||||
independently subject to duplicate-binding and unused checks.
|
||||
The package dependency graph is the sorted, deduplicated union of the real
|
||||
imports in all eligible files. Self-import is rejected.
|
||||
imports in all eligible files. Occurrences retain their owning file and
|
||||
position, but equal canonical targets create one graph edge/package action.
|
||||
Self-import is rejected.
|
||||
- An executable package is one declared `package main` and containing a
|
||||
`fn main`; path and directory spelling do not classify commands. An ordinary
|
||||
import of a package declared `main` is rejected, except for the toolchain's
|
||||
@@ -272,8 +283,8 @@ ImportPath = ident { "." ident } .
|
||||
- Only names marked `export` (§5) are visible across module boundaries.
|
||||
|
||||
Import paths remain unquoted and dotted. Grouped imports, quoted import paths,
|
||||
dot imports, and blank imports are not implemented. In particular, `_` is
|
||||
rejected as an alias rather than being treated as a blank import.
|
||||
and dot imports are not implemented. `_` is reserved here for the blank form;
|
||||
it is not an ordinary alias.
|
||||
|
||||
---
|
||||
|
||||
@@ -298,23 +309,42 @@ The `=` between signature and body is required. A bodiless fn (`;`
|
||||
terminator) declares an external symbol (C FFI); the bare `...` C-style
|
||||
variadic is legal only on a bodiless declaration (§6.3).
|
||||
|
||||
At package scope, exactly `fn init() void = Block;` declares a special package
|
||||
initializer. It must have a body, no parameters, no result, no `export`, and no
|
||||
attribute. Multiple init declarations are permitted and retain owner-file and
|
||||
source order. `init` is not inserted into ordinary package scope: it cannot be
|
||||
called as `init()`, selected as `pkg.init`, exported, or used by another kind
|
||||
of declaration. Package-variable initialization completes before these
|
||||
functions run.
|
||||
|
||||
### 5.2 `let`
|
||||
|
||||
```
|
||||
LetDecl = "let" ident ":" Type [ "=" Expr ] ";" .
|
||||
```
|
||||
|
||||
A mutable binding. Without an initialiser the storage is uninitialised.
|
||||
A mutable binding. Without an initialiser, package-level storage is
|
||||
zero-backed; an uninitialized function-local binding retains the existing
|
||||
uninitialized-local rule.
|
||||
A `static` qualifier (`static let …`) gives function-local storage
|
||||
static lifetime.
|
||||
|
||||
For a package-level `let` with an initializer, values representable by the
|
||||
static-data emitter are installed statically. Every other otherwise valid
|
||||
initializer is evaluated exactly once at runtime. Checked references through
|
||||
package functions contribute variable-dependency edges; dependencies precede
|
||||
dependents, and source declaration order breaks ready ties. Initialization
|
||||
cycles are errors. Runtime package lets execute after imported package tasks and
|
||||
before the package's init functions. `const` and `def` are not broadened by
|
||||
this runtime path.
|
||||
|
||||
### 5.3 `const`
|
||||
|
||||
`const` introduces an immutable binding of the same shape as `let`.
|
||||
|
||||
TODO(spec): pin the exact `const` vs `def` boundary against `cmd/wcc`
|
||||
(both keywords exist; this text takes `def` = compile-time constant
|
||||
[Hare's `def`] and `const` = immutable runtime binding — confirm).
|
||||
`const` introduces an immutable storage binding of the same declaration shape
|
||||
as `let`; assignment to it is rejected. At package scope its initializer stays
|
||||
within the existing static-data forms. A `const` is not entered into the
|
||||
runtime package-variable schedule described above; use mutable `let` when an
|
||||
otherwise valid initializer requires runtime evaluation.
|
||||
|
||||
### 5.4 `def`
|
||||
|
||||
@@ -561,6 +591,15 @@ the program. Two placements, following the Go `foo` / `foo_test` model:
|
||||
};
|
||||
```
|
||||
|
||||
Production, production-plus-white-box-test, external black-box-test, test
|
||||
support, and generated test main are distinct package actions. Before a test
|
||||
function runs, the generated test product initializes its exact reachable
|
||||
variant graph dependency-first and once per canonical action. A white-box
|
||||
variant replaces the colocated production task rather than initializing both;
|
||||
an external variant depends on ordinary production. Imports, runtime lets, and
|
||||
init declarations found only in `*_test.ww` never enter an ordinary production
|
||||
build.
|
||||
|
||||
---
|
||||
|
||||
## 11. Concurrency (reserved)
|
||||
|
||||
@@ -24,7 +24,7 @@ categories out of the ordinary developer target.
|
||||
| --- | --- |
|
||||
| Arena, lexer, parser, checker, module-decl parse, narrow codegen | Six in-process C unit binaries |
|
||||
| Compile success/rejection, stage-routed diagnostics, and runtime exit | `test/wcc/data/*/case.ww`, executed by `wwfixture` |
|
||||
| Package semantics | `test/package` and the native package-test coordinator |
|
||||
| Package semantics | `test/package`, `test/sep/sepinit_test.ww`, and the native package-test coordinator |
|
||||
| Language behavior | `test/lang/*_test.ww` through the language `@test` runtime |
|
||||
| Library behavior | The package coordinator's `lib/...` tree walk (`ww test -j N lib/...`) |
|
||||
| Standalone library-source compilation | Three import-free real source paths named by `LIBRARY_STANDALONE_SOURCES`, compiled directly by both frontends |
|
||||
@@ -236,25 +236,41 @@ qualifier remain distinct. The alias matrix covers default and explicit-only
|
||||
qualification, bare function/type/def/const/variable rejection with exact
|
||||
unused-before-undefined diagnostics, same-file duplicate bindings, accepted
|
||||
same-path imports under distinct bindings, alias reuse across files, sibling
|
||||
scope isolation, package-declaration collisions, unused aliases, and explicit
|
||||
blank-alias rejection. It also pins canonical `.wwi` spelling, archive/action
|
||||
ownership, stage-equal diagnostics and binaries, and clean rejection state.
|
||||
scope isolation, package-declaration collisions, unused aliases, blank
|
||||
side-effect imports, repeated blank/default/explicit combinations, and blank
|
||||
no-binding/no-unused behavior. It also pins canonical `.wwi` spelling,
|
||||
archive/action ownership, one canonical direct edge for repeated occurrences,
|
||||
stage-equal diagnostics and binaries, and clean rejection state.
|
||||
The declared-name observer proves imports are file-scoped while dependency
|
||||
edges are the package-wide sorted union; command and
|
||||
production/internal/external/generated-main variants retain canonical action
|
||||
ownership; vendor expansion changes identity but not the effective qualifier;
|
||||
compiler argv contains only direct `.wwi` inputs; and its named rejected
|
||||
actions leave neither committed nor staged action artifacts or a published
|
||||
binary. It also forces a staged multi-artifact commit to fail after the
|
||||
interface rename, then proves that both stages invalidate old unit vouchers and
|
||||
reconsider the importer rather than accepting a mixed warm generation. A
|
||||
separate injected stamp-removal failure proves the pre-commit gate leaves all
|
||||
previously committed artifacts byte-identical.
|
||||
binary. It also forces a request transaction to reject after dependency work
|
||||
has staged, then proves that both stages restore every prior artifact, unit,
|
||||
tool record, stamp, and product rather than accepting a mixed warm generation.
|
||||
Together with the existing directory, recursive, vendor,
|
||||
exact-argv, command, and persistent-workdir observers, the package suite proves
|
||||
archive-only link argv and exact warm/rejection-state behavior without
|
||||
duplicating those broader mechanisms in this observer.
|
||||
|
||||
`test/sep/sepinit_test.ww` is the single focused package-initialization owner.
|
||||
It generates all source trees temporarily and runs independent cold/persistent
|
||||
Cstage and WWstage legs. Its matrix covers blank-only reachability; dependency,
|
||||
diamond, and independent ready-task order; runtime call/allocation and aggregate
|
||||
package lets; multiple init declarations and invalid forms; direct/qualified
|
||||
init invisibility; initialization cycles and diagnostic order; command,
|
||||
internal-test, external-test, support, and generated-main ownership; canonical
|
||||
task and dispatcher symbols; deterministic one- and two-member archives;
|
||||
`.wwi` exclusion; byte-identical artifacts/binaries; init-only invalidation;
|
||||
warm invalid-init rollback; direct/recursive variant equivalence; exact
|
||||
production, support, and generated-main task ordering; complete normalized
|
||||
rejection diagnostics; dangling staging/rollback no-follow rejection; and
|
||||
checked compiler-output failure/non-regular-destination rollback; and
|
||||
bounded-memory allocation-failure parity under one shared ceiling supplied by
|
||||
the repository-built `sep-limitexec` helper.
|
||||
|
||||
`ww build`, an explicit single-file `ww test -o <stem>`, and each successful
|
||||
directory-package `ww test -c` build publish `<stem>.sepwork` as a caller-owned
|
||||
artifact directory. The driver acquires it with one fresh `mkdir` and refuses
|
||||
@@ -279,13 +295,17 @@ no hashes, every decision reproducible with `cmp` against plain files. The
|
||||
driver identity covers graph construction, owner-unit composition,
|
||||
direct-export argument construction, archive creation, and commit algorithms
|
||||
that neither unit bytes nor compiler identity can name.
|
||||
Recompiled artifacts land at staged `.new` names and commit by rename with the
|
||||
unit renamed last, so an interrupted build forces a recompile rather than a
|
||||
false reuse; the link always reruns. One workdir serves one invocation at a
|
||||
time and may hold the complete command-global action universe for all selected
|
||||
roots and isolated variants; semantic identity, rather than request shape,
|
||||
controls reuse. Both driver stages implement the identical contract. This is
|
||||
build staleness in the Make/mk/Go sense, not a result cache:
|
||||
Recompiled artifacts, dispatcher artifacts, products, statuses, tool copies,
|
||||
and the stamp land at staged `.new` names. After every requested product stages
|
||||
successfully, one rollback-capable transaction installs the whole generation;
|
||||
any producer or installation failure preserves the prior committed bytes and
|
||||
removes remaining stages. An interrupted or rejected request therefore cannot
|
||||
create false reuse or a mixed generation; a successful executable link still
|
||||
reruns when required. One workdir serves one invocation at a time and may hold
|
||||
the complete command-global action universe for all selected roots and isolated
|
||||
variants; semantic identity, rather than request shape, controls reuse. Both
|
||||
driver stages implement the identical contract. This is build staleness in the
|
||||
Make/mk/Go sense, not a result cache:
|
||||
tests always run, and the byte-identity and bootstrap gates keep building on
|
||||
fresh scratch. `make clean` reclaims every workdir under `out/`.
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
sink.zero = zero;
|
||||
let rb: [1]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(&sink.vt, rb[0:1], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(&sink.vt, rb[0:1], wb[0:4]);
|
||||
let src: [4]u8;
|
||||
let _: i32 = sputstr("ABCD", src[0:4], 0);
|
||||
let wr: (size | io.error) = io.write(&b.vt, src[0:4]);
|
||||
@@ -109,7 +109,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [8]u8;
|
||||
let wb: [8]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:8], wb[0:8]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:8], wb[0:8]);
|
||||
|
||||
// Write under the buffer limit — nothing reaches src.
|
||||
let buf: [5]u8;
|
||||
@@ -139,7 +139,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [4]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:4]);
|
||||
|
||||
// 10B payload through a 4B wbuf: bwrite must flush twice mid-write.
|
||||
let buf: [10]u8;
|
||||
@@ -170,7 +170,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [4]u8;
|
||||
let wb: [16]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:16]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:16]);
|
||||
|
||||
let p: io.stream = &b.vt;
|
||||
|
||||
@@ -204,7 +204,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [4]u8;
|
||||
let wb: [16]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:16]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:16]);
|
||||
let nilbs: [1]u8;
|
||||
bufio.setflush(&b, nilbs[0:0]);
|
||||
|
||||
@@ -245,7 +245,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [4]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:4]);
|
||||
|
||||
assert(!(!bufio.isbuffered(&b.vt)));
|
||||
assert(!(bufio.isbuffered(m)));
|
||||
@@ -264,7 +264,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [8]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:8], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:8], wb[0:4]);
|
||||
|
||||
let p: io.stream = &b.vt;
|
||||
|
||||
@@ -303,7 +303,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [8]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:8], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:8], wb[0:4]);
|
||||
|
||||
let p: io.stream = &b.vt;
|
||||
|
||||
@@ -339,7 +339,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [8]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:8], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:8], wb[0:4]);
|
||||
|
||||
let p: io.stream = &b.vt;
|
||||
|
||||
@@ -385,7 +385,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
let rb: [4]u8;
|
||||
let _: i32 = sputstr("ABCD", rb[0:4], 0);
|
||||
let wb: [1]u8;
|
||||
let b: bufio.stream = bufio.init(&mem.vt, rb[0:4], wb[0:1]);
|
||||
let b: bufio.stream = bufio.newstream(&mem.vt, rb[0:4], wb[0:1]);
|
||||
bufio.unread(&b, rb[0:3]);
|
||||
let out: [3]u8;
|
||||
let r: (size | io.eof | io.error) = io.read(&b.vt, out[0:3]);
|
||||
@@ -406,7 +406,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [16]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:16], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:16], wb[0:4]);
|
||||
|
||||
let push: [3]u8;
|
||||
push[0] = 88u8; push[1] = 89u8; push[2] = 90u8; // "XYZ"
|
||||
@@ -437,7 +437,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [4]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:4]);
|
||||
|
||||
let r: (void | io.error) = bufio.flush(&b);
|
||||
match (r) {
|
||||
@@ -454,7 +454,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [4]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:4]);
|
||||
let nilbs: [1]u8;
|
||||
bufio.setflush(&b, nilbs[0:0]); // suppress the default '\n' detector
|
||||
|
||||
@@ -490,7 +490,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [4]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(src, rb[0:4], wb[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(src, rb[0:4], wb[0:4]);
|
||||
let nilbs: [1]u8;
|
||||
bufio.setflush(&b, nilbs[0:0]); // suppress the default '\n' detector
|
||||
|
||||
@@ -524,7 +524,7 @@ fn checkpartialflush(zero: bool) void = {
|
||||
|
||||
let rb: [4]u8;
|
||||
let wb: [16]u8;
|
||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:16]);
|
||||
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:16]);
|
||||
let bs: [1]u8;
|
||||
bs[0] = 32u8; // ' '
|
||||
bufio.setflush(&b, bs[0:1]);
|
||||
|
||||
@@ -4,7 +4,7 @@ import math.random;
|
||||
import test;
|
||||
|
||||
@test fn seq() void = {
|
||||
let r: random.random = random.init(1234567u64);
|
||||
let r: random.random = random.fromseed(1234567u64);
|
||||
assert(!(random.next(&r) != 6457827717110365317u64));
|
||||
assert(!(random.next(&r) != 3203168211198807973u64));
|
||||
assert(!(random.next(&r) != 9817491932198370423u64));
|
||||
@@ -13,8 +13,8 @@ import test;
|
||||
};
|
||||
|
||||
@test fn deterministic() void = {
|
||||
let a: random.random = random.init(42u64);
|
||||
let b: random.random = random.init(42u64);
|
||||
let a: random.random = random.fromseed(42u64);
|
||||
let b: random.random = random.fromseed(42u64);
|
||||
let i: i32 = 0;
|
||||
for (i < 32) {
|
||||
assert(!(random.next(&a) != random.next(&b)));
|
||||
@@ -23,7 +23,7 @@ import test;
|
||||
};
|
||||
|
||||
@test fn u32n_inrange() void = {
|
||||
let r: random.random = random.init(7u64);
|
||||
let r: random.random = random.fromseed(7u64);
|
||||
let i: i32 = 0;
|
||||
for (i < 200) {
|
||||
let v: u32 = random.u32n(&r, 17u32);
|
||||
@@ -35,7 +35,7 @@ import test;
|
||||
};
|
||||
|
||||
@test fn u64n_pow2() void = {
|
||||
let r: random.random = random.init(99u64);
|
||||
let r: random.random = random.fromseed(99u64);
|
||||
let i: i32 = 0;
|
||||
for (i < 200) {
|
||||
let v: u64 = random.u64n(&r, 16u64);
|
||||
@@ -45,7 +45,7 @@ import test;
|
||||
};
|
||||
|
||||
@test fn u64n_nonpow2() void = {
|
||||
let r: random.random = random.init(123u64);
|
||||
let r: random.random = random.fromseed(123u64);
|
||||
let i: i32 = 0;
|
||||
for (i < 200) {
|
||||
let v: u64 = random.u64n(&r, 100u64);
|
||||
@@ -60,12 +60,12 @@ import test;
|
||||
|
||||
@test fn u32n_zero_aborts() void = {
|
||||
test.expectabort();
|
||||
let r: random.random = random.init(1u64);
|
||||
let r: random.random = random.fromseed(1u64);
|
||||
random.u32n(&r, 0u32);
|
||||
};
|
||||
|
||||
@test fn u64n_zero_aborts() void = {
|
||||
test.expectabort();
|
||||
let r: random.random = random.init(1u64);
|
||||
let r: random.random = random.fromseed(1u64);
|
||||
random.u64n(&r, 0u64);
|
||||
};
|
||||
|
||||
@@ -75,31 +75,6 @@ fn astrow(label: str, src: str, needles: []str) void = {
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
fn rejectrow(label: str, src: str, needle: str) void = {
|
||||
let td: str = testenv.fresh();
|
||||
testenv.writefile(strings.concat(td, "/a.ww"), src);
|
||||
let tools: []str = ["wwdump", "wwdump_ww"];
|
||||
let stages: []str = ["cstage", "wwstage"];
|
||||
let errors: []str = ["", ""];
|
||||
let i: i32 = 0;
|
||||
for (i < tools.len) {
|
||||
let av: []str = [testenv.driver(tools[i]), "-a",
|
||||
strings.concat(td, "/a.ww")];
|
||||
let co: testenv.commandout;
|
||||
testenv.runcommand(td, td, stages[i], av, tmo(), &co);
|
||||
if (co.termination != exec.termination.EXIT || co.code == 0
|
||||
|| !testenv.has(co.stderr, needle)) {
|
||||
fail(label, strings.concat(stages[i], " accepted rejected import"));
|
||||
};
|
||||
errors[i] = strings.dup(co.stderr);
|
||||
i += 1;
|
||||
};
|
||||
if (!testenv.same(errors[0], errors[1])) {
|
||||
fail(label, "cs/ww parse diagnostics DIFFER");
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
@test fn astproof() void = {
|
||||
let trailing: []str = ["(dot \"x\"", "(structlit",
|
||||
"(tname \"pkg.point\""];
|
||||
@@ -127,9 +102,11 @@ fn rejectrow(label: str, src: str, needle: str) void = {
|
||||
"package main;\n",
|
||||
"import stable acme.codec;\n",
|
||||
"fn main() i32 = { return 0; };\n"), aliased);
|
||||
rejectrow("blank-alias", strings.concat(
|
||||
// A blank N_USE deliberately has no `.str` qualifier, so astprint's
|
||||
// `(use` line has no quoted binding while remaining a real use node.
|
||||
let blank: []str = ["(use\n"];
|
||||
astrow("blank-import", strings.concat(
|
||||
"package main;\n",
|
||||
"import _ acme.codec;\n",
|
||||
"fn main() i32 = { return 0; };\n"),
|
||||
"blank import alias _ is not implemented");
|
||||
"fn main() i32 = { return 0; };\n"), blank);
|
||||
};
|
||||
|
||||
@@ -1157,12 +1157,16 @@ fn hexbytes(value: str) str = {
|
||||
assert(!has(externalproduction, "//ww:module "));
|
||||
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
|
||||
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
|
||||
assert(same(samemainunit, strings.concat(
|
||||
assert(strings.hasprefix(samemainunit, strings.concat(
|
||||
"//ww:module-reset __wwtestmain.pkg.internal.main\n",
|
||||
"package main;\nimport pkg;\nimport test;\n")));
|
||||
assert(same(externalmainunit, strings.concat(
|
||||
assert(strings.hasprefix(externalmainunit, strings.concat(
|
||||
"//ww:module-reset __wwtestmain.pkg_test.external.main\n",
|
||||
"package main;\nimport pkg_test;\nimport test;\n")));
|
||||
assert(has(samemainunit, "//ww:direct-export pkg "));
|
||||
assert(has(samemainunit, "//ww:direct-export test "));
|
||||
assert(has(externalmainunit, "//ww:direct-export pkg_test "));
|
||||
assert(has(externalmainunit, "//ww:direct-export test "));
|
||||
assert(!has(samemainunit, "PACKAGE_PRODUCTION"));
|
||||
assert(!has(samemainunit, "SAME_TEST_SOURCE"));
|
||||
assert(!has(externalmainunit, "EXTERNAL_TEST_SOURCE"));
|
||||
@@ -1221,13 +1225,15 @@ fn hexbytes(value: str) str = {
|
||||
let productioncompile: str = linecontaining(ctrace,
|
||||
"/pkg.unit.ww");
|
||||
assert(same(samecompile, strings.concat(
|
||||
"--test-package -c --import __same ",
|
||||
"--test-package --package-init-symbol ",
|
||||
"__ww..pkg.p.pkg.v1.r0.init -c --import __same ",
|
||||
sharedwork, "__same.wwi --import api ", sharedwork,
|
||||
"api.wwi -I ", sharedwork, "pkg-internal-test.wwi -o ",
|
||||
sharedwork, "pkg-internal-test.s ", sharedwork,
|
||||
"pkg-internal-test.unit.ww")));
|
||||
assert(same(externalcompile, strings.concat(
|
||||
"--test-package -c --import __external ",
|
||||
"--test-package --package-init-symbol ",
|
||||
"__ww..pkg.p.pkg_test.v2.r0.init -c --import __external ",
|
||||
sharedwork, "__external.wwi --import pkg ", sharedwork,
|
||||
"pkg.wwi -I ", sharedwork,
|
||||
"pkg_test-external-test.wwi -o ", sharedwork,
|
||||
@@ -1239,7 +1245,9 @@ fn hexbytes(value: str) str = {
|
||||
"pkg_test-external-test-main.unit.ww");
|
||||
assert(same(samemaincompile, strings.concat(
|
||||
"-T --entry --test-support-module test ",
|
||||
"--test-target-package pkg -c --import pkg ",
|
||||
"--test-target-package pkg --package-init-symbol ",
|
||||
"__ww..pkg.p.__wwtestmain.pkg.internal.main.v3.r2.init ",
|
||||
"--init-dispatch-symbol __ww..dispatch -c --import pkg ",
|
||||
sharedwork, "pkg-internal-test.wwi --import test ",
|
||||
sharedwork, "test.wwi -I ", sharedwork,
|
||||
"pkg-internal-test-main.wwi -o ", sharedwork,
|
||||
@@ -1247,22 +1255,25 @@ fn hexbytes(value: str) str = {
|
||||
"pkg-internal-test-main.unit.ww")));
|
||||
assert(same(externalmaincompile, strings.concat(
|
||||
"-T --entry --test-support-module test ",
|
||||
"--test-target-package pkg_test -c --import pkg_test ",
|
||||
"--test-target-package pkg_test --package-init-symbol ",
|
||||
"__ww..pkg.p.__wwtestmain.pkg_test.external.main.v3.r2.init ",
|
||||
"--init-dispatch-symbol __ww..dispatch -c --import pkg_test ",
|
||||
sharedwork, "pkg_test-external-test.wwi --import test ",
|
||||
sharedwork, "test.wwi -I ", sharedwork,
|
||||
"pkg_test-external-test-main.wwi -o ", sharedwork,
|
||||
"pkg_test-external-test-main.s ", sharedwork,
|
||||
"pkg_test-external-test-main.unit.ww")));
|
||||
assert(same(productioncompile, strings.concat(
|
||||
"--package-init-symbol __ww..pkg.p.pkg.v0.r0.init ",
|
||||
"-c --import api ", sharedwork, "api.wwi -I ", sharedwork,
|
||||
"pkg.wwi -o ", sharedwork,
|
||||
"pkg.s ", sharedwork, "pkg.unit.ww")));
|
||||
let ltrace: str = readfile(linkertrace);
|
||||
assert(occurrences(ltrace, "\n") == 2);
|
||||
let samelink: str = linecontaining(ltrace,
|
||||
strings.concat("-o ", samebin, " "));
|
||||
strings.concat("-o ", samebin, ".new "));
|
||||
let externallink: str = linecontaining(ltrace,
|
||||
strings.concat("-o ", externalbin, " "));
|
||||
strings.concat("-o ", externalbin, ".new "));
|
||||
assert(has(samelink, strings.concat(sharedwork, "api.a")));
|
||||
assert(has(samelink,
|
||||
strings.concat(sharedwork, "implementation.a")));
|
||||
@@ -1848,7 +1859,7 @@ fn hexbytes(value: str) str = {
|
||||
ri = 0;
|
||||
for (ri < bins.len) {
|
||||
let link: str = linecontaining(ltrace,
|
||||
strings.concat("-o ", bins[ri], " "));
|
||||
strings.concat("-o ", bins[ri], ".new "));
|
||||
assert(has(link, strings.concat(sharedwork, mainkeys[ri], ".a")));
|
||||
assert(has(link, strings.concat(sharedwork, rootkeys[ri], ".a")));
|
||||
assert(!has(link, ".wwi"));
|
||||
@@ -2403,13 +2414,13 @@ fn hexbytes(value: str) str = {
|
||||
let links: str = readfile(linktrace);
|
||||
assert(occurrences(links, "\n") == 4);
|
||||
let namedsame: str = linecontaining(links,
|
||||
strings.concat("-o ", bins[0], " "));
|
||||
strings.concat("-o ", bins[0], ".new "));
|
||||
let namedexternal: str = linecontaining(links,
|
||||
strings.concat("-o ", bins[1], " "));
|
||||
strings.concat("-o ", bins[1], ".new "));
|
||||
let consumersame: str = linecontaining(links,
|
||||
strings.concat("-o ", bins[2], " "));
|
||||
strings.concat("-o ", bins[2], ".new "));
|
||||
let consumerexternal: str = linecontaining(links,
|
||||
strings.concat("-o ", bins[3], " "));
|
||||
strings.concat("-o ", bins[3], ".new "));
|
||||
assert(has(namedsame, strings.concat(work, "__wwtest.a")));
|
||||
assert(!has(namedsame, strings.concat(work, "test.a")));
|
||||
assert(has(namedexternal, strings.concat(work, "test.a")));
|
||||
@@ -2595,19 +2606,22 @@ fn hexbytes(value: str) str = {
|
||||
let atrace: str = readfile(assemblertraces[si]);
|
||||
let ltrace: str = readfile(linkertraces[si]);
|
||||
assert(occurrences(ctrace, "\n") == packagecount + 1);
|
||||
assert(occurrences(atrace, "\n") == packagecount + 1);
|
||||
assert(occurrences(atrace, "\n") == packagecount + 2);
|
||||
assert(occurrences(ltrace, "\n") == 1);
|
||||
let rootline: str = linecontaining(ctrace,
|
||||
strings.concat("/", rootaction, ".unit.new"));
|
||||
assert(occurrences(rootline, "<--import>") == packagecount);
|
||||
let expectedroot: str = "BEGIN<--entry><-c>";
|
||||
let expectedroot: str = strings.concat(
|
||||
"BEGIN<--entry><--package-init-symbol><__ww..pkg.p.",
|
||||
rootaction, ".v0.r0.init><--init-dispatch-symbol>",
|
||||
"<__ww..dispatch><-c>");
|
||||
i = 0;
|
||||
for (i < packagecount) {
|
||||
let name: str = boundarypkgname(i);
|
||||
expectedroot = strings.concat(expectedroot, "<--import><", name,
|
||||
"><", works[si], "/", name, ".wwi>");
|
||||
"><", works[si], "/", name, ".wwi.new>");
|
||||
assert(occurrences(rootline, strings.concat("<", name, "><",
|
||||
works[si], "/", name, ".wwi>")) == 1);
|
||||
works[si], "/", name, ".wwi.new>")) == 1);
|
||||
i += 1;
|
||||
};
|
||||
expectedroot = strings.concat(expectedroot, "<-I><", works[si], "/",
|
||||
@@ -2617,12 +2631,14 @@ fn hexbytes(value: str) str = {
|
||||
i = 0;
|
||||
for (i < packagecount) {
|
||||
let name: str = boundarypkgname(i);
|
||||
let expectedcompile: str = "BEGIN<-c>";
|
||||
let expectedcompile: str = strings.concat(
|
||||
"BEGIN<--package-init-symbol><__ww..pkg.p.", name,
|
||||
".v0.r0.init><-c>");
|
||||
if (i + 1 < packagecount) {
|
||||
let next: str = boundarypkgname(i + 1);
|
||||
expectedcompile = strings.concat(expectedcompile,
|
||||
"<--import><", next, "><", works[si], "/", next,
|
||||
".wwi>");
|
||||
".wwi.new>");
|
||||
};
|
||||
expectedcompile = strings.concat(expectedcompile, "<-I><",
|
||||
works[si], "/", name, ".wwi.new><-o><", works[si], "/",
|
||||
@@ -2634,7 +2650,7 @@ fn hexbytes(value: str) str = {
|
||||
assert(same(linecontaining(atrace,
|
||||
strings.concat("/", name, ".o.new")), expectedassemble));
|
||||
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
|
||||
name, ".a>")) == 1);
|
||||
name, ".a.new>")) == 1);
|
||||
assert(os.exists(strings.concat(works[si], "/", name, ".wwi")));
|
||||
assert(os.exists(strings.concat(works[si], "/", name, ".s")));
|
||||
assert(os.exists(strings.concat(works[si], "/", name, ".o")));
|
||||
@@ -2652,35 +2668,47 @@ fn hexbytes(value: str) str = {
|
||||
};
|
||||
let z: str = strings.concat("package ", name, ";\n// OWNER_Z_",
|
||||
name, "\nfn private_value() i32 = { return value(); };\n");
|
||||
assert(same(readfile(strings.concat(works[si], "/", name,
|
||||
".unit.ww")), strings.concat("//ww:module-reset ", name,
|
||||
"\n", a, "\n//ww:module-reset ", name, "\n", z, "\n")));
|
||||
let unit: str = readfile(strings.concat(works[si], "/", name,
|
||||
".unit.ww"));
|
||||
assert(strings.hasprefix(unit, strings.concat("//ww:module-reset ",
|
||||
name, "\n", a, "\n//ww:module-reset ", name, "\n", z, "\n")));
|
||||
if (i + 1 < packagecount) {
|
||||
assert(has(unit, strings.concat("//ww:direct-export ",
|
||||
boundarypkgname(i + 1), " ")));
|
||||
};
|
||||
assert(strings.hasprefix(readfile(strings.concat(works[si], "/",
|
||||
name, ".wwi")), strings.concat("//ww:module ", name, "\n")));
|
||||
i += 1;
|
||||
};
|
||||
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
|
||||
rootaction, ".a>")) == 1);
|
||||
rootaction, ".a.new>")) == 1);
|
||||
assert(!has(ltrace, ".wwi>"));
|
||||
let expectedlink: str = strings.concat("BEGIN<-o><", bins[si], "><",
|
||||
works[si], "/", rootaction, ".a>");
|
||||
let expectedlink: str = strings.concat("BEGIN<-o><", bins[si], ".new><",
|
||||
works[si], "/", rootaction, ".a.new>");
|
||||
i = 0;
|
||||
for (i < packagecount) {
|
||||
expectedlink = strings.concat(expectedlink, "<", works[si], "/",
|
||||
boundarypkgname(i), ".a>");
|
||||
boundarypkgname(i), ".a.new>");
|
||||
i += 1;
|
||||
};
|
||||
expectedlink = strings.concat(expectedlink, "<", repo(),
|
||||
"/out/bin/../lib/libwwrt.a>\n");
|
||||
assert(same(ltrace, expectedlink));
|
||||
assert(same(readfile(strings.concat(works[si], "/", rootaction,
|
||||
".unit.ww")),
|
||||
let rootunit: str = readfile(strings.concat(works[si], "/", rootaction,
|
||||
".unit.ww"));
|
||||
assert(strings.hasprefix(rootunit,
|
||||
strings.concat("//ww:module-reset target\n", roota,
|
||||
"\n//ww:module-reset target\n", rootz, "\n")));
|
||||
assert(occurrences(rootunit, "//ww:direct-export p") == packagecount);
|
||||
let rootassemble: str = strings.concat("BEGIN<-o><", works[si], "/",
|
||||
rootaction, ".o.new><", works[si], "/", rootaction, ".s.new>");
|
||||
assert(same(linecontaining(atrace,
|
||||
strings.concat("/", rootaction, ".o.new")), rootassemble));
|
||||
let dispatchassemble: str = strings.concat("BEGIN<-o><", works[si],
|
||||
"/", rootaction, ".init.o.new><", works[si], "/", rootaction,
|
||||
".init.s.new>");
|
||||
assert(same(linecontaining(atrace,
|
||||
strings.concat("/", rootaction, ".init.o.new")), dispatchassemble));
|
||||
|
||||
// Repeating the same semantic request in the persistent work root may
|
||||
// relink the requested binary, but must not compile or assemble any action.
|
||||
@@ -2711,16 +2739,21 @@ fn hexbytes(value: str) str = {
|
||||
let adelta: str = strings.sub(chainatrace, chainabefore, chainatrace.len);
|
||||
let ldelta: str = strings.sub(chainltrace, chainlbefore, chainltrace.len);
|
||||
assert(occurrences(cdelta, "\n") == 1);
|
||||
assert(occurrences(adelta, "\n") == 1);
|
||||
assert(occurrences(adelta, "\n") == 2);
|
||||
assert(occurrences(ldelta, "\n") == 1);
|
||||
assert(same(cdelta, strings.concat("BEGIN<--entry><-c><--import><p000><",
|
||||
assert(same(cdelta, strings.concat(
|
||||
"BEGIN<--entry><--package-init-symbol><__ww..pkg.p.",
|
||||
chainaction, ".v0.r0.init><--init-dispatch-symbol>",
|
||||
"<__ww..dispatch><-c><--import><p000><",
|
||||
works[si], "/p000.wwi><-I><", works[si], "/", chainaction,
|
||||
".wwi.new><-o><", works[si], "/", chainaction, ".s.new><",
|
||||
works[si], "/", chainaction, ".unit.new>\n")));
|
||||
assert(same(adelta, strings.concat("BEGIN<-o><", works[si], "/",
|
||||
chainaction, ".o.new><", works[si], "/", chainaction, ".s.new>\n")));
|
||||
chainaction, ".o.new><", works[si], "/", chainaction, ".s.new>\n",
|
||||
"BEGIN<-o><", works[si], "/", chainaction, ".init.o.new><",
|
||||
works[si], "/", chainaction, ".init.s.new>\n")));
|
||||
let expectedchainlink: str = strings.concat("BEGIN<-o><", chainbins[si],
|
||||
"><", works[si], "/", chainaction, ".a>");
|
||||
".new><", works[si], "/", chainaction, ".a.new>");
|
||||
i = 0;
|
||||
for (i < packagecount) {
|
||||
expectedchainlink = strings.concat(expectedchainlink, "<", works[si],
|
||||
@@ -2731,9 +2764,11 @@ fn hexbytes(value: str) str = {
|
||||
"/out/bin/../lib/libwwrt.a>\n");
|
||||
assert(same(ldelta, expectedchainlink));
|
||||
assert(!has(ldelta, ".wwi>"));
|
||||
assert(same(readfile(strings.concat(works[si], "/", chainaction,
|
||||
".unit.ww")), strings.concat("//ww:module-reset chain\n",
|
||||
chainsource, "\n")));
|
||||
let chainunit: str = readfile(strings.concat(works[si], "/", chainaction,
|
||||
".unit.ww"));
|
||||
assert(strings.hasprefix(chainunit, strings.concat(
|
||||
"//ww:module-reset chain\n", chainsource, "\n")));
|
||||
assert(has(chainunit, "//ww:direct-export p000 "));
|
||||
let chainrun: []str = [chainbins[si]];
|
||||
runcommand(root, strings.concat("boundary-chain-run-", stages[si]),
|
||||
chainrun, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
@@ -3308,26 +3343,20 @@ fn hexbytes(value: str) str = {
|
||||
runcommand(root, strings.concat("multidir-failure-", stages[i]), av,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stdout, "alpha_same_survives ... ok\n"));
|
||||
assert(has(out.stdout, "beta_same_survives ... ok\n"));
|
||||
assert(has(out.stdout, "beta_external_survives ... ok\n"));
|
||||
assert(has(out.stdout, strings.concat("ok ", alpha,
|
||||
" [alpha, same-package]\n")));
|
||||
assert(has(out.stdout, strings.concat("ok ", beta,
|
||||
" [beta, same-package]\n")));
|
||||
assert(has(out.stdout, strings.concat("ok ", beta,
|
||||
" [beta_test, external]\n")));
|
||||
assert(!has(out.stdout, "alpha_external_fails ..."));
|
||||
assert(out.stdout.len == 0);
|
||||
assert(has(out.stderr, "has no exported declaration 'hidden'"));
|
||||
assert(has(out.stderr, strings.concat("FAIL ", alpha,
|
||||
" [alpha] (build exit 1)\n")));
|
||||
assert(has(out.stderr, strings.concat("FAIL ", alpha,
|
||||
" [alpha_test] (build exit 1)\n")));
|
||||
assert(!has(out.stderr, strings.concat("FAIL ", alpha,
|
||||
" [alpha]")));
|
||||
assert(!has(out.stderr, strings.concat("FAIL ", beta, " [")));
|
||||
let alphapos: i32 = pos(out.stdout, strings.concat("ok ", alpha,
|
||||
" [alpha, same-package]\n"));
|
||||
let betapos: i32 = pos(out.stdout, strings.concat("ok ", beta,
|
||||
" [beta, same-package]\n"));
|
||||
assert(has(out.stderr, strings.concat("FAIL ", beta,
|
||||
" [beta] (build exit 1)\n")));
|
||||
assert(has(out.stderr, strings.concat("FAIL ", beta,
|
||||
" [beta_test] (build exit 1)\n")));
|
||||
let alphapos: i32 = pos(out.stderr, strings.concat("FAIL ", alpha,
|
||||
" [alpha] (build exit 1)\n"));
|
||||
let betapos: i32 = pos(out.stderr, strings.concat("FAIL ", beta,
|
||||
" [beta] (build exit 1)\n"));
|
||||
assert(alphapos >= 0 && alphapos < betapos);
|
||||
diagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
|
||||
if (i == 0) { referenceout = strings.dup(out.stdout); }
|
||||
@@ -3338,8 +3367,8 @@ fn hexbytes(value: str) str = {
|
||||
clean(root);
|
||||
};
|
||||
|
||||
// One failing root is a product failure, not permission for the shared build
|
||||
// request to suppress an independently compilable sibling root.
|
||||
// Roots remain independently diagnosed and may be staged in parallel, but one
|
||||
// failing product rejects publication and execution of the entire request.
|
||||
@test fn sibling_test_variant_failures_are_isolated() void = {
|
||||
let root: str = fresh();
|
||||
let badexternal: str = strings.concat(root, "/badexternal");
|
||||
@@ -3380,15 +3409,15 @@ fn hexbytes(value: str) str = {
|
||||
runcommand(root, strings.concat("isolated-external-", tags[i]),
|
||||
externalav, (120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stdout, "valid_same_runs ... ok\n"));
|
||||
assert(has(out.stdout, "[badexternal, same-package]\n"));
|
||||
assert(out.stdout.len == 0);
|
||||
assert(has(out.stderr,
|
||||
"has no exported declaration 'hidden'"));
|
||||
assert(has(out.stderr,
|
||||
strings.concat("FAIL ", badexternal,
|
||||
" [badexternal] (build exit 1)\n")));
|
||||
assert(has(out.stderr,
|
||||
strings.concat("FAIL ", badexternal,
|
||||
" [badexternal_test] (build exit 1)\n")));
|
||||
assert(!has(out.stderr, strings.concat("FAIL ", badexternal,
|
||||
" [badexternal]")));
|
||||
externaldiagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
|
||||
|
||||
let sameav: []str = [driver(stages[i]), "test", "-I", root,
|
||||
@@ -3396,23 +3425,20 @@ fn hexbytes(value: str) str = {
|
||||
runcommand(root, strings.concat("isolated-same-", tags[i]), sameav,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stdout, "valid_external_runs ... ok\n"));
|
||||
assert(has(out.stdout, "[badsame_test, external]\n"));
|
||||
assert(out.stdout.len == 0);
|
||||
assert(has(out.stderr, "undefined: missing"));
|
||||
assert(has(out.stderr, strings.concat("FAIL ", badsame,
|
||||
" [badsame] (build exit 1)\n")));
|
||||
assert(!has(out.stderr, strings.concat("FAIL ", badsame,
|
||||
" [badsame_test]")));
|
||||
assert(has(out.stderr, strings.concat("FAIL ", badsame,
|
||||
" [badsame_test] (build exit 1)\n")));
|
||||
samediagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
|
||||
i += 1;
|
||||
};
|
||||
assert(same(externaldiagnostics[0], externaldiagnostics[1]));
|
||||
assert(same(samediagnostics[0], samediagnostics[1]));
|
||||
|
||||
// A first persistent union pass may contain a root-local compiler failure.
|
||||
// Its successfully committed actions still become reusable: only the
|
||||
// uncommitted failing root is compiled again on the next request in both
|
||||
// driver stages.
|
||||
// A persistent request is one publication transaction. A rejection leaves
|
||||
// no reusable generation, so every staged action is reconsidered next time.
|
||||
let warmroot: str = strings.concat(root, "/warm-partial");
|
||||
assert(os.mkdir(warmroot, 448i32) == 0);
|
||||
let trace: str = strings.concat(root, "/warm-partial.trace");
|
||||
@@ -3452,9 +3478,14 @@ fn hexbytes(value: str) str = {
|
||||
expectexit(&out, 1);
|
||||
let secondtrace: str = readfile(trace);
|
||||
assert(occurrences(secondtrace,
|
||||
"/badexternal-internal-test.unit.new") == 1);
|
||||
"/badexternal-internal-test.unit.new") == 2);
|
||||
assert(occurrences(secondtrace,
|
||||
"/badexternal_test-external-test.unit.new") == 2);
|
||||
assert(!os.exists(strings.concat(warmroot,
|
||||
"/badexternal-internal-test.unit.ww")));
|
||||
assert(!os.exists(strings.concat(warmroot,
|
||||
"/badexternal_test-external-test.unit.ww")));
|
||||
assert(!os.exists(strings.concat(warmroot, "/.wwtool.stamp")));
|
||||
|
||||
let wwtracebin: str = strings.concat(repo(), "/out/partial-trace-",
|
||||
workescape(root));
|
||||
@@ -3502,9 +3533,14 @@ fn hexbytes(value: str) str = {
|
||||
expectexit(&out, 1);
|
||||
let wwsecond: str = readfile(wwtrace);
|
||||
assert(occurrences(wwsecond,
|
||||
"/badexternal-internal-test.unit.new") == 1);
|
||||
"/badexternal-internal-test.unit.new") == 2);
|
||||
assert(occurrences(wwsecond,
|
||||
"/badexternal_test-external-test.unit.new") == 2);
|
||||
assert(!os.exists(strings.concat(wwwarmroot,
|
||||
"/badexternal-internal-test.unit.ww")));
|
||||
assert(!os.exists(strings.concat(wwwarmroot,
|
||||
"/badexternal_test-external-test.unit.ww")));
|
||||
assert(!os.exists(strings.concat(wwwarmroot, "/.wwtool.stamp")));
|
||||
clean(wwtracebin);
|
||||
clean(root);
|
||||
};
|
||||
@@ -3850,8 +3886,10 @@ fn hexbytes(value: str) str = {
|
||||
let wantsecret: str = strings.concat(
|
||||
"//ww:module-reset domain.internal.secret\n", secreta,
|
||||
"\n//ww:module-reset domain.internal.secret\n", secretz, "\n");
|
||||
assert(same(readfile(strings.concat(works[si],
|
||||
"/domain.internal.secret.unit.ww")), wantsecret));
|
||||
let secretunit: str = readfile(strings.concat(works[si],
|
||||
"/domain.internal.secret.unit.ww"));
|
||||
assert(strings.hasprefix(secretunit, wantsecret));
|
||||
assert(has(secretunit, "//ww:direct-export domain.leaf "));
|
||||
let ai: i32 = 0;
|
||||
for (ai < artifacts.len) {
|
||||
let xi: i32 = 0;
|
||||
@@ -3869,8 +3907,13 @@ fn hexbytes(value: str) str = {
|
||||
let atrace: str = readfile(assemblertraces[si]);
|
||||
let ltrace: str = readfile(linkertraces[si]);
|
||||
assert(occurrences(ctrace, "\n") == 3);
|
||||
assert(occurrences(atrace, "\n") == 3);
|
||||
assert(occurrences(atrace, "\n") == 4);
|
||||
assert(occurrences(ltrace, "\n") == 1);
|
||||
let dispatchline: str = strings.concat("BEGIN<-o><", works[si],
|
||||
"/domain.client.init.o.new><", works[si],
|
||||
"/domain.client.init.s.new>");
|
||||
assert(same(linecontaining(atrace, "/domain.client.init.o.new"),
|
||||
dispatchline));
|
||||
let secretline: str = linecontaining(ctrace,
|
||||
"domain.internal.secret.unit.new");
|
||||
assert(occurrences(secretline, "domain.leaf.wwi") == 1);
|
||||
@@ -4420,7 +4463,16 @@ fn hexbytes(value: str) str = {
|
||||
for (ui < unitartifacts.len) {
|
||||
let unit: str = readfile(strings.concat(work, unitartifacts[ui],
|
||||
".unit.ww"));
|
||||
assert(same(unit, wantunits[ui]));
|
||||
assert(strings.hasprefix(unit, wantunits[ui]));
|
||||
if (ui == 1 || ui == 2) {
|
||||
assert(has(unit, strings.concat("//ww:direct-export ",
|
||||
baseidentity, " ")));
|
||||
} else { if (ui == 3) {
|
||||
assert(has(unit, strings.concat("//ww:direct-export ",
|
||||
leftidentity, " ")));
|
||||
assert(has(unit, strings.concat("//ww:direct-export ",
|
||||
rightidentity, " ")));
|
||||
}; };
|
||||
assert(!has(unit, "//ww:module "));
|
||||
if (si == 0) { referenceunits[ui] = strings.dup(unit); }
|
||||
else { assert(same(referenceunits[ui], unit)); };
|
||||
@@ -4458,23 +4510,32 @@ fn hexbytes(value: str) str = {
|
||||
let atrace: str = readfile(assemblertrace);
|
||||
let ltrace: str = readfile(linkertrace);
|
||||
assert(occurrences(ctrace, "\n") == 4);
|
||||
let baseline: str = strings.concat("BEGIN<-c><-I><", work,
|
||||
let baseline: str = strings.concat(
|
||||
"BEGIN<--package-init-symbol><__ww..pkg.p.", baseidentity,
|
||||
".v0.r0.init><-c><-I><", work,
|
||||
artifacts[0], ".wwi><-o><", work,
|
||||
artifacts[0], ".s><", work,
|
||||
artifacts[0], ".unit.ww>");
|
||||
let leftline: str = strings.concat("BEGIN<-c><--import>",
|
||||
let leftline: str = strings.concat(
|
||||
"BEGIN<--package-init-symbol><__ww..pkg.p.", leftidentity,
|
||||
".v0.r0.init><-c><--import>",
|
||||
"<", baseidentity, "><", work,
|
||||
artifacts[0], ".wwi><-I><", work,
|
||||
artifacts[1], ".wwi><-o><", work,
|
||||
artifacts[1], ".s><", work,
|
||||
artifacts[1], ".unit.ww>");
|
||||
let rightline: str = strings.concat("BEGIN<-c><--import>",
|
||||
let rightline: str = strings.concat(
|
||||
"BEGIN<--package-init-symbol><__ww..pkg.p.", rightidentity,
|
||||
".v0.r0.init><-c><--import>",
|
||||
"<", baseidentity, "><", work,
|
||||
artifacts[0], ".wwi><-I><", work,
|
||||
artifacts[2], ".wwi><-o><", work,
|
||||
artifacts[2], ".s><", work,
|
||||
artifacts[2], ".unit.ww>");
|
||||
let rootline: str = strings.concat("BEGIN<--entry><-c><--import>",
|
||||
let rootline: str = strings.concat(
|
||||
"BEGIN<--entry><--package-init-symbol><__ww..pkg.p.",
|
||||
rootidentity, ".v0.r0.init><--init-dispatch-symbol>",
|
||||
"<__ww..dispatch><-c><--import>",
|
||||
"<", leftidentity, "><", work,
|
||||
artifacts[1], ".wwi><--import>",
|
||||
"<", rightidentity, "><", work,
|
||||
@@ -4520,7 +4581,7 @@ fn hexbytes(value: str) str = {
|
||||
expectexit(&out, 1);
|
||||
assert(same(out.stderr, strings.concat("w6c: import ", leftidentity,
|
||||
": export owner mismatch in ", work, artifacts[0], ".wwi\n")));
|
||||
assert(occurrences(atrace, "\n") == 4);
|
||||
assert(occurrences(atrace, "\n") == 5);
|
||||
ai = 0;
|
||||
for (ai < artifacts.len) {
|
||||
let assemblerline: str = strings.concat("BEGIN<-o><", work,
|
||||
@@ -4529,8 +4590,12 @@ fn hexbytes(value: str) str = {
|
||||
artifacts[ai], ".o")), assemblerline));
|
||||
ai += 1;
|
||||
};
|
||||
let dispatcherline: str = strings.concat("BEGIN<-o><", work,
|
||||
artifacts[3], ".init.o><", work, artifacts[3], ".init.s>");
|
||||
assert(same(linecontaining(atrace, strings.concat(work,
|
||||
artifacts[3], ".init.o")), dispatcherline));
|
||||
assert(occurrences(ltrace, "\n") == 1);
|
||||
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
|
||||
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, ".new><", work,
|
||||
artifacts[3], ".a>")));
|
||||
ai = 0;
|
||||
for (ai < artifacts.len) {
|
||||
@@ -4842,17 +4907,17 @@ fn hexbytes(value: str) str = {
|
||||
let externalline: str = linecontaining(ctrace,
|
||||
strings.concat(artifacts[2], ".unit.new"));
|
||||
assert(has(externalline, strings.concat("<--import><", commandid,
|
||||
"><", work, artifacts[0], ".wwi>")));
|
||||
"><", work, artifacts[0], ".wwi.new>")));
|
||||
let internalmainline: str = linecontaining(ctrace,
|
||||
strings.concat(artifacts[3], ".unit.new"));
|
||||
let externalmainline: str = linecontaining(ctrace,
|
||||
strings.concat(artifacts[4], ".unit.new"));
|
||||
assert(has(internalmainline, strings.concat("<--import><", internalid,
|
||||
"><", work, artifacts[1], ".wwi>")));
|
||||
"><", work, artifacts[1], ".wwi.new>")));
|
||||
assert(has(internalmainline, strings.concat(
|
||||
"<--test-target-package><", internalid, ">")));
|
||||
assert(has(externalmainline, strings.concat("<--import><", externalid,
|
||||
"><", work, artifacts[2], ".wwi>")));
|
||||
"><", work, artifacts[2], ".wwi.new>")));
|
||||
assert(has(externalmainline, strings.concat(
|
||||
"<--test-target-package><", externalid, ">")));
|
||||
assert(occurrences(ctrace, strings.concat("<", work, artifacts[0],
|
||||
@@ -5470,27 +5535,37 @@ fn hexbytes(value: str) str = {
|
||||
let commandatrace: str = readfile(commandassemblertraces[commandstage]);
|
||||
let commandltrace: str = readfile(commandlinkertraces[commandstage]);
|
||||
assert(occurrences(commandctrace, "\n") == 3);
|
||||
assert(occurrences(commandatrace, "\n") == 3);
|
||||
assert(occurrences(commandatrace, "\n") == 5);
|
||||
assert(occurrences(commandltrace, "\n") == 2);
|
||||
let commandalphacompile: str = linecontaining(commandctrace,
|
||||
strings.concat(commandalphaid, ".unit.new"));
|
||||
assert(occurrences(commandalphacompile, strings.concat(
|
||||
"<--import><library><", commandwork, "library.wwi>")) == 1);
|
||||
"<--import><library><", commandwork, "library.wwi.new>")) == 1);
|
||||
assert(!has(commandalphacompile, "cmd-zeta.wwi"));
|
||||
let alphaassembly: str = strings.concat("BEGIN<-o><", commandwork,
|
||||
commandalphaid, ".init.o.new><", commandwork, commandalphaid,
|
||||
".init.s.new>");
|
||||
let zetaassembly: str = strings.concat("BEGIN<-o><", commandwork,
|
||||
commandzetaid, ".init.o.new><", commandwork, commandzetaid,
|
||||
".init.s.new>");
|
||||
assert(same(linecontaining(commandatrace, strings.concat(commandalphaid,
|
||||
".init.o.new")), alphaassembly));
|
||||
assert(same(linecontaining(commandatrace, strings.concat(commandzetaid,
|
||||
".init.o.new")), zetaassembly));
|
||||
let commandalphalink: str = linecontaining(commandltrace,
|
||||
strings.concat("<-o><", commandbins[commandstage], "/cmd-alpha>"));
|
||||
strings.concat("<-o><", commandbins[commandstage], "/cmd-alpha.new>"));
|
||||
let commandzetalink: str = linecontaining(commandltrace,
|
||||
strings.concat("<-o><", commandbins[commandstage], "/cmd-zeta>"));
|
||||
strings.concat("<-o><", commandbins[commandstage], "/cmd-zeta.new>"));
|
||||
assert(occurrences(commandalphalink, strings.concat("<", commandwork,
|
||||
commandalphaid, ".a>")) == 1);
|
||||
commandalphaid, ".a.new>")) == 1);
|
||||
assert(occurrences(commandalphalink, strings.concat("<", commandwork,
|
||||
"library.a>")) == 1);
|
||||
"library.a.new>")) == 1);
|
||||
assert(!has(commandalphalink, strings.concat(commandzetaid, ".a")));
|
||||
assert(!has(commandalphalink, ".wwi>"));
|
||||
assert(has(commandalphalink, strings.concat("<-L><", repo(),
|
||||
"/out/lib><-l><wcc>")));
|
||||
assert(has(commandzetalink, strings.concat("<", commandwork,
|
||||
commandzetaid, ".a>")));
|
||||
commandzetaid, ".a.new>")));
|
||||
assert(!has(commandzetalink, "library.a"));
|
||||
assert(!has(commandzetalink, ".wwi>"));
|
||||
let normalizedcommandcompiler: str = normalizedtrace(commandctrace,
|
||||
@@ -7276,8 +7351,10 @@ fn runtimepath(relative: str) str = {
|
||||
"//ww:module-reset ", expanded, "\n", neara, "\n",
|
||||
"//ww:module-reset ", expanded, "\n", nearz, "\n",
|
||||
"//ww:vendor-dir ", hexbytes(nearest), "\n");
|
||||
assert(same(readfile(strings.concat(works[si], "/", expanded,
|
||||
".unit.ww")), wantnear));
|
||||
let nearunit: str = readfile(strings.concat(works[si], "/", expanded,
|
||||
".unit.ww"));
|
||||
assert(strings.hasprefix(nearunit, wantnear));
|
||||
assert(has(nearunit, "//ww:direct-export lib.leaf "));
|
||||
let clientunit: str = readfile(strings.concat(works[si],
|
||||
"/domain.app.client.unit.ww"));
|
||||
assert(has(clientunit, strings.concat("//ww:import-map lib.math ",
|
||||
@@ -7299,8 +7376,14 @@ fn runtimepath(relative: str) str = {
|
||||
let atrace: str = readfile(assemblertraces[si]);
|
||||
let ltrace: str = readfile(linkertraces[si]);
|
||||
assert(occurrences(ctrace, "\n") == 3);
|
||||
assert(occurrences(atrace, "\n") == 3);
|
||||
assert(occurrences(atrace, "\n") == 4);
|
||||
assert(occurrences(ltrace, "\n") == 1);
|
||||
assert(has(ltrace, strings.concat("BEGIN<-o><", bins[si], ".new>")));
|
||||
let dispatchline: str = strings.concat("BEGIN<-o><", works[si],
|
||||
"/domain.app.client.init.o.new><", works[si],
|
||||
"/domain.app.client.init.s.new>");
|
||||
assert(same(linecontaining(atrace,
|
||||
"/domain.app.client.init.o.new"), dispatchline));
|
||||
let nearline: str = linecontaining(ctrace,
|
||||
strings.concat(expanded, ".unit.new"));
|
||||
assert(occurrences(nearline, "<--import><lib.leaf>") == 1);
|
||||
@@ -7308,16 +7391,16 @@ fn runtimepath(relative: str) str = {
|
||||
let clientline: str = linecontaining(ctrace,
|
||||
"domain.app.client.unit.new");
|
||||
assert(occurrences(clientline, strings.concat("<--import><", expanded,
|
||||
"><", works[si], "/", expanded, ".wwi>")) == 1);
|
||||
"><", works[si], "/", expanded, ".wwi.new>")) == 1);
|
||||
assert(occurrences(clientline, strings.concat(
|
||||
"<--import-map><lib.math><", expanded, ">")) == 1);
|
||||
assert(!has(clientline, "lib.leaf.wwi"));
|
||||
assert(occurrences(ltrace, strings.concat("<", works[si],
|
||||
"/domain.app.client.a>")) == 1);
|
||||
"/domain.app.client.a.new>")) == 1);
|
||||
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
|
||||
expanded, ".a>")) == 1);
|
||||
expanded, ".a.new>")) == 1);
|
||||
assert(occurrences(ltrace, strings.concat("<", works[si],
|
||||
"/lib.leaf.a>")) == 1);
|
||||
"/lib.leaf.a.new>")) == 1);
|
||||
assert(!has(ltrace, ".wwi>"));
|
||||
let nc: str = normalizedtrace(ctrace,
|
||||
strings.concat(works[si], "/"), bins[si]);
|
||||
@@ -7732,9 +7815,9 @@ fn runtimepath(relative: str) str = {
|
||||
let externalline: str = linecontaining(testtrace,
|
||||
"domain.app.testclient_test-external-test.unit.new");
|
||||
assert(occurrences(internalline, strings.concat("<--import><", expanded,
|
||||
"><", testwork, expanded, ".wwi>")) == 1);
|
||||
"><", testwork, expanded, ".wwi.new>")) == 1);
|
||||
assert(occurrences(externalline, strings.concat("<--import><", expanded,
|
||||
"><", testwork, expanded, ".wwi>")) == 1);
|
||||
"><", testwork, expanded, ".wwi.new>")) == 1);
|
||||
assert(occurrences(internalline, strings.concat(
|
||||
"<--import-map><lib.math><", expanded, ">")) == 1);
|
||||
assert(occurrences(externalline, strings.concat(
|
||||
@@ -8029,15 +8112,7 @@ fn runtimepath(relative: str) str = {
|
||||
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||
"\"$WW_NAME_COMPILER_TRACE\"; done\n",
|
||||
"printf '\\n' >> \"$WW_NAME_COMPILER_TRACE\"\n",
|
||||
"\"$WW_NAME_REAL_COMPILER\" \"$@\"\n",
|
||||
"status=$?\n",
|
||||
"if [ \"$status\" -eq 0 ] && ",
|
||||
"[ -n \"$WW_COMMIT_BLOCK_STAMP\" ]; then\n",
|
||||
" mv -- \"$WW_COMMIT_BLOCK_STAMP\" ",
|
||||
"\"$WW_COMMIT_BLOCK_STAMP.saved\" || exit 97\n",
|
||||
" mkdir -- \"$WW_COMMIT_BLOCK_STAMP\" || exit 98\n",
|
||||
"fi\n",
|
||||
"exit \"$status\"\n"));
|
||||
"exec \"$WW_NAME_REAL_COMPILER\" \"$@\"\n"));
|
||||
|
||||
let stages: []str = ["ww", "ww_ww"];
|
||||
let compilers: []str = ["w6c", "w6c_ww"];
|
||||
@@ -8059,8 +8134,6 @@ fn runtimepath(relative: str) str = {
|
||||
strings.concat(root, "/ww-commit-work")];
|
||||
let commitcoldbins: []str = [strings.concat(root, "/c-commit-cold"),
|
||||
strings.concat(root, "/ww-commit-cold")];
|
||||
let commitblockbins: []str = [strings.concat(root, "/c-commit-block"),
|
||||
strings.concat(root, "/ww-commit-block")];
|
||||
let commitrejectbins: []str = [strings.concat(root, "/c-commit-reject"),
|
||||
strings.concat(root, "/ww-commit-reject")];
|
||||
let commitfixedbins: []str = [strings.concat(root, "/c-commit-fixed"),
|
||||
@@ -8087,8 +8160,6 @@ fn runtimepath(relative: str) str = {
|
||||
let repeatedtraceref: str = "";
|
||||
let changedtraceref: str = "";
|
||||
let aliastraceref: str = "";
|
||||
let commitfailref: str = "";
|
||||
let commitpreflightref: str = "";
|
||||
let commitbindingref: str = "";
|
||||
let commitbinref: str = "";
|
||||
let initialwwiref: str = "";
|
||||
@@ -8115,9 +8186,7 @@ fn runtimepath(relative: str) str = {
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_NAME_COMPILER_TRACE=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_NAME_REAL_COMPILER=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_COMMIT_BLOCK_STAMP=")) {
|
||||
"WW_NAME_REAL_COMPILER=")) {
|
||||
append(env, baseenv[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
@@ -8168,11 +8237,10 @@ fn runtimepath(relative: str) str = {
|
||||
(30i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 42);
|
||||
|
||||
// A failed multi-file artifact rename may have published a new
|
||||
// interface before a later rename fails. It invalidates every old unit
|
||||
// voucher and the workdir identity, so the next request must reconsider
|
||||
// an importer even when the regenerated dependency export now compares
|
||||
// equal to that partially published interface.
|
||||
// The package and command form one publication transaction. A changed
|
||||
// declared name is visible to the importer through the staged .wwi, but
|
||||
// its resulting semantic rejection must preserve the complete prior
|
||||
// generation and force the next request to reconsider both actions.
|
||||
let commitcoldav: []str = [driver(stages[si]), "build", "-w",
|
||||
commitworks[si], "-I", source, "-o", commitcoldbins[si], commitapp];
|
||||
runcommandenv(root, strings.concat("name-commit-cold-", stages[si]),
|
||||
@@ -8182,96 +8250,72 @@ fn runtimepath(relative: str) str = {
|
||||
runcommand(root, strings.concat("name-commit-cold-run-", stages[si]),
|
||||
commitrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 42);
|
||||
let commitpaths: []str = ["/.wwtool.ww", "/.wwtool.w6c",
|
||||
"/.wwtool.w6a", "/.wwtool.stamp", "/commit.codec.unit.ww",
|
||||
"/commit.codec.wwi", "/commit.codec.s", "/commit.codec.o",
|
||||
"/commit.codec.a", "/cmd.commit.unit.ww", "/cmd.commit.wwi",
|
||||
"/cmd.commit.s", "/cmd.commit.o", "/cmd.commit.a",
|
||||
"/cmd.commit.init.unit.ww", "/cmd.commit.init.s",
|
||||
"/cmd.commit.init.o"];
|
||||
let commitsnapshots: []str = alloc([], commitpaths.len: u64)!;
|
||||
let cpi: i32 = 0;
|
||||
for (cpi < commitpaths.len) {
|
||||
append(commitsnapshots, readfile(strings.concat(commitworks[si],
|
||||
commitpaths[cpi])));
|
||||
cpi += 1;
|
||||
};
|
||||
let commitcoldbytes: str = readfile(commitcoldbins[si]);
|
||||
rewritefile(commitcodecfile, cablebody);
|
||||
let commitstamp: str = strings.concat(commitworks[si],
|
||||
"/.wwtool.stamp");
|
||||
let savedstamp: str = strings.concat(commitstamp, ".saved");
|
||||
let oldcommitwwi: str = readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.wwi"));
|
||||
let oldcommits: str = readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.s"));
|
||||
let oldcommito: str = readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.o"));
|
||||
let oldcommita: str = readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.a"));
|
||||
let blockenv: []str = alloc([], (env.len + 1): u64)!;
|
||||
let bei: i32 = 0;
|
||||
for (bei < env.len) { append(blockenv, env[bei]); bei += 1; };
|
||||
append(blockenv, strings.concat("WW_COMMIT_BLOCK_STAMP=", commitstamp));
|
||||
let commitblockav: []str = [driver(stages[si]), "build", "-w",
|
||||
commitworks[si], "-I", source, "-o", commitblockbins[si],
|
||||
commitapp];
|
||||
runcommandenv(root, strings.concat("name-commit-preflight-", stages[si]),
|
||||
commitblockav, blockenv,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "ww: cannot invalidate package workdir\n"));
|
||||
if (si == 0) { commitpreflightref = strings.dup(out.stderr); }
|
||||
else { assert(same(commitpreflightref, out.stderr)); };
|
||||
assert(same(oldcommitwwi, readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.wwi"))));
|
||||
assert(same(oldcommits, readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.s"))));
|
||||
assert(same(oldcommito, readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.o"))));
|
||||
assert(same(oldcommita, readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.a"))));
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/commit.codec.unit.ww")));
|
||||
assert(!os.exists(commitblockbins[si]));
|
||||
assert(os.rmdir(commitstamp) == 0);
|
||||
assert(os.rename(savedstamp, commitstamp) == 0);
|
||||
|
||||
// With the stamp preflight restored, force a later artifact rename to
|
||||
// fail after the changed interface has already been published.
|
||||
let blockedasm: str = strings.concat(commitworks[si],
|
||||
"/commit.codec.s");
|
||||
assert(os.remove(blockedasm) == 0);
|
||||
assert(os.mkdir(blockedasm, 448i32) == 0);
|
||||
let commitrejectav: []str = [driver(stages[si]), "build", "-w",
|
||||
commitworks[si], "-I", source, "-o", commitrejectbins[si],
|
||||
commitapp];
|
||||
runcommandenv(root, strings.concat("name-commit-partial-", stages[si]),
|
||||
commitrejectav, env,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "ww: cannot commit commit.codec\n"));
|
||||
if (si == 0) { commitfailref = strings.dup(out.stderr); }
|
||||
else { assert(same(commitfailref, out.stderr)); };
|
||||
assert(has(readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.wwi")),
|
||||
"//ww:module commit.codec\npackage cable;\n"));
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/commit.codec.unit.ww")));
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/cmd.commit.unit.ww")));
|
||||
assert(!os.exists(strings.concat(commitworks[si], "/.wwtool.stamp")));
|
||||
let partialsuffixes: []str = [".unit.new", ".wwi.new", ".s.new",
|
||||
".o.new", ".a.new"];
|
||||
let psi: i32 = 0;
|
||||
for (psi < partialsuffixes.len) {
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/commit.codec", partialsuffixes[psi])));
|
||||
psi += 1;
|
||||
".o.new", ".a.new", ".init.unit.new", ".init.s.new",
|
||||
".init.o.new"];
|
||||
let rejectedactions: []str = ["commit.codec", "cmd.commit"];
|
||||
let attemptlabels: []str = ["0", "1"];
|
||||
let attempt: i32 = 0;
|
||||
for (attempt < 2) {
|
||||
rewritefile(traces[si], "");
|
||||
runcommandenv(root, strings.concat("name-commit-reject-",
|
||||
stages[si], "-", attemptlabels[attempt]),
|
||||
commitrejectav, env,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "imported as cable and not used"));
|
||||
assert(has(out.stderr, "undefined: wire"));
|
||||
assert(has(out.stderr, "ww: w6c failed for cmd.commit\n"));
|
||||
let ncommitbinding: str = normalizedtrace(out.stderr,
|
||||
strings.concat(commitworks[si], "/"), commitrejectbins[si]);
|
||||
if (si == 0 && attempt == 0) {
|
||||
commitbindingref = strings.dup(ncommitbinding);
|
||||
} else { assert(same(commitbindingref, ncommitbinding)); };
|
||||
let rejecttrace: str = readfile(traces[si]);
|
||||
assert(occurrences(rejecttrace,
|
||||
"/commit.codec.unit.new") == 1);
|
||||
assert(occurrences(rejecttrace,
|
||||
"/cmd.commit.unit.new") == 1);
|
||||
cpi = 0;
|
||||
for (cpi < commitpaths.len) {
|
||||
assert(same(commitsnapshots[cpi], readfile(strings.concat(
|
||||
commitworks[si], commitpaths[cpi]))));
|
||||
cpi += 1;
|
||||
};
|
||||
assert(same(commitcoldbytes, readfile(commitcoldbins[si])));
|
||||
let rai: i32 = 0;
|
||||
for (rai < rejectedactions.len) {
|
||||
let psi: i32 = 0;
|
||||
for (psi < partialsuffixes.len) {
|
||||
assert(!os.exists(strings.concat(commitworks[si], "/",
|
||||
rejectedactions[rai], partialsuffixes[psi])));
|
||||
psi += 1;
|
||||
};
|
||||
rai += 1;
|
||||
};
|
||||
assert(!os.exists(commitrejectbins[si]));
|
||||
assert(!os.exists(strings.concat(commitrejectbins[si], ".new")));
|
||||
attempt += 1;
|
||||
};
|
||||
assert(!os.exists(commitrejectbins[si]));
|
||||
assert(os.rmdir(blockedasm) == 0);
|
||||
rewritefile(traces[si], "");
|
||||
runcommandenv(root, strings.concat("name-commit-reconsider-", stages[si]),
|
||||
commitrejectav, env,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "undefined: wire"));
|
||||
let ncommitbinding: str = normalizedtrace(out.stderr,
|
||||
strings.concat(commitworks[si], "/"), commitrejectbins[si]);
|
||||
if (si == 0) { commitbindingref = strings.dup(ncommitbinding); }
|
||||
else { assert(same(commitbindingref, ncommitbinding)); };
|
||||
assert(has(readfile(traces[si]), "/cmd.commit.unit.new"));
|
||||
assert(os.exists(strings.concat(commitworks[si],
|
||||
"/commit.codec.unit.ww")));
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/cmd.commit.unit.ww")));
|
||||
assert(!os.exists(commitrejectbins[si]));
|
||||
rewritefile(commitappfile, strings.concat(
|
||||
"package main;\nimport commit.codec;\n",
|
||||
"fn main() i32 = { return cable.value(); };\n"));
|
||||
@@ -8285,6 +8329,10 @@ fn runtimepath(relative: str) str = {
|
||||
runcommand(root, strings.concat("name-commit-fixed-run-", stages[si]),
|
||||
commitfixedrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 42);
|
||||
assert(has(readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.wwi")),
|
||||
"//ww:module commit.codec\npackage cable;\n"));
|
||||
assert(same(commitcoldbytes, readfile(commitcoldbins[si])));
|
||||
let commitbinbytes: str = readfile(commitfixedbins[si]);
|
||||
if (si == 0) { commitbinref = strings.dup(commitbinbytes); }
|
||||
else { assert(same(commitbinref, commitbinbytes)); };
|
||||
@@ -8614,10 +8662,12 @@ fn runtimepath(relative: str) str = {
|
||||
let one: str = strings.concat(source, "/pkg/one");
|
||||
let two: str = strings.concat(source, "/pkg/two");
|
||||
let positives: []str = ["default", "alias", "reuse", "repeatok",
|
||||
"repeatedfiles"];
|
||||
"repeatedfiles", "blankalias", "blankrepeat", "blankdefault",
|
||||
"blankexplicit", "blankfiles"];
|
||||
let negatives: []str = ["barefn", "baretype", "baredef", "bareconst",
|
||||
"barevar", "aliasbad", "aliasleak", "repeatdup", "aliasdup",
|
||||
"defaultalias", "declcollision", "unusedalias", "blankalias"];
|
||||
"defaultalias", "declcollision", "unusedalias", "blankqual",
|
||||
"blankbare", "blankordinaryunused"];
|
||||
let dirs: []str = [one, two];
|
||||
let i: i32 = 0;
|
||||
for (i < positives.len) {
|
||||
@@ -8673,6 +8723,24 @@ fn runtimepath(relative: str) str = {
|
||||
"fn second() i32 = { return right.value(); };\n"));
|
||||
writefile(strings.concat(source, "/cmd/repeatedfiles/main.ww"),
|
||||
"package main;\nfn main() i32 = { return first() + second(); };\n");
|
||||
writefile(strings.concat(source, "/cmd/blankalias/main.ww"),
|
||||
"package main;\nimport _ pkg.one;\nfn main() i32 = { return 0; };\n");
|
||||
writefile(strings.concat(source, "/cmd/blankrepeat/main.ww"),
|
||||
strings.concat("package main;\nimport _ pkg.one;\n",
|
||||
"import _ pkg.one;\nfn main() i32 = { return 0; };\n"));
|
||||
writefile(strings.concat(source, "/cmd/blankdefault/main.ww"),
|
||||
strings.concat("package main;\nimport _ pkg.one;\nimport pkg.one;\n",
|
||||
"fn main() i32 = { return wire.value(); };\n"));
|
||||
writefile(strings.concat(source, "/cmd/blankexplicit/main.ww"),
|
||||
strings.concat("package main;\nimport _ pkg.one;\n",
|
||||
"import stable pkg.one;\n",
|
||||
"fn main() i32 = { return stable.value(); };\n"));
|
||||
writefile(strings.concat(source, "/cmd/blankfiles/a.ww"),
|
||||
"package main;\nimport _ pkg.one;\n");
|
||||
writefile(strings.concat(source, "/cmd/blankfiles/b.ww"),
|
||||
"package main;\nimport _ pkg.one;\n");
|
||||
writefile(strings.concat(source, "/cmd/blankfiles/main.ww"),
|
||||
"package main;\nfn main() i32 = { return 0; };\n");
|
||||
|
||||
let bareexprs: []str = ["value()", "take(7)", "DEFINED", "CONSTANT",
|
||||
"VARIABLE"];
|
||||
@@ -8716,22 +8784,29 @@ fn runtimepath(relative: str) str = {
|
||||
"fn main() i32 = { return stable(); };\n"));
|
||||
writefile(strings.concat(source, "/cmd/unusedalias/main.ww"),
|
||||
"package main;\nimport stable pkg.one;\nfn main() i32 = { return 0; };\n");
|
||||
writefile(strings.concat(source, "/cmd/blankalias/main.ww"),
|
||||
"package main;\nimport _ pkg.one;\nfn main() i32 = { return 0; };\n");
|
||||
writefile(strings.concat(source, "/cmd/blankqual/main.ww"),
|
||||
strings.concat("package main;\nimport _ pkg.one;\n",
|
||||
"fn main() i32 = { return wire.value(); };\n"));
|
||||
writefile(strings.concat(source, "/cmd/blankbare/main.ww"),
|
||||
strings.concat("package main;\nimport _ pkg.one;\n",
|
||||
"fn main() i32 = { return value(); };\n"));
|
||||
writefile(strings.concat(source, "/cmd/blankordinaryunused/main.ww"),
|
||||
strings.concat("package main;\nimport _ pkg.one;\nimport pkg.one;\n",
|
||||
"fn main() i32 = { return 0; };\n"));
|
||||
|
||||
let stages: []str = ["ww", "ww_ww"];
|
||||
let expected: []i32 = [83, 83, 40, 33, 22];
|
||||
let binaryrefs: []str = ["", "", "", "", ""];
|
||||
let expected: []i32 = [83, 83, 40, 33, 22, 0, 0, 11, 11, 0];
|
||||
let binaryrefs: []str = ["", "", "", "", "", "", "", "", "", ""];
|
||||
let diagrefs: []str = ["", "", "", "", "", "", "", "", "",
|
||||
"", "", "", ""];
|
||||
"", "", "", "", "", ""];
|
||||
let needles: []str = ["undefined: value", "unknown type 'Thing'",
|
||||
"undefined: DEFINED", "undefined: CONSTANT", "undefined: VARIABLE",
|
||||
"unknown type 'wire.Thing'", "package 'stable' is not directly imported",
|
||||
"wire redeclared in this block", "stable redeclared in this block",
|
||||
"wire redeclared in this block",
|
||||
"stable already declared through import of package stable",
|
||||
"\"pkg.one\" imported as stable and not used",
|
||||
"blank import alias _ is not implemented"];
|
||||
"\"pkg.one\" imported as stable and not used", "undefined: wire",
|
||||
"undefined: value", "\"pkg.one\" imported as wire and not used"];
|
||||
let exactdiags: []str = [
|
||||
strings.concat(
|
||||
"$WORK/cmd.barefn.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n",
|
||||
@@ -8777,8 +8852,7 @@ fn runtimepath(relative: str) str = {
|
||||
strings.concat(
|
||||
"$WORK/cmd.unusedalias.unit.new:3:1: error: \"pkg.one\" imported as stable and not used\n",
|
||||
"ww: w6c failed for cmd.unusedalias\n"),
|
||||
strings.concat(source,
|
||||
"/cmd/blankalias/main.ww:2:8: error: blank import alias _ is not implemented\n"),
|
||||
"", "", "",
|
||||
];
|
||||
let si: i32 = 0;
|
||||
for (si < stages.len) {
|
||||
@@ -8820,6 +8894,26 @@ fn runtimepath(relative: str) str = {
|
||||
let repeatedunit: str = readfile(strings.concat(work,
|
||||
"/cmd.repeatedfiles.unit.ww"));
|
||||
assert(occurrences(repeatedunit, "pkg.one;") == 2);
|
||||
let blankunit: str = readfile(strings.concat(work,
|
||||
"/cmd.blankalias.unit.ww"));
|
||||
assert(has(blankunit, "import _ pkg.one;"));
|
||||
let blankwwi: str = readfile(strings.concat(work,
|
||||
"/cmd.blankalias.wwi"));
|
||||
assert(!has(blankwwi, "import _") && !has(blankwwi, "__ww.."));
|
||||
let blankrepeat: str = readfile(strings.concat(work,
|
||||
"/cmd.blankrepeat.unit.ww"));
|
||||
assert(occurrences(blankrepeat, "import _ pkg.one;") == 2);
|
||||
assert(occurrences(blankrepeat,
|
||||
"//ww:direct-export pkg.one ") == 1);
|
||||
let blankfiles: str = readfile(strings.concat(work,
|
||||
"/cmd.blankfiles.unit.ww"));
|
||||
assert(occurrences(blankfiles, "import _ pkg.one;") == 2);
|
||||
assert(occurrences(blankfiles,
|
||||
"//ww:direct-export pkg.one ") == 1);
|
||||
let blankdispatch: str = readfile(strings.concat(work,
|
||||
"/cmd.blankdefault.init.unit.ww"));
|
||||
assert(occurrences(blankdispatch,
|
||||
"//ww:init-call __ww..pkg.p.pkg.one.v0.r0.init") == 1);
|
||||
|
||||
i = 0;
|
||||
for (i < negatives.len) {
|
||||
|
||||
36
test/sep/limitexec.c
Normal file
36
test/sep/limitexec.c
Normal file
@@ -0,0 +1,36 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Test-only deterministic launcher for allocation-failure observers. Keeping
|
||||
* setrlimit in a repository-built helper avoids depending on util-linux paths
|
||||
* or shell-specific ulimit syntax. */
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
fputs("usage: sep-limitexec bytes program [arg ...]\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
errno = 0;
|
||||
char *end = NULL;
|
||||
unsigned long long value = strtoull(argv[1], &end, 10);
|
||||
if (errno != 0 || end == argv[1] || *end != '\0') {
|
||||
fputs("sep-limitexec: invalid limit\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
struct rlimit limit;
|
||||
limit.rlim_cur = (rlim_t)value;
|
||||
limit.rlim_max = (rlim_t)value;
|
||||
if (setrlimit(RLIMIT_AS, &limit) != 0) {
|
||||
fputs("sep-limitexec: setrlimit failed\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
execv(argv[2], &argv[2]);
|
||||
fputs("sep-limitexec: exec failed\n", stderr);
|
||||
return 127;
|
||||
}
|
||||
1421
test/sep/sepinit_test.ww
Normal file
1421
test/sep/sepinit_test.ww
Normal file
File diff suppressed because it is too large
Load Diff
@@ -140,6 +140,7 @@ main(void)
|
||||
"import io;",
|
||||
"import io.bufio;",
|
||||
"import stable io.bufio;",
|
||||
"import _ io.bufio;",
|
||||
"def MAX: i32 = 4096;",
|
||||
"export def MAX: i32 = 4096;",
|
||||
"type point = struct { x: i32, y: i32 };",
|
||||
@@ -149,6 +150,7 @@ main(void)
|
||||
"type arr = [16]u8;",
|
||||
|
||||
"fn nop() void = {};",
|
||||
"fn init() void = {}; fn init() void = {};",
|
||||
"export fn id(x: i32) i32 = { return x; };",
|
||||
"fn add(a: i32, b: i32) i32 = { return a + b; };",
|
||||
"@symbol(\"malloc\") fn cmalloc(n: u64) *void;",
|
||||
|
||||
@@ -49,6 +49,15 @@ struct row { const char *src, *expect; };
|
||||
|
||||
static const struct row rows[] = {
|
||||
{ "fn main() void = {};", "ok" },
|
||||
{ "fn init() void = {}; fn init() void = {};", "ok" },
|
||||
{ "fn init(x: i32) void = {};", "func init must have no arguments and no return values" },
|
||||
{ "fn init() i32 = { return 1; };", "func init must have no arguments and no return values" },
|
||||
{ "fn init() void;", "func init must have a body" },
|
||||
{ "export fn init() void = {};", "func init cannot be exported" },
|
||||
{ "fn init() void = {}; fn f() void = { init(); };", "undefined: init" },
|
||||
{ "fn make() i32 = { return 7; }; let state: i32 = make();", "ok" },
|
||||
{ "fn left() i32 = { return right; }; let first: i32 = left(); let right: i32 = 3;", "ok" },
|
||||
{ "fn readb() i32 = { return b; }; let a: i32 = readb(); let b: i32 = a;", "initialization cycle for a" },
|
||||
{ "fn id(x: i32) i32 = { return x; };", "ok" },
|
||||
{ "fn add(a: i32, b: i32) i32 = { return a + b; };", "ok" },
|
||||
{ "def MAX: i32 = 4096;", "ok" },
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//ww:run-exit 42
|
||||
package main;
|
||||
type bs = struct { rbuf: []u8, mark: i32 };
|
||||
fn init(b: *bs, rbuf: []u8) void = { b.rbuf = rbuf; b.mark = 9; };
|
||||
fn setup(b: *bs, rbuf: []u8) void = { b.rbuf = rbuf; b.mark = 9; };
|
||||
fn main() i32 = {
|
||||
let raw: [8]u8; raw[0] = 0u8; let b: bs; init(&b, raw[0:5]);
|
||||
let raw: [8]u8; raw[0] = 0u8; let b: bs; setup(&b, raw[0:5]);
|
||||
if (b.rbuf.len != 5) { return 1; }; if (b.rbuf.cap != 8) { return 2; };
|
||||
if (b.mark != 9) { return 3; }; return 42;
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ export fn main() i32 = {
|
||||
if (sel == 0) { src = &mstB.vt; };
|
||||
let rbuf: [4]u8;
|
||||
let wbuf: [4]u8;
|
||||
let bc: bufio.stream = bufio.init(src, rbuf[0:4], wbuf[0:4]);
|
||||
let bc: bufio.stream = bufio.newstream(src, rbuf[0:4], wbuf[0:4]);
|
||||
let vs: io.stream = &bc.vt;
|
||||
let out: [4]u8;
|
||||
let rd = io.read(vs, out[0:4]);
|
||||
|
||||
@@ -10,7 +10,7 @@ export fn main() i32 = {
|
||||
let msrc: io.stream = &mst.vt;
|
||||
let rbuf: [4]u8;
|
||||
let wbuf: [4]u8;
|
||||
let bc: bufio.stream = bufio.init(msrc, rbuf[0:4], wbuf[0:4]);
|
||||
let bc: bufio.stream = bufio.newstream(msrc, rbuf[0:4], wbuf[0:4]);
|
||||
let vs: io.stream = &bc.vt;
|
||||
if (!bufio.isbuffered(vs)) { return 91; };
|
||||
if (bufio.isbuffered(msrc)) { return 92; };
|
||||
|
||||
@@ -10,7 +10,7 @@ export fn main() i32 = {
|
||||
let msrc: io.stream = &mst.vt;
|
||||
let rbuf: [4]u8;
|
||||
let wbuf: [4]u8;
|
||||
let b: bufio.stream = bufio.init(msrc, rbuf[0:4], wbuf[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(msrc, rbuf[0:4], wbuf[0:4]);
|
||||
let vsbuf: io.stream = &b.vt;
|
||||
let buf2: [4]u8;
|
||||
let st2: memio.stream = memio.fixed(buf2[0:4]);
|
||||
|
||||
@@ -12,7 +12,7 @@ export fn main() i32 = {
|
||||
let msrc: io.stream = &mst.vt;
|
||||
let rbuf: [8]u8;
|
||||
let wbuf: [4]u8;
|
||||
let b: bufio.stream = bufio.init(msrc, rbuf[0:8], wbuf[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(msrc, rbuf[0:8], wbuf[0:4]);
|
||||
let vs: io.stream = &b.vt;
|
||||
let out: [4]u8;
|
||||
let rd1 = io.read(vs, out[0:3]);
|
||||
|
||||
@@ -10,7 +10,7 @@ export fn main() i32 = {
|
||||
let sinkvs: io.stream = &sink.vt;
|
||||
let rb: [4]u8;
|
||||
let wb: [8]u8;
|
||||
let b: bufio.stream = bufio.init(sinkvs, rb[0:4], wb[0:8]);
|
||||
let b: bufio.stream = bufio.newstream(sinkvs, rb[0:4], wb[0:8]);
|
||||
let bvs: io.stream = &b.vt;
|
||||
let semi: [1]u8;
|
||||
semi[0] = 59u8;
|
||||
|
||||
@@ -11,7 +11,7 @@ export fn main() i32 = {
|
||||
let vs: io.stream = &mst.vt;
|
||||
let rbuf: [4]u8;
|
||||
let wbuf: [4]u8;
|
||||
let b: bufio.stream = bufio.init(vs, rbuf[0:4], wbuf[0:4]);
|
||||
let b: bufio.stream = bufio.newstream(vs, rbuf[0:4], wbuf[0:4]);
|
||||
let bvs: io.stream = &b.vt;
|
||||
let out: [4]u8;
|
||||
let rd = io.read(bvs, out[0:3]);
|
||||
|
||||
@@ -10,7 +10,7 @@ export fn main() i32 = {
|
||||
let msrc: io.stream = &mst.vt;
|
||||
let rbuf: [8]u8;
|
||||
let wbuf: [8]u8;
|
||||
let b: bufio.stream = bufio.init(msrc, rbuf[0:8], wbuf[0:8]);
|
||||
let b: bufio.stream = bufio.newstream(msrc, rbuf[0:8], wbuf[0:8]);
|
||||
let vs: io.stream = &b.vt;
|
||||
let payload: [5]u8;
|
||||
payload[0] = 104u8; payload[1] = 105u8;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package main;
|
||||
import math.random;
|
||||
export fn main() int = {
|
||||
let g: random.random = random.init(1u64);
|
||||
let g: random.random = random.fromseed(1u64);
|
||||
let x: u32 = random.u32n(&g, 1u32);
|
||||
if (x >= 1u32) { return 1; };
|
||||
return 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package main;
|
||||
import math.random;
|
||||
export fn main() int = {
|
||||
let g: random.random = random.init(1u64);
|
||||
let g: random.random = random.fromseed(1u64);
|
||||
let x: u32 = random.u32n(&g, 10u32);
|
||||
if (x >= 10u32) { return 1; };
|
||||
return 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package main;
|
||||
import math.random;
|
||||
export fn main() int = {
|
||||
let g: random.random = random.init(1u64);
|
||||
let g: random.random = random.fromseed(1u64);
|
||||
let x: u64 = random.u64n(&g, 1u64);
|
||||
if (x >= 1u64) { return 1; };
|
||||
return 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package main;
|
||||
import math.random;
|
||||
export fn main() int = {
|
||||
let g: random.random = random.init(1u64);
|
||||
let g: random.random = random.fromseed(1u64);
|
||||
let x: u64 = random.u64n(&g, 10u64);
|
||||
if (x >= 10u64) { return 1; };
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user