test: prove declared package import semantics
This commit is contained in:
@@ -2634,10 +2634,13 @@ commit and are implementation evidence, not requirements for the replacement.
|
|||||||
|
|
||||||
### 11.2 Conflated identities and accidental behavior
|
### 11.2 Conflated identities and accidental behavior
|
||||||
|
|
||||||
|
This table records the baseline that the implemented slices below replaced;
|
||||||
|
sections 11.6–11.18 are authoritative where they conflict with it.
|
||||||
|
|
||||||
| Concept that must be separate | Current conflation or accident |
|
| Concept that must be separate | Current conflation or accident |
|
||||||
|---|---|
|
|---|---|
|
||||||
| package identity | Dotted import spelling is graph key, module/symbol prefix, artifact basename, and link identity. |
|
| package identity | Before the local-package slices, dotted import spelling was simultaneously graph key, module/symbol prefix, artifact basename, and link identity. The implemented loader now separates source spelling, expanded canonical identity, physical directory, and storage locator. |
|
||||||
| declared name | A directory's leaf is checked against it for imports, but root directories and literal file roots receive different validation. `.wwi` itself retains only the leaf package name. |
|
| declared name | Before section 11.18, imported directories required their declared name to equal the import-path leaf and `.wwi` retained only that leaf. The implemented compiler/export path now carries the declaration independently. |
|
||||||
| filesystem location | Ordered search roots silently choose/shadow a location; the same physical directory may be compiled under two import identities, while duplicate locations for one spelling produce no collision diagnostic. Paths are lexical, not content identities. |
|
| filesystem location | Ordered search roots silently choose/shadow a location; the same physical directory may be compiled under two import identities, while duplicate locations for one spelling produce no collision diagnostic. Paths are lexical, not content identities. |
|
||||||
| package versus file | Directories create separate-compilation nodes; files disappear into owners. The same `package` syntax means two compilation models. |
|
| package versus file | Directories create separate-compilation nodes; files disappear into owners. The same `package` syntax means two compilation models. |
|
||||||
| artifact versus identity | `<dotted-path>.wwi/.s/.o/.a` names artifacts; root aliases to `__root`, which can collide with a real import. |
|
| artifact versus identity | `<dotted-path>.wwi/.s/.o/.a` names artifacts; root aliases to `__root`, which can collide with a real import. |
|
||||||
@@ -2802,19 +2805,22 @@ falls back to directory lookup through the entry package's directory, explicit
|
|||||||
containing the directory wins over an earlier file decoy. There is no network,
|
containing the directory wins over an earlier file decoy. There is no network,
|
||||||
manifest, or imported-file fallback. Explicit single-file CLI roots retain
|
manifest, or imported-file fallback. Explicit single-file CLI roots retain
|
||||||
their raw-unit compatibility path. The loader uses the compiler frontend's
|
their raw-unit compatibility path. The loader uses the compiler frontend's
|
||||||
imports-only parser, unions duplicate imports, byte-sorts direct edges, interns
|
imports-only parser, retains every real import occurrence with its owning
|
||||||
canonical directory actions, and reports self-imports and stable cycle chains
|
source file and position, byte-sorts and deduplicates the resulting canonical
|
||||||
before compilation.
|
direct edges, interns canonical directory actions, and reports self-imports and
|
||||||
|
stable cycle chains before compilation. Occurrence retention makes contextual
|
||||||
|
`internal` and `vendor` checks run at every import site; it does not duplicate
|
||||||
|
package actions or compiler inputs.
|
||||||
|
|
||||||
A directory package consists of its immediate `.ww` entries whose basenames do
|
A directory package consists of its immediate `.ww` entries whose basenames do
|
||||||
not begin `.` or `_`: regular files and symlinks targeting regular files are
|
not begin `.` or `_`: regular files and symlinks targeting regular files are
|
||||||
included under the entry name, while symlinks targeting directories are
|
included under the entry name, while symlinks targeting directories are
|
||||||
ignored. The production variant excludes `*_test.ww`; each variant retains
|
ignored. The production variant excludes `*_test.ww`; each variant retains
|
||||||
byte-sorted filename order. Every selected file must
|
byte-sorted filename order. Every selected production file must declare the
|
||||||
declare the same package. An ordinary importable directory's declaration must
|
same package name, but that declaration is independent of the directory name
|
||||||
equal the final component of its import path. A selected command directory
|
and every component of the canonical import path. A selected command directory
|
||||||
instead declares `package main` to validate command kind while retaining its
|
declares `package main` while retaining its complete canonical import identity.
|
||||||
complete canonical import identity. A source import of a command package from a
|
A source import of a command package from a
|
||||||
different directory is rejected; the one same-directory exception is an
|
different directory is rejected; the one same-directory exception is an
|
||||||
external `main_test` variant's canonical import of its production action. Two
|
external `main_test` variant's canonical import of its production action. Two
|
||||||
ordinary logical identities for one physical directory are rejected rather
|
ordinary logical identities for one physical directory are rejected rather
|
||||||
@@ -2842,9 +2848,11 @@ path and deduplicated by the loader; a source spelling expanded through
|
|||||||
`vendor` additionally receives the non-dependency `--import-map` described in
|
`vendor` additionally receives the non-dependency `--import-map` described in
|
||||||
section 11.16. No transitive `.wwi` is passed.
|
section 11.16. No transitive `.wwi` is passed.
|
||||||
Origin-tagged facts inside those direct artifacts are compiler data, not source
|
Origin-tagged facts inside those direct artifacts are compiler data, not source
|
||||||
imports: a source qualifier is visible only when its owning package directly
|
imports: a source qualifier is visible only in the source file that directly
|
||||||
imports it, and private members, transitive-only qualifiers, bare values, and
|
imports it. The qualifier is the imported export's declared package name, not
|
||||||
bare types remain compiler errors. In `-c` package mode the compiler parses each
|
the source spelling or import-path leaf. Private members, transitive-only
|
||||||
|
qualifiers, bare values, and bare types remain compiler errors. In `-c` package
|
||||||
|
mode the compiler parses each
|
||||||
export independently, then coalesces repeated exported type/constant facts with
|
export independently, then coalesces repeated exported type/constant facts with
|
||||||
the same origin, kind, and name, preserving one nominal type identity across
|
the same origin, kind, and name, preserving one nominal type identity across
|
||||||
diamonds; raw non-package `w6c` retains its existing one-source behavior. The
|
diamonds; raw non-package `w6c` retains its existing one-source behavior. The
|
||||||
@@ -2855,8 +2863,9 @@ boundary is live in production Cstage and WWstage compilers and drivers.
|
|||||||
A selected production root is one normal package action. Its finalized
|
A selected production root is one normal package action. Its finalized
|
||||||
canonical import identity tags its owner-only unit; it receives only direct
|
canonical import identity tags its owner-only unit; it receives only direct
|
||||||
exports, emits `.wwi`, `.o`, and a deterministic `.a`, and is compiled exactly
|
exports, emits `.wwi`, `.o`, and a deterministic `.a`, and is compiled exactly
|
||||||
once. The declared package name validates the last component of that identity
|
once. The declared package name is semantic package content but never validates,
|
||||||
for ordinary importable packages. After loading and identity finalization, the
|
shortens, aliases, or replaces that identity. After loading and identity
|
||||||
|
finalization, the
|
||||||
declaration also selects the terminal build action: `package main` is a command
|
declaration also selects the terminal build action: `package main` is a command
|
||||||
and every other valid declaration is a compile-only library. A command root
|
and every other valid declaration is a compile-only library. A command root
|
||||||
receives the narrow compiler `--entry` flag, which controls bare `main` codegen,
|
receives the narrow compiler `--entry` flag, which controls bare `main` codegen,
|
||||||
@@ -2869,8 +2878,8 @@ package declaration to classify and remains a raw command unit; it does not
|
|||||||
participate in canonical directory-package interning.
|
participate in canonical directory-package interning.
|
||||||
The package driver still uses the parser-only `--command-package` marker for
|
The package driver still uses the parser-only `--command-package` marker for
|
||||||
command test variants that must remain ordinary archive code. Neither marker
|
command test variants that must remain ordinary archive code. Neither marker
|
||||||
changes export identity, and imported interfaces remain under strict leaf
|
changes export identity, and imported interfaces retain independent canonical
|
||||||
validation. The linkers seed `main` before archive selection, so the existing
|
owner and declared-name records. The linkers seed `main` before archive selection, so the existing
|
||||||
WWAR member protocol needs no special root object or format change.
|
WWAR member protocol needs no special root object or format change.
|
||||||
|
|
||||||
Publication is separate from that semantic action choice. `ww build -o lib.a
|
Publication is separate from that semantic action choice. `ww build -o lib.a
|
||||||
@@ -2885,7 +2894,7 @@ action identity. The historical action-selecting `-p` exception is removed and
|
|||||||
rejected as an unknown build flag. Assembly-only `-S` still stops before object,
|
rejected as an unknown build flag. Assembly-only `-S` still stops before object,
|
||||||
archive, publication, or link production. A literal directory is
|
archive, publication, or link production. A literal directory is
|
||||||
reverse-resolved through the active source roots or receives the deterministic
|
reverse-resolved through the active source roots or receives the deterministic
|
||||||
local identity described below; its declared leaf can never invent or truncate
|
local identity described below; its declaration can never invent or truncate
|
||||||
that identity. Two cold builds with identical inputs are required to produce
|
that identity. Two cold builds with identical inputs are required to produce
|
||||||
byte-identical requested products. Compiler intrinsics keep their package-mode
|
byte-identical requested products. Compiler intrinsics keep their package-mode
|
||||||
runtime ABI independent of transitive source interfaces (for example, `alloc`
|
runtime ABI independent of transitive source interfaces (for example, `alloc`
|
||||||
@@ -2918,7 +2927,7 @@ publication spelling, `FILE.wwi.new`, so an incomplete archive/export pair is
|
|||||||
never caused by a late path-overflow failure. Package loading, cycle detection,
|
never caused by a late path-overflow failure. Package loading, cycle detection,
|
||||||
and closure validation retain diagnostic precedence over this publication-only
|
and closure validation retain diagnostic precedence over this publication-only
|
||||||
check, and `-S` does not validate a publication path it never consumes.
|
check, and `-S` does not validate a publication path it never consumes.
|
||||||
Build workdir format 13 and test workdir format 12 invalidate older unit
|
Build workdir format 14 and test workdir format 13 invalidate older unit
|
||||||
vouchers before reuse because source binding and vendor-directory identity now
|
vouchers before reuse because source binding and vendor-directory identity now
|
||||||
participate in compiler argv and persistent unit semantics. Thereafter
|
participate in compiler argv and persistent unit semantics. Thereafter
|
||||||
an equivalent warm library build invokes no tools, a private dependency change
|
an equivalent warm library build invokes no tools, a private dependency change
|
||||||
@@ -2956,21 +2965,28 @@ package variant:
|
|||||||
files followed by byte-sorted matching `package p` test files. It is distinct
|
files followed by byte-sorted matching `package p` test files. It is distinct
|
||||||
from production so its private production declarations and test declarations
|
from production so its private production declarations and test declarations
|
||||||
remain isolated to that test product.
|
remain isolated to that test product.
|
||||||
- The external variant selects only matching `package p_test` files. Its
|
- When production sources establish `p`, the external variant selects only
|
||||||
`import p` is a direct edge to the same ordinary production action used by
|
matching `package p_test` files, where `p` is the production declaration
|
||||||
|
rather than an import-path leaf. A test-only directory may establish its own
|
||||||
|
one consistent test package name, matching pinned `go/build` classification.
|
||||||
|
A real source import of the production package uses its canonical import
|
||||||
|
path and is a direct edge to the same ordinary production action used by
|
||||||
ordinary products and transitive imports; there is no external-production
|
ordinary products and transitive imports; there is no external-production
|
||||||
role or artifact.
|
role or artifact.
|
||||||
- Generated main is a separate package action whose owner-only generated unit
|
- Generated main is a separate package action whose owner-only generated unit
|
||||||
declares `package main` and imports exactly the selected variant and test
|
declares `package main` and imports exactly the selected variant and test
|
||||||
support. It consumes those direct `.wwi` files, emits its own `.wwi/.o/.a`,
|
support. It consumes those direct `.wwi` files, emits its own `.wwi/.o/.a`,
|
||||||
and alone receives compiler `-T --entry`.
|
and alone receives compiler `-T --entry`. Its target edge also receives the
|
||||||
|
compiler-private `--test-target-package <canonical-path>` binding. That
|
||||||
|
private canonical-path qualifier prevents a tested command declared `main`
|
||||||
|
from colliding with generated main; it is not user alias syntax.
|
||||||
|
|
||||||
The authoritative directory-action identity is the triple **(canonical
|
The authoritative directory-action identity is the triple **(canonical
|
||||||
filesystem directory, canonical ordinary import path, semantic variant)**.
|
filesystem directory, canonical ordinary import path, semantic variant)**.
|
||||||
The semantic variants are production, internal production-plus-test, and
|
The semantic variants are production, internal production-plus-test, and
|
||||||
external `_test`; generated main and the reserved test-support alias are
|
external `_test`; generated main and the reserved test-support alias are
|
||||||
explicit non-directory action classes. Source package name validates the leaf
|
explicit non-directory action classes. The declared package name is stored
|
||||||
of the bound import path but is not itself a second identity. Requested-root
|
separately and is not part of canonical directory/path interning. Requested-root
|
||||||
state, discovery role, product ordinal, output path, persistent artifact key,
|
state, discovery role, product ordinal, output path, persistent artifact key,
|
||||||
and discovery order never enter the triple.
|
and discovery order never enter the triple.
|
||||||
|
|
||||||
@@ -2999,17 +3015,19 @@ invocation, each still-unbound directory is finalized by this exact algorithm:
|
|||||||
root cannot rename an explicitly resolved package.
|
root cannot rename an explicitly resolved package.
|
||||||
4. If no active root can represent the directory, bind the reserved,
|
4. If no active root can represent the directory, bind the reserved,
|
||||||
non-source-importable identity
|
non-source-importable identity
|
||||||
`__wwlocal.p<escaped-canonical-absolute-directory>.<declared-leaf>`. The
|
`__wwlocal.p<escaped-canonical-absolute-directory>`. The
|
||||||
escape is injective and reversible over path bytes: ASCII letters and digits
|
escape is injective and reversible over path bytes: ASCII letters and digits
|
||||||
are copied, `_` becomes `_u`, `/` becomes `_s`, and every other byte becomes
|
are copied, `_` becomes `_u`, `/` becomes `_s`, and every other byte becomes
|
||||||
`_xHH` with lowercase hexadecimal. Source imports of `__wwlocal` or any of
|
`_xHH` with lowercase hexadecimal. Source imports of `__wwlocal` or any of
|
||||||
its children are rejected, so this command-local identity creates no alias.
|
its children are rejected, so this command-local identity creates no alias.
|
||||||
|
|
||||||
The selected full identity's final component is then validated against the
|
The selected full identity is never validated against the ordinary declared
|
||||||
ordinary declared package name (or against the ordinary leaf obtained by
|
package name. Production and internal variants retain the production
|
||||||
removing `_test` for the external variant). The one command-kind rule is that a
|
declaration; when production exists, an external variant is admitted only as
|
||||||
selected command family declares `main`/`main_test` while keeping the finalized
|
`<production-declared-name>_test`. A test-only directory instead establishes
|
||||||
ordinary identity unchanged. A source import of that command from another
|
one consistent test package declaration itself. The one command-kind rule is that a selected
|
||||||
|
command family declares `main`/`main_test` while keeping the finalized ordinary
|
||||||
|
identity unchanged. A source import of that command from another
|
||||||
directory rejects as a program before tools; a colocated external command test
|
directory rejects as a program before tools; a colocated external command test
|
||||||
may reuse the canonical production action. There is no fallback from an empty
|
may reuse the canonical production action. There is no fallback from an empty
|
||||||
import path to a declaration name. Relative, absolute, and symlink spellings
|
import path to a declaration name. Relative, absolute, and symlink spellings
|
||||||
@@ -3027,9 +3045,10 @@ The derivation and diagnostics are implemented symmetrically in
|
|||||||
variant descriptors, preserves an explicitly resolved identity only for one
|
variant descriptors, preserves an explicitly resolved identity only for one
|
||||||
direct request, and forwards a caller's `-w` semantic-action store unchanged.
|
direct request, and forwards a caller's `-w` semantic-action store unchanged.
|
||||||
It never derives identity or persistent layout from a pattern traversal prefix
|
It never derives identity or persistent layout from a pattern traversal prefix
|
||||||
and does not add that prefix to import search. `w6c` and `wcc` continue to
|
and does not add that prefix to import search. `w6c` and `wcc` consume the
|
||||||
consume and validate the finalized dotted identity; neither tool performs
|
finalized dotted identity as export/symbol owner while reading the declared
|
||||||
directory lookup or introduces a package registry.
|
name independently from export data; neither tool performs directory lookup or
|
||||||
|
introduces a package registry.
|
||||||
|
|
||||||
Artifact publication follows the semantic action instead of product order:
|
Artifact publication follows the semantic action instead of product order:
|
||||||
production uses the full finalized ordinary identity, internal appends
|
production uses the full finalized ordinary identity, internal appends
|
||||||
@@ -3352,11 +3371,13 @@ and any sorted driver-private vendor/import-map voucher comments, but no
|
|||||||
dependency body. When exact source spelling differs from a selected expanded
|
dependency body. When exact source spelling differs from a selected expanded
|
||||||
canonical identity, the drivers also pass sorted, unique
|
canonical identity, the drivers also pass sorted, unique
|
||||||
`--import-map <source-spelling> <canonical-import-path>` triples. A map must
|
`--import-map <source-spelling> <canonical-import-path>` triples. A map must
|
||||||
preserve the import leaf and target an ordinary direct `--import`; it adds no
|
target an ordinary direct `--import`; it adds no export input or graph edge.
|
||||||
export input or graph edge. The compilers rewrite only matching imports in the
|
The compilers rewrite only the matching primary import's canonical semantic key
|
||||||
primary source list before merging interfaces, leaving the source qualifier,
|
before merging interfaces. They then obtain that target's declared package name
|
||||||
position, imported interface metadata, and generated/synthetic imports
|
from its direct export and install it as the default qualifier in the owning
|
||||||
untouched. Executable linking independently walks the full reachable package
|
source file. Source spelling and position remain intact; generated/synthetic
|
||||||
|
imports use their explicit compiler-owned bindings. Executable linking
|
||||||
|
independently walks the full reachable package
|
||||||
closure and passes archives, never interfaces. The same path handles an
|
closure and passes archives, never interfaces. The same path handles an
|
||||||
ordinary package, the production-plus-internal-test variant, the external test
|
ordinary package, the production-plus-internal-test variant, the external test
|
||||||
package and its reused production package, compiler-generated test main, and
|
package and its reused production package, compiler-generated test main, and
|
||||||
@@ -3533,14 +3554,13 @@ and storage-address derivation. The complete `path`, together with the
|
|||||||
semantic `variant` and `role`, is the persisted/compiler owner carried through
|
semantic `variant` and `role`, is the persisted/compiler owner carried through
|
||||||
source-import edges, module-reset and export ownership, compiler `--import`
|
source-import edges, module-reset and export ownership, compiler `--import`
|
||||||
arguments, generated-main construction, and symbol qualification; `storage`
|
arguments, generated-main construction, and symbol qualification; `storage`
|
||||||
participates in none of those identities. The reversible outside-root form
|
participates in none of those identities. The reversible outside-root form is
|
||||||
remains
|
`__wwlocal.p<escaped-canonical-absolute-directory>` and is
|
||||||
`__wwlocal.p<escaped-canonical-absolute-directory>.<declared-leaf>` and is
|
|
||||||
allocated to its exact length. It is neither truncated nor replaced by a
|
allocated to its exact length. It is neither truncated nor replaced by a
|
||||||
digest, and `__wwlocal` remains unavailable to source imports. Package
|
digest, and `__wwlocal` remains unavailable to source imports. Package
|
||||||
declarations continue to validate the selected package kind and leaf; they do
|
declarations classify package kind and contribute semantic export content; they
|
||||||
not supply a missing identity and do not alter a command package's canonical
|
do not validate a path leaf, supply a missing identity, or alter a command
|
||||||
path.
|
package's canonical path.
|
||||||
|
|
||||||
Short actions retain their established `.unit.ww`, `.wwi`, `.s`, `.o`, and
|
Short actions retain their established `.unit.ww`, `.wwi`, `.s`, `.o`, and
|
||||||
`.a` basenames when the basename plus `.unit.new` fits the 255-byte supported
|
`.a` basenames when the basename plus `.unit.new` fits the 255-byte supported
|
||||||
@@ -3712,6 +3732,9 @@ The Cstage representation is exact and deliberately small:
|
|||||||
`depcap`;
|
`depcap`;
|
||||||
- each `seppkg.context_state` is a lazily extended, zero-filled
|
- each `seppkg.context_state` is a lazily extended, zero-filled
|
||||||
`unsigned char *` with `context_cap`;
|
`unsigned char *` with `context_cap`;
|
||||||
|
- each package owns a dynamically grown import-occurrence vector recording
|
||||||
|
kind, source spelling, source file, line, column, and stable dependency
|
||||||
|
action index; its separate dependency vector remains sorted/deduplicated;
|
||||||
- parsed `sepproduct` values are a dynamically allocated vector, and each
|
- parsed `sepproduct` values are a dynamically allocated vector, and each
|
||||||
product stores its support-action index directly; and
|
product stores its support-action index directly; and
|
||||||
- package-load frames and topological-DFS frames are temporary dynamic vectors,
|
- package-load frames and topological-DFS frames are temporary dynamic vectors,
|
||||||
@@ -3720,7 +3743,8 @@ The Cstage representation is exact and deliberately small:
|
|||||||
The WWstage representation is isomorphic. `sepgraph.pkg: []seppkg` and
|
The WWstage representation is isomorphic. `sepgraph.pkg: []seppkg` and
|
||||||
`sepgraph.context: []sepcontext` use allocated slice length as capacity and keep
|
`sepgraph.context: []sepcontext` use allocated slice length as capacity and keep
|
||||||
separate `n`/`ncontext` logical counts. Every `seppkg` owns a dynamically grown
|
separate `n`/`ncontext` logical counts. Every `seppkg` owns a dynamically grown
|
||||||
`deps: []i32` with `ndeps` and a lazily zero-extended `contextstate: []u8`.
|
`bindings: []sepbind`, a dynamically grown `deps: []i32` with `ndeps`, and a
|
||||||
|
lazily zero-extended `contextstate: []u8`.
|
||||||
Products, load frames, and topological frames use typed dynamically allocated
|
Products, load frames, and topological frames use typed dynamically allocated
|
||||||
slices. `internal/wwpackage` continues to construct one union command for all
|
slices. `internal/wwpackage` continues to construct one union command for all
|
||||||
selected directory-test groups, but now checks the complete
|
selected directory-test groups, but now checks the complete
|
||||||
@@ -4051,7 +4075,9 @@ directory, rather than falling through.
|
|||||||
Source retains only the effective spelling, such as `lib.math`. Selection
|
Source retains only the effective spelling, such as `lib.math`. Selection
|
||||||
assigns the target the complete expanded canonical identity, such as
|
assigns the target the complete expanded canonical identity, such as
|
||||||
`domain.app.vendor.lib.math`, and separately canonicalizes its physical
|
`domain.app.vendor.lib.math`, and separately canonicalizes its physical
|
||||||
directory. The action key is that expanded identity and canonical directory,
|
directory. The target's declared name independently supplies the default
|
||||||
|
qualifier in each importing source file. The action key is that expanded
|
||||||
|
identity and canonical directory,
|
||||||
plus the existing variant/role. Different physical vendor copies are distinct;
|
plus the existing variant/role. Different physical vendor copies are distinct;
|
||||||
different expanded vendor routes remain distinct even when symlinks converge
|
different expanded vendor routes remain distinct even when symlinks converge
|
||||||
on one physical directory; repeated resolutions of the same pair reuse one
|
on one physical directory; repeated resolutions of the same pair reuse one
|
||||||
@@ -4110,12 +4136,13 @@ unique auxiliary mapping:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Both compilers require the map target to be an existing direct `--import`,
|
Both compilers require the map target to be an existing direct `--import`,
|
||||||
require source keys to be sorted and unique, require the final import leaf to
|
require source keys to be sorted and unique, and require a matching import in
|
||||||
remain unchanged, and require a matching import in the primary source input.
|
the primary source input. No leaf-equality condition exists. After parsing the
|
||||||
After parsing only that primary input and before prepending imported interfaces,
|
primary input and before prepending imported interfaces, the compiler replaces
|
||||||
the compiler replaces its semantic import key while preserving its source leaf,
|
its semantic import key while preserving source position and spelling. It then
|
||||||
position, and spelling bytes. Imported `.wwi` nodes and synthetic sources are
|
reads the expanded target's declared name from the direct `.wwi` and installs
|
||||||
never rewritten. Thus the map adds no dependency or export input, expanded
|
that name only in the declaring source file. Thus the map adds no dependency or
|
||||||
|
export input, expanded
|
||||||
identity flows into self-contained `.wwi` ownership and symbols, and direct
|
identity flows into self-contained `.wwi` ownership and symbols, and direct
|
||||||
exports still have no transitive leakage. Linking remains independent: each
|
exports still have no transitive leakage. Linking remains independent: each
|
||||||
executable consumes its root archive and complete reachable archive closure,
|
executable consumes its root archive and complete reachable archive closure,
|
||||||
@@ -4132,7 +4159,7 @@ Hex encoding keeps arbitrary legal filesystem bytes inside one comment. The
|
|||||||
metadata makes ordinary-to-vendor changes and vendor symlink retargeting
|
metadata makes ordinary-to-vendor changes and vendor symlink retargeting
|
||||||
invalidate the importer even when its source bytes and both already-warm export
|
invalidate the importer even when its source bytes and both already-warm export
|
||||||
bytes happen to match. It contains no dependency body and does not alter source
|
bytes happen to match. It contains no dependency body and does not alter source
|
||||||
positions. The current workdir formats are build 13 and test 12. An equivalent
|
positions. The current workdir formats are build 14 and test 13. An equivalent
|
||||||
warm request remains a package-production no-op; an export change propagates
|
warm request remains a package-production no-op; an export change propagates
|
||||||
only through ordinary direct-export comparison.
|
only through ordinary direct-export comparison.
|
||||||
|
|
||||||
@@ -4320,7 +4347,8 @@ and cannot make one variant visible to another.
|
|||||||
Vendor selection remains distinct from vendor import resolution. Selecting a
|
Vendor selection remains distinct from vendor import resolution. Selecting a
|
||||||
directory below `vendor`, literally or through an explicitly vendor-rooted
|
directory below `vendor`, literally or through an explicitly vendor-rooted
|
||||||
pattern, keeps its complete canonical local identity; it is never shortened to
|
pattern, keeps its complete canonical local identity; it is never shortened to
|
||||||
the suffix after `vendor`. A generic recursive pattern does not expose vendored
|
the suffix after `vendor`, and its declaration never renames it. A generic
|
||||||
|
recursive pattern does not expose vendored
|
||||||
descendants as ordinary short command roots. Independently, an allowed real
|
descendants as ordinary short command roots. Independently, an allowed real
|
||||||
source import still searches nearest-first below local `vendor`, creates the
|
source import still searches nearest-first below local `vendor`, creates the
|
||||||
expanded identity described in section 11.16, supplies the required
|
expanded identity described in section 11.16, supplies the required
|
||||||
@@ -4355,8 +4383,8 @@ files. A compiler receives exactly the sorted, deduplicated `.wwi` exports of
|
|||||||
direct source dependencies and any required vendor import-map binding. Each
|
direct source dependencies and any required vendor import-map binding. Each
|
||||||
executable link receives its root archive and complete reachable archive
|
executable link receives its root archive and complete reachable archive
|
||||||
closure, never a `.wwi`. Canonical duplicate roots reuse the same action; the
|
closure, never a `.wwi`. Canonical duplicate roots reuse the same action; the
|
||||||
pattern text and the product receiving an output do not affect semantic or
|
pattern text, declared qualifier, and product receiving an output do not affect
|
||||||
persistent identity.
|
canonical or persistent action ownership.
|
||||||
|
|
||||||
Selection and package-clause validation finish before the coordinator creates
|
Selection and package-clause validation finish before the coordinator creates
|
||||||
its removable temporary plan, and the coordinator never creates persistent
|
its removable temporary plan, and the coordinator never creates persistent
|
||||||
@@ -4457,6 +4485,208 @@ rejection-state preservation. The existing
|
|||||||
diamond and long-closure observers independently prove sorted/deduplicated
|
diamond and long-closure observers independently prove sorted/deduplicated
|
||||||
direct `.wwi` cardinality and archive-only reachable link closures.
|
direct `.wwi` cardinality and archive-only reachable link closures.
|
||||||
|
|
||||||
|
### 11.18 Implemented canonical identity, declared-name, and file-import-scope slice
|
||||||
|
|
||||||
|
Directory-package identity and source naming are now independent throughout
|
||||||
|
local build and test. For example:
|
||||||
|
|
||||||
|
```ww
|
||||||
|
// canonical import identity: acme.codec
|
||||||
|
package wire;
|
||||||
|
```
|
||||||
|
|
||||||
|
is imported with the existing dotted syntax:
|
||||||
|
|
||||||
|
```ww
|
||||||
|
package main;
|
||||||
|
import acme.codec;
|
||||||
|
export fn main() i32 = { return wire.value(); };
|
||||||
|
```
|
||||||
|
|
||||||
|
The package action, exports, symbols, archives, dependency edges, persistent
|
||||||
|
storage ownership, and link closure remain owned by `acme.codec`. Only the
|
||||||
|
source-file binding is named `wire`. The path leaf `codec` is not installed as
|
||||||
|
another qualifier, and a sibling source file receives no `wire` binding unless
|
||||||
|
that file has its own import.
|
||||||
|
|
||||||
|
The implemented representation keeps five facts distinct:
|
||||||
|
|
||||||
|
1. source import spelling, including its source file, line, and column;
|
||||||
|
2. contextually expanded canonical import identity;
|
||||||
|
3. canonical physical directory;
|
||||||
|
4. the one declared package name read from eligible source clauses and `.wwi`
|
||||||
|
package markers; and
|
||||||
|
5. the source-file-local default qualifier binding from that declaration to
|
||||||
|
the canonical target.
|
||||||
|
|
||||||
|
Both drivers retain one dynamically allocated `sepbind` occurrence for every
|
||||||
|
real import site. The occurrence stores the source spelling and position plus a
|
||||||
|
stable action index. Contextual `internal` and vendor resolution is therefore
|
||||||
|
rechecked for every source import even if its target action already exists. A
|
||||||
|
separate package dependency vector unions those occurrences, deduplicates by
|
||||||
|
canonical action, and sorts by complete canonical identity/variant/role. That
|
||||||
|
vector alone supplies dependency traversal and compiler `--import` arguments.
|
||||||
|
Patterns, qualifiers, declared names, export closure facts, and generated edges
|
||||||
|
never create source dependency edges.
|
||||||
|
|
||||||
|
The owner-only composed unit preserves byte-sorted source boundaries with one
|
||||||
|
`//ww:module-reset <canonical-owner>` separator per file. Parser nodes carry a
|
||||||
|
source-section ID as well as canonical owner and declared package name. Each
|
||||||
|
real `N_USE` therefore belongs to one source section. `.wwi` emission repeats
|
||||||
|
canonical-owner/package markers as needed for contributing source sections and
|
||||||
|
retains imports only with the declarations from the file that owned them.
|
||||||
|
Interfaces remain source-like transitional data, but canonical owner and
|
||||||
|
declared name are no longer collapsed into one token.
|
||||||
|
|
||||||
|
`w6c` and `w6c_ww` validate every direct export's leading canonical owner
|
||||||
|
against its paired `--import` path. After all direct exports are parsed, they
|
||||||
|
build canonical-path-to-declared-name metadata from those interfaces, apply any
|
||||||
|
vendor `--import-map` only to canonical identity, and bind the imported
|
||||||
|
declaration as the default qualifier of each primary source import. The
|
||||||
|
checkers and code generators select bindings by source-section ID and canonical
|
||||||
|
owner. Qualified and retained bare-import lookups mark only that file's binding
|
||||||
|
used. Two files may consequently bind the same name to different canonical
|
||||||
|
packages, while the graph still contains one edge/action for each target.
|
||||||
|
|
||||||
|
Within one file, two imports that produce the same default qualifier are a
|
||||||
|
redeclared binding; the later unused binding is also reported. An unused import
|
||||||
|
is reported at its own import position even if a sibling file uses the same
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
different name. Any ordinary source import of a package declared `main` is
|
||||||
|
rejected as `package <canonical-path> is a program, not an importable package`,
|
||||||
|
regardless of its path leaf. The one pinned loader exception is an external
|
||||||
|
test's exact same-directory import of the command production: it is rewired to
|
||||||
|
the forced-library test copy. WW admits only that canonical colocated edge.
|
||||||
|
|
||||||
|
Test naming is likewise declaration-based. Production and internal-test
|
||||||
|
variants use the production declared name. When production files exist,
|
||||||
|
external files must declare `<production-declared-name>_test`; a test-only
|
||||||
|
directory may establish one consistent package name from its test files, as in
|
||||||
|
pinned `go/build`. External action identity remains the canonical production
|
||||||
|
identity plus the existing external variant suffix where that production
|
||||||
|
exists. Imports found only in internal or external test files belong only to
|
||||||
|
that variant. Support and generated-main actions retain their isolated
|
||||||
|
identities and archive closures. A generated dispatcher privately binds its
|
||||||
|
tested target through
|
||||||
|
`--test-target-package <canonical-path>` so a command variant declared `main`
|
||||||
|
does not collide with the dispatcher's own synthesized `main`; this is
|
||||||
|
compiler-generated wiring, not source alias syntax. Zero-test dispatchers mark
|
||||||
|
their compiler-owned target/support metadata imports consumed.
|
||||||
|
|
||||||
|
Vendor expansion changes only canonical identity and physical selection. A
|
||||||
|
source spelling such as `lib.codec` can resolve to
|
||||||
|
`domain.app.vendor.lib.codec`, while the vendored package's declaration, for
|
||||||
|
example `package wire`, supplies the file-local qualifier. The driver emits one
|
||||||
|
sorted semantic `--import-map lib.codec domain.app.vendor.lib.codec` and one
|
||||||
|
direct export input despite repeated import occurrences in separate files.
|
||||||
|
The expanded identity continues to own symbols, `.wwi`, archive, voucher, and
|
||||||
|
link inputs.
|
||||||
|
|
||||||
|
Canonical action interning remains the directory/path/variant model of sections
|
||||||
|
11.7 and 11.14. Independent file bindings never clone an action, and a declared
|
||||||
|
name never enters an artifact basename or storage locator. The name is semantic
|
||||||
|
content in the owner unit and export. Changing only a dependency's declaration
|
||||||
|
therefore keeps the same action identity but changes its export bytes, causes
|
||||||
|
each direct importer to be reconsidered, and stops propagation after an
|
||||||
|
importer's regenerated export is unchanged. An identical warm request remains
|
||||||
|
a producer no-op. Build workdir format 14 and test format 13 prevent reuse of
|
||||||
|
older vouchers that lack these semantics.
|
||||||
|
|
||||||
|
Compiler argv still contains exactly the sorted, deduplicated `.wwi` exports of
|
||||||
|
direct canonical dependencies; no transitive `.wwi` and no qualifier-derived
|
||||||
|
path appears. Linker argv still contains only the executable root archive and
|
||||||
|
complete reachable archive closure plus runtime/native inputs. Publication and
|
||||||
|
completion occur only after the corresponding action/product succeeds.
|
||||||
|
|
||||||
|
Responsibility is intentionally split as follows:
|
||||||
|
|
||||||
|
- `internal/wwpackage` classifies production, internal, and external test files
|
||||||
|
from their declarations, derives the allowed external name from the
|
||||||
|
production declaration, expands request patterns, and submits variant roots.
|
||||||
|
It does not resolve imports, choose qualifiers, or create dependency edges.
|
||||||
|
- `cmd/ww/main.c` and `selfhost/cmd/ww/main.ww` own per-site parsing and
|
||||||
|
contextual resolution, canonical directory/action interning, declared-name
|
||||||
|
consistency, imported-command rejection, sorted dependency union, exact tool
|
||||||
|
argv, variant/generated-main construction, persistence, linking, and
|
||||||
|
publication. Their storage, diagnostics, call positions, and allocation
|
||||||
|
failures are isomorphic.
|
||||||
|
- `cmd/w6c`/`cmd/wcc` and `selfhost/cmd/w6c`/`selfhost/cmd/wcc` own export
|
||||||
|
owner/name reading and writing, file-local binding installation, collision
|
||||||
|
and unused-import diagnostics, name/type lookup, canonical symbol ownership,
|
||||||
|
and generated-dispatcher private qualification. Cstage and WWstage emit
|
||||||
|
byte-identical applicable interfaces, assembly, archives, and binaries.
|
||||||
|
- `cmd/wwtest` remains only the test-command dispatcher.
|
||||||
|
|
||||||
|
The behavior follows pinned official Go 1.26.5 source at commit
|
||||||
|
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||||
|
|
||||||
|
- `go/build.Package` stores `Dir`, `Name`, `ImportPath`, production files, and
|
||||||
|
test files independently, while package-clause consistency is checked during
|
||||||
|
file classification
|
||||||
|
([`go/build/build.go`, lines 436–493](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L436-L493),
|
||||||
|
[`go/build/build.go`, lines 939–1049](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L1049)).
|
||||||
|
- The loader interns by resolved `ImportPath`, keeps `ImportPath` and `Name`
|
||||||
|
separate, constructs edges from source imports, and rejects an imported
|
||||||
|
package whose `Name == "main"` except for the exact same-directory test case
|
||||||
|
([`cmd/go/internal/load/pkg.go`, lines 633–636](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L633-L636),
|
||||||
|
[lines 757–806](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L757-L806),
|
||||||
|
[lines 2024–2047](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2024-L2047)).
|
||||||
|
- The test loader builds distinct production/internal/external/generated-main
|
||||||
|
packages, derives external `Name` from `p.Name + "_test"`, handles the
|
||||||
|
same-directory command self-import, and rewrites it to the library-form test
|
||||||
|
copy
|
||||||
|
([`cmd/go/internal/load/test.go`, lines 144–203](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L144-L203),
|
||||||
|
[lines 228–293](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L228-L293),
|
||||||
|
[lines 421–472](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L421-L472)).
|
||||||
|
- `go/types.Package` stores independent path and name. The resolver creates one
|
||||||
|
child scope per source file, uses the imported package's declared name when
|
||||||
|
no alias is present, inserts imports into that file scope, reconciles them
|
||||||
|
with package declarations, and reports unused imports
|
||||||
|
([`go/types/package.go`, lines 26–40](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/package.go#L26-L40),
|
||||||
|
[`go/types/resolver.go`, lines 237–350](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L237-L350),
|
||||||
|
[lines 463–480](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L463-L480),
|
||||||
|
[lines 701–735](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L701-L735)).
|
||||||
|
The production compiler mirrors those rules
|
||||||
|
([`cmd/compile/internal/types2/resolver.go`, lines 223–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L223-L335),
|
||||||
|
[lines 473–486](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L473-L486),
|
||||||
|
[lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)).
|
||||||
|
- Compiler export import reconstructs and interns package descriptors by
|
||||||
|
canonical path while restoring their independently encoded package names and
|
||||||
|
imports
|
||||||
|
([`cmd/compile/internal/importer/ureader.go`, lines 152–196](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/importer/ureader.go#L152-L196),
|
||||||
|
[`go/internal/gcimporter/ureader.go`, lines 224–244](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/internal/gcimporter/ureader.go#L224-L244)).
|
||||||
|
- Work actions consume cached canonical package objects and direct imports,
|
||||||
|
while test execution builds and links the isolated test action graph
|
||||||
|
([`cmd/go/internal/work/action.go`, lines 437–455](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L455),
|
||||||
|
[lines 628–659](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L628-L659),
|
||||||
|
[`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)).
|
||||||
|
|
||||||
|
The deliberately retained source grammar is `import dotted.path;`. Quoted Go
|
||||||
|
imports, explicit aliases, dot imports, and blank imports are not implemented.
|
||||||
|
Because bindings already retain source ownership and position separately from
|
||||||
|
canonical identity and declared name, adding explicit aliases later will not
|
||||||
|
require another package-wide namespace redesign.
|
||||||
|
|
||||||
|
The focused native observer
|
||||||
|
`declared_name_identity_and_file_import_scope` generates every tree
|
||||||
|
temporarily and exercises both stages from independent cold roots. It proves
|
||||||
|
the identity/name/qualifier split, file-local collision and unused behavior,
|
||||||
|
one-edge/action reuse, command and imported-command rules, all test variants,
|
||||||
|
vendor expansion, recursive/direct selection, owner-only units, exact direct
|
||||||
|
exports and archive-only links, warm no-op behavior, declared-name invalidation,
|
||||||
|
rejection-state preservation, normalized argv, artifact/binary identity,
|
||||||
|
allocation-bearing runtime behavior, and request/product-order independence.
|
||||||
|
|
||||||
## 12. Candidate architectures and hard-gate decision
|
## 12. Candidate architectures and hard-gate decision
|
||||||
|
|
||||||
Five candidates were developed as coherent systems, not as feature bins.
|
Five candidates were developed as coherent systems, not as feature bins.
|
||||||
|
|||||||
22
docs/spec.md
22
docs/spec.md
@@ -249,13 +249,25 @@ PackageClause = "package" ident ";" .
|
|||||||
ImportDecl = "import" ident ";" .
|
ImportDecl = "import" ident ";" .
|
||||||
```
|
```
|
||||||
|
|
||||||
- Every source file begins with a package clause. A directory of `.ww`
|
- Every source file begins with a package clause. A directory of eligible
|
||||||
files sharing one package name compiles as a single module.
|
`.ww` files sharing one declared package name compiles as one package. The
|
||||||
- `import foo;` makes module `foo`'s exported names available as
|
declared name need not equal the directory name or the final component of its
|
||||||
`foo.Name`. Self-import is rejected.
|
canonical import identity.
|
||||||
- An executable's entry module is `package main;` with a `fn main`.
|
- `import acme.codec;` loads the canonical package `acme.codec`. If that
|
||||||
|
package declares `package wire;`, the importing file sees its exported names
|
||||||
|
as `wire.Name`; `codec.Name` is not an additional binding. The import binding
|
||||||
|
is scoped to that source file. A sibling file must declare its own import.
|
||||||
|
The package dependency graph is the sorted, deduplicated union of the real
|
||||||
|
imports in all eligible files. 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
|
||||||
|
colocated external-test wiring.
|
||||||
- Only names marked `export` (§5) are visible across module boundaries.
|
- Only names marked `export` (§5) are visible across module boundaries.
|
||||||
|
|
||||||
|
The implemented grammar remains dotted and unaliased. Quoted import paths,
|
||||||
|
explicit aliases, dot imports, and blank imports are not currently accepted.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Declarations
|
## 5. Declarations
|
||||||
|
|||||||
@@ -227,6 +227,20 @@ owns individual `@test` functions.
|
|||||||
Separate compilation is the only driver build path; no compatibility mode
|
Separate compilation is the only driver build path; no compatibility mode
|
||||||
switch remains.
|
switch remains.
|
||||||
|
|
||||||
|
`test/package/package_test.ww` also owns the dual-stage
|
||||||
|
`declared_name_identity_and_file_import_scope` observer. It generates temporary
|
||||||
|
directory trees proving that canonical import identity, physical directory,
|
||||||
|
declared package name, and source-file default qualifier remain distinct;
|
||||||
|
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
|
||||||
|
declared qualifier; compiler argv contains only direct `.wwi` inputs; and its
|
||||||
|
named rejected actions leave neither committed nor staged action artifacts or a
|
||||||
|
published binary. 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.
|
||||||
|
|
||||||
`ww build`, an explicit single-file `ww test -o <stem>`, and each successful
|
`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
|
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
|
artifact directory. The driver acquires it with one fresh `mkdir` and refuses
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package wwfixture;
|
|||||||
|
|
||||||
def protocolversion: i32 = 1;
|
def protocolversion: i32 = 1;
|
||||||
def corpuscount: i32 = 1759;
|
def corpuscount: i32 = 1759;
|
||||||
def errorcount: i32 = 352;
|
def errorcount: i32 = 351;
|
||||||
def compilecount: i32 = 21;
|
def compilecount: i32 = 22;
|
||||||
def runcount: i32 = 209;
|
def runcount: i32 = 209;
|
||||||
def runexitcount: i32 = 1177;
|
def runexitcount: i32 = 1177;
|
||||||
def nativecount: i32 = 3518;
|
def nativecount: i32 = 3518;
|
||||||
def corpushash: str = "38613db49b4c87a14d87fb9392e5500e17cc0c95767fb31d8eb9bc4fe2bf74c5";
|
def corpushash: str = "47d731a8fd089ecdef9a1b9b94f3dfc06a733b7e03236014f095b068a67ce176";
|
||||||
|
|
||||||
type directive = enum i32 {
|
type directive = enum i32 {
|
||||||
ERROR = 0,
|
ERROR = 0,
|
||||||
|
|||||||
@@ -21,15 +21,16 @@ package wwi_test;
|
|||||||
// qualification of the compiler-private name on both stages.
|
// qualification of the compiler-private name on both stages.
|
||||||
//
|
//
|
||||||
// wwileaf — BUG-C (#11) regression pin: a decl-less / export-less
|
// wwileaf — BUG-C (#11) regression pin: a decl-less / export-less
|
||||||
// primary module's `.wwi` `package` line must carry the module's real
|
// primary module's `.wwi` must preserve its independently parsed declaration,
|
||||||
// leaf, NOT the literal default "main". Table-driven over the three
|
// rather than substituting the literal default "main". Table-driven over the three
|
||||||
// decl-less shapes routing the wwi_emit fallback (empty, comment-only,
|
// decl-less shapes routing the wwi_emit fallback (empty, comment-only,
|
||||||
// nested dotted path a.b.c -> leaf c). Each row drives the REAL
|
// nested dotted path a.b.c -> leaf c). Each row drives the REAL
|
||||||
// producer->importer flow on BOTH stages: (a) the dep `.wwi` package
|
// producer->importer flow on BOTH stages: (a) the dep `.wwi` package
|
||||||
// owner marker is the complete path and its package line equals the real leaf,
|
// owner marker is the complete path and its package line equals the real leaf,
|
||||||
// (b) the dep `.wwi` is byte-identical
|
// (b) the dep `.wwi` is byte-identical
|
||||||
// across stages, (c) a root importing the dep RESOLVES on both stages
|
// across stages, (c) a root importing the dep RESOLVES on both stages
|
||||||
// and the two importer `.s` are byte-identical. The owner units and
|
// and both importers diagnose the same file-local unused binding after
|
||||||
|
// obtaining that declared name from export data. The owner units and
|
||||||
// separate exports are fed straight to w6c / w6c_ww (not `ww build`):
|
// separate exports are fed straight to w6c / w6c_ww (not `ww build`):
|
||||||
// the producer-unit shape `//ww:module-reset <path>` + body is exactly
|
// the producer-unit shape `//ww:module-reset <path>` + body is exactly
|
||||||
// what the driver's sep_emit_body emits.
|
// what the driver's sep_emit_body emits.
|
||||||
@@ -331,8 +332,8 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
|
|||||||
"package ", leaf, ";\n",
|
"package ", leaf, ";\n",
|
||||||
body));
|
body));
|
||||||
|
|
||||||
// Leg a — both stages emit the dep `.wwi`; the `package` leaf is
|
// Leg a — both stages emit the dep `.wwi`; the `package` declaration is
|
||||||
// the module's real leaf, not the default "main".
|
// the source declaration supplied independently of its canonical owner.
|
||||||
let cav: []str = [testenv.driver("w6c"), "-c", "-I", cswwi,
|
let cav: []str = [testenv.driver("w6c"), "-c", "-I", cswwi,
|
||||||
"-o", css, prod];
|
"-o", css, prod];
|
||||||
if (!runok(td, "csprod", cav)) { fail(tag, "w6c producer errored"); };
|
if (!runok(td, "csprod", cav)) { fail(tag, "w6c producer errored"); };
|
||||||
@@ -342,7 +343,7 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
|
|||||||
let wanthead: str = strings.concat(strings.concat(strings.concat(
|
let wanthead: str = strings.concat(strings.concat(strings.concat(
|
||||||
"//ww:module ", path), "\npackage "), strings.concat(want, ";\n"));
|
"//ww:module ", path), "\npackage "), strings.concat(want, ";\n"));
|
||||||
if (!strings.hasprefix(testenv.readfile(cswwi), wanthead)) {
|
if (!strings.hasprefix(testenv.readfile(cswwi), wanthead)) {
|
||||||
fail(tag, ".wwi owner or package leaf is incomplete (BUG-C)");
|
fail(tag, ".wwi owner or declared package name is incomplete (BUG-C)");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Leg b — the dep `.wwi` is byte-identical across stages (rule 10).
|
// Leg b — the dep `.wwi` is byte-identical across stages (rule 10).
|
||||||
@@ -350,9 +351,11 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
|
|||||||
fail(tag, "w6c vs w6c_ww .wwi differ (rule 10)");
|
fail(tag, "w6c vs w6c_ww .wwi differ (rule 10)");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Leg c — a root importing the dep RESOLVES from a separate export on
|
// Leg c — a root importing the empty dep obtains its default qualifier from
|
||||||
// both stages (pre-fix: "package main does not match import path"
|
// the separate export on both stages. With no exported declaration to use,
|
||||||
// REJECT).
|
// Go-style file scope requires the import itself to be rejected as unused;
|
||||||
|
// the diagnostic proves that the reader recovered the declared name rather
|
||||||
|
// than substituting the historical default `main` declaration.
|
||||||
testenv.writefile(root, strings.concat(
|
testenv.writefile(root, strings.concat(
|
||||||
"//ww:module-reset\n",
|
"//ww:module-reset\n",
|
||||||
"package main;\n",
|
"package main;\n",
|
||||||
@@ -360,22 +363,59 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
|
|||||||
"export fn main() i32 = { return 42; };\n"));
|
"export fn main() i32 = { return 42; };\n"));
|
||||||
let rcav: []str = [testenv.driver("w6c"), "-c", "--import", path,
|
let rcav: []str = [testenv.driver("w6c"), "-c", "--import", path,
|
||||||
cswwi, "-o", rcss, root];
|
cswwi, "-o", rcss, root];
|
||||||
if (!runok(td, "csroot", rcav)) {
|
|
||||||
fail(tag, "w6c rejected the import (BUG-C)");
|
|
||||||
};
|
|
||||||
let rwav: []str = [testenv.driver("w6c_ww"), "-c", "--import", path,
|
let rwav: []str = [testenv.driver("w6c_ww"), "-c", "--import", path,
|
||||||
wwwwi, "-o", rwws, root];
|
wwwwi, "-o", rwws, root];
|
||||||
if (!runok(td, "wsroot", rwav)) {
|
let rco: testenv.commandout;
|
||||||
fail(tag, "w6c_ww rejected the import (BUG-C)");
|
let rwo: testenv.commandout;
|
||||||
|
testenv.runcommand(td, td, "csroot", rcav, lifetime(), &rco);
|
||||||
|
testenv.runcommand(td, td, "wsroot", rwav, lifetime(), &rwo);
|
||||||
|
let (prefix, suffix) = strings.rcut(path, ".");
|
||||||
|
let leaf: str = suffix;
|
||||||
|
if (leaf.len == 0) { leaf = path; };
|
||||||
|
let unused: str;
|
||||||
|
if (testenv.same(want, leaf)) {
|
||||||
|
unused = strings.concat(strings.concat("\"", path),
|
||||||
|
"\" imported and not used");
|
||||||
|
} else {
|
||||||
|
unused = strings.concat(strings.concat(strings.concat(
|
||||||
|
"\"", path), "\" imported as "), strings.concat(want,
|
||||||
|
" and not used"));
|
||||||
};
|
};
|
||||||
if (!testenv.same(testenv.readfile(rcss), testenv.readfile(rwws))) {
|
if (rco.termination != exec.termination.EXIT || rco.code == 0
|
||||||
fail(tag, "importer .s differ cs vs ww (rule 10)");
|
|| rwo.termination != exec.termination.EXIT || rwo.code == 0
|
||||||
|
|| !testenv.same(rco.stderr, rwo.stderr)
|
||||||
|
|| !testenv.has(rco.stderr, unused)) {
|
||||||
|
fail(tag, "imported-name or unused-import behavior differs by stage");
|
||||||
|
};
|
||||||
|
testenv.clean(td);
|
||||||
|
};
|
||||||
|
|
||||||
|
fn resetfallbackrow() void = {
|
||||||
|
let td: str = testenv.fresh();
|
||||||
|
let src: str = strings.concat(td, "/reset.ww");
|
||||||
|
testenv.writefile(src, strings.concat(
|
||||||
|
"//ww:module-reset raw.owner\n",
|
||||||
|
"export fn value() i32 = { return 7; };\n"));
|
||||||
|
let cs: str = strings.concat(td, "/c.wwi");
|
||||||
|
let ws: str = strings.concat(td, "/w.wwi");
|
||||||
|
let cav: []str = [testenv.driver("w6c"), "-c", "-I", cs,
|
||||||
|
"-o", strings.concat(td, "/c.s"), src];
|
||||||
|
let wav: []str = [testenv.driver("w6c_ww"), "-c", "-I", ws,
|
||||||
|
"-o", strings.concat(td, "/w.s"), src];
|
||||||
|
if (!runok(td, "reset-c", cav) || !runok(td, "reset-w", wav)) {
|
||||||
|
fail("nested", "a package-less reset owner failed to export");
|
||||||
|
};
|
||||||
|
let body: str = testenv.readfile(cs);
|
||||||
|
if (!testenv.same(body, testenv.readfile(ws))
|
||||||
|
|| !testenv.has(body, "//ww:module raw.owner\npackage main;\n")
|
||||||
|
|| !testenv.has(body, "export fn value() i32;")) {
|
||||||
|
fail("nested", "reset-owner fallback lost its source section");
|
||||||
};
|
};
|
||||||
testenv.clean(td);
|
testenv.clean(td);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Each shape lacks any module-tagged decl, so wwi_emit's decl-scan
|
// Each shape lacks any module-tagged decl, so wwi_emit's decl-scan
|
||||||
// misses and the leaf must come from the parse-stamped N_FILE identity.
|
// misses and the declaration must come from the parse-stamped N_FILE fact.
|
||||||
@test fn wwileaf_empty() void = {
|
@test fn wwileaf_empty() void = {
|
||||||
leafrow("empty", "emptymod", "emptymod", "", "emptymod");
|
leafrow("empty", "emptymod", "emptymod", "", "emptymod");
|
||||||
};
|
};
|
||||||
@@ -386,4 +426,5 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
|
|||||||
|
|
||||||
@test fn wwileaf_nested() void = {
|
@test fn wwileaf_nested() void = {
|
||||||
leafrow("nested", "a.b.c", "c", "", "c");
|
leafrow("nested", "a.b.c", "c", "", "c");
|
||||||
|
resetfallbackrow();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -319,8 +319,8 @@ fn workescape(s: str) str = {
|
|||||||
return strings.frombytes(out);
|
return strings.frombytes(out);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn localidentity(dir: str, leaf: str) str = {
|
fn localidentity(dir: str, declaredname: str) str = {
|
||||||
let out: []u8 = alloc([], (dir.len * 4 + leaf.len + 16): u64)!;
|
let out: []u8 = alloc([], (dir.len * 4 + 16): u64)!;
|
||||||
let prefix: str = "__wwlocal.p";
|
let prefix: str = "__wwlocal.p";
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < prefix.len) { append(out, prefix[i]); i += 1; };
|
for (i < prefix.len) { append(out, prefix[i]); i += 1; };
|
||||||
@@ -343,9 +343,6 @@ fn localidentity(dir: str, leaf: str) str = {
|
|||||||
};
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
append(out, '.');
|
|
||||||
i = 0;
|
|
||||||
for (i < leaf.len) { append(out, leaf[i]); i += 1; };
|
|
||||||
return strings.frombytes(out);
|
return strings.frombytes(out);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1241,14 +1238,16 @@ fn hexbytes(value: str) str = {
|
|||||||
let externalmaincompile: str = linecontaining(ctrace,
|
let externalmaincompile: str = linecontaining(ctrace,
|
||||||
"pkg_test-external-test-main.unit.ww");
|
"pkg_test-external-test-main.unit.ww");
|
||||||
assert(same(samemaincompile, strings.concat(
|
assert(same(samemaincompile, strings.concat(
|
||||||
"-T --entry --test-support-module test -c --import pkg ",
|
"-T --entry --test-support-module test ",
|
||||||
|
"--test-target-package pkg -c --import pkg ",
|
||||||
sharedwork, "pkg-internal-test.wwi --import test ",
|
sharedwork, "pkg-internal-test.wwi --import test ",
|
||||||
sharedwork, "test.wwi -I ", sharedwork,
|
sharedwork, "test.wwi -I ", sharedwork,
|
||||||
"pkg-internal-test-main.wwi -o ", sharedwork,
|
"pkg-internal-test-main.wwi -o ", sharedwork,
|
||||||
"pkg-internal-test-main.s ", sharedwork,
|
"pkg-internal-test-main.s ", sharedwork,
|
||||||
"pkg-internal-test-main.unit.ww")));
|
"pkg-internal-test-main.unit.ww")));
|
||||||
assert(same(externalmaincompile, strings.concat(
|
assert(same(externalmaincompile, strings.concat(
|
||||||
"-T --entry --test-support-module test -c --import pkg_test ",
|
"-T --entry --test-support-module test ",
|
||||||
|
"--test-target-package pkg_test -c --import pkg_test ",
|
||||||
sharedwork, "pkg_test-external-test.wwi --import test ",
|
sharedwork, "pkg_test-external-test.wwi --import test ",
|
||||||
sharedwork, "test.wwi -I ", sharedwork,
|
sharedwork, "test.wwi -I ", sharedwork,
|
||||||
"pkg_test-external-test-main.wwi -o ", sharedwork,
|
"pkg_test-external-test-main.wwi -o ", sharedwork,
|
||||||
@@ -1495,9 +1494,9 @@ fn hexbytes(value: str) str = {
|
|||||||
aliasunit];
|
aliasunit];
|
||||||
runcommand(root, strings.concat("alias-unowned-", aliasstages[i]),
|
runcommand(root, strings.concat("alias-unowned-", aliasstages[i]),
|
||||||
rawav, (30i64 * (time.second: i64)): time.duration, &out);
|
rawav, (30i64 * (time.second: i64)): time.duration, &out);
|
||||||
assert(out.termination == exec.termination.EXIT && out.code != 0);
|
expectexit(&out, 0);
|
||||||
assert(has(out.stderr, "package")
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||||
&& has(out.stderr, "does not match import path"));
|
assert(os.exists(asmout));
|
||||||
let badav: []str = [driver(aliasstages[i]), "-c",
|
let badav: []str = [driver(aliasstages[i]), "-c",
|
||||||
"--test-support-module", "arbitrary", "-o", asmout, aliasunit];
|
"--test-support-module", "arbitrary", "-o", asmout, aliasunit];
|
||||||
runcommand(root, strings.concat("alias-arbitrary-", aliasstages[i]),
|
runcommand(root, strings.concat("alias-arbitrary-", aliasstages[i]),
|
||||||
@@ -4226,9 +4225,13 @@ fn hexbytes(value: str) str = {
|
|||||||
let leftbody: str = strings.concat(
|
let leftbody: str = strings.concat(
|
||||||
"package parityleft;\n",
|
"package parityleft;\n",
|
||||||
"import ", baseidentity, ";\n",
|
"import ", baseidentity, ";\n",
|
||||||
"import ", baseidentity, ";\n",
|
|
||||||
"export fn value() i32 = { return ",
|
"export fn value() i32 = { return ",
|
||||||
"paritybase.value(); };\n");
|
"paritybase.value(); };\n");
|
||||||
|
let leftz: str = strings.concat(
|
||||||
|
"package parityleft;\n",
|
||||||
|
"import ", baseidentity, ";\n",
|
||||||
|
"export fn repeated_binding() i32 = { return ",
|
||||||
|
"paritybase.value(); };\n");
|
||||||
let rightbody: str = strings.concat(
|
let rightbody: str = strings.concat(
|
||||||
"package parityright;\n",
|
"package parityright;\n",
|
||||||
"import ", baseidentity, ";\n",
|
"import ", baseidentity, ";\n",
|
||||||
@@ -4242,7 +4245,8 @@ fn hexbytes(value: str) str = {
|
|||||||
"parityright.value() + 1; };\n");
|
"parityright.value() + 1; };\n");
|
||||||
writefile(strings.concat(base, "/a.ww"), basea);
|
writefile(strings.concat(base, "/a.ww"), basea);
|
||||||
writefile(strings.concat(base, "/z.ww"), basez);
|
writefile(strings.concat(base, "/z.ww"), basez);
|
||||||
writefile(strings.concat(left, "/left.ww"), leftbody);
|
writefile(strings.concat(left, "/a.ww"), leftbody);
|
||||||
|
writefile(strings.concat(left, "/z.ww"), leftz);
|
||||||
writefile(strings.concat(right, "/right.ww"), rightbody);
|
writefile(strings.concat(right, "/right.ww"), rightbody);
|
||||||
writefile(strings.concat(target, "/main.ww"), rootbody);
|
writefile(strings.concat(target, "/main.ww"), rootbody);
|
||||||
|
|
||||||
@@ -4316,7 +4320,8 @@ fn hexbytes(value: str) str = {
|
|||||||
"//ww:module-reset ", baseidentity, "\n", basea,
|
"//ww:module-reset ", baseidentity, "\n", basea,
|
||||||
"\n//ww:module-reset ", baseidentity, "\n", basez, "\n"),
|
"\n//ww:module-reset ", baseidentity, "\n", basez, "\n"),
|
||||||
strings.concat("//ww:module-reset ", leftidentity, "\n",
|
strings.concat("//ww:module-reset ", leftidentity, "\n",
|
||||||
leftbody, "\n"),
|
leftbody, "\n//ww:module-reset ", leftidentity, "\n",
|
||||||
|
leftz, "\n"),
|
||||||
strings.concat("//ww:module-reset ", rightidentity, "\n",
|
strings.concat("//ww:module-reset ", rightidentity, "\n",
|
||||||
rightbody, "\n"),
|
rightbody, "\n"),
|
||||||
strings.concat("//ww:module-reset ", rootidentity, "\n", rootbody,
|
strings.concat("//ww:module-reset ", rootidentity, "\n", rootbody,
|
||||||
@@ -4425,9 +4430,8 @@ fn hexbytes(value: str) str = {
|
|||||||
assert(has(assembly, strings.concat(identities[ai], ".value")));
|
assert(has(assembly, strings.concat(identities[ai], ".value")));
|
||||||
};
|
};
|
||||||
if (ai == 3) {
|
if (ai == 3) {
|
||||||
assert(has(exportf, strings.concat("\npackage paritycommand",
|
assert(has(exportf, "\npackage main;\n"));
|
||||||
";\n")));
|
assert(!has(exportf, "\npackage paritycommand;\n"));
|
||||||
assert(!has(exportf, "\npackage main;\n"));
|
|
||||||
};
|
};
|
||||||
if (si == 0) {
|
if (si == 0) {
|
||||||
referenceexports[ai] = strings.dup(exportf);
|
referenceexports[ai] = strings.dup(exportf);
|
||||||
@@ -4476,18 +4480,23 @@ fn hexbytes(value: str) str = {
|
|||||||
assert(same(linecontaining(ctrace, strings.concat(artifacts[3],
|
assert(same(linecontaining(ctrace, strings.concat(artifacts[3],
|
||||||
".unit.ww")), rootline));
|
".unit.ww")), rootline));
|
||||||
assert(!has(rootline, strings.concat(artifacts[0], ".wwi")));
|
assert(!has(rootline, strings.concat(artifacts[0], ".wwi")));
|
||||||
// The primary command declaration is accepted only when the compiler
|
// Canonical owner and declared name stay independent even in a raw
|
||||||
// receives command classification from --entry. Imported interfaces and
|
// package compile. --entry selects link-root code generation; it is not
|
||||||
// ordinary package compiles retain strict identity-leaf validation.
|
// permission to replace canonical owner with the declared name.
|
||||||
let rejectwwi: str = strings.concat(root, "/reject-", tags[si], ".wwi");
|
let rejectwwi: str = strings.concat(root, "/reject-", tags[si], ".wwi");
|
||||||
let rejectasm: str = strings.concat(root, "/reject-", tags[si], ".s");
|
let rejectasm: str = strings.concat(root, "/reject-", tags[si], ".s");
|
||||||
let rejectav: []str = [driver(compilers[si]), "-c", "-I", rejectwwi,
|
let rejectav: []str = [driver(compilers[si]), "-c", "--import",
|
||||||
"-o", rejectasm, strings.concat(work, artifacts[3], ".unit.ww")];
|
leftidentity,
|
||||||
|
strings.concat(work, artifacts[1], ".wwi"),
|
||||||
|
"--import", rightidentity,
|
||||||
|
strings.concat(work, artifacts[2], ".wwi"),
|
||||||
|
"-I", rejectwwi, "-o", rejectasm,
|
||||||
|
strings.concat(work, artifacts[3], ".unit.ww")];
|
||||||
runcommand(root, strings.concat("command-without-entry-", tags[si]),
|
runcommand(root, strings.concat("command-without-entry-", tags[si]),
|
||||||
rejectav, (60i64 * (time.second: i64)): time.duration, &out);
|
rejectav, (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 1);
|
expectexit(&out, 0);
|
||||||
assert(has(out.stderr, "does not match import path"));
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||||
assert(has(out.stderr, rootidentity));
|
assert(os.exists(rejectwwi) && os.exists(rejectasm));
|
||||||
let ownerrejectwwi: str = strings.concat(root, "/owner-reject-",
|
let ownerrejectwwi: str = strings.concat(root, "/owner-reject-",
|
||||||
tags[si], ".wwi");
|
tags[si], ".wwi");
|
||||||
let ownerrejectasm: str = strings.concat(root, "/owner-reject-",
|
let ownerrejectasm: str = strings.concat(root, "/owner-reject-",
|
||||||
@@ -4726,11 +4735,11 @@ fn hexbytes(value: str) str = {
|
|||||||
"package main_test;\n",
|
"package main_test;\n",
|
||||||
"import ", commandid, ";\n",
|
"import ", commandid, ";\n",
|
||||||
"@test fn command_external() void = { ",
|
"@test fn command_external() void = { ",
|
||||||
"assert(cmdtool.value() == 41); };\n"));
|
"assert(main.value() == 41); };\n"));
|
||||||
writefile(strings.concat(importer, "/importer.ww"), strings.concat(
|
writefile(strings.concat(importer, "/importer.ww"), strings.concat(
|
||||||
"package importer;\n",
|
"package importer;\n",
|
||||||
"import ", commandid, ";\n",
|
"import ", commandid, ";\n",
|
||||||
"export fn value() i32 = { return cmdtool.value(); };\n"));
|
"export fn value() i32 = { return main.value(); };\n"));
|
||||||
writeexecutable(wrapper, strings.concat(
|
writeexecutable(wrapper, strings.concat(
|
||||||
"#!/bin/sh\n",
|
"#!/bin/sh\n",
|
||||||
"printf 'BEGIN' >> \"$WW_COMMAND_COMPILER_TRACE\"\n",
|
"printf 'BEGIN' >> \"$WW_COMMAND_COMPILER_TRACE\"\n",
|
||||||
@@ -4830,8 +4839,12 @@ fn hexbytes(value: str) str = {
|
|||||||
strings.concat(artifacts[4], ".unit.new"));
|
strings.concat(artifacts[4], ".unit.new"));
|
||||||
assert(has(internalmainline, strings.concat("<--import><", internalid,
|
assert(has(internalmainline, strings.concat("<--import><", internalid,
|
||||||
"><", work, artifacts[1], ".wwi>")));
|
"><", work, artifacts[1], ".wwi>")));
|
||||||
|
assert(has(internalmainline, strings.concat(
|
||||||
|
"<--test-target-package><", internalid, ">")));
|
||||||
assert(has(externalmainline, strings.concat("<--import><", externalid,
|
assert(has(externalmainline, strings.concat("<--import><", externalid,
|
||||||
"><", work, artifacts[2], ".wwi>")));
|
"><", work, artifacts[2], ".wwi>")));
|
||||||
|
assert(has(externalmainline, strings.concat(
|
||||||
|
"<--test-target-package><", externalid, ">")));
|
||||||
assert(occurrences(ctrace, strings.concat("<", work, artifacts[0],
|
assert(occurrences(ctrace, strings.concat("<", work, artifacts[0],
|
||||||
".unit.new>")) == 1);
|
".unit.new>")) == 1);
|
||||||
assert(has(readfile(strings.concat(work, artifacts[0], ".s")),
|
assert(has(readfile(strings.concat(work, artifacts[0], ".s")),
|
||||||
@@ -4870,7 +4883,7 @@ fn hexbytes(value: str) str = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// The same command action is not generally source-importable. It is
|
// The same command action is not generally source-importable. It is
|
||||||
// classified before leaf validation so this Go-like diagnostic is stable,
|
// classified from its declaration so this Go-like diagnostic is stable,
|
||||||
// and graph failure occurs before any compiler invocation.
|
// and graph failure occurs before any compiler invocation.
|
||||||
clean(trace);
|
clean(trace);
|
||||||
writefile(trace, "");
|
writefile(trace, "");
|
||||||
@@ -7844,6 +7857,547 @@ fn runtimepath(relative: str) str = {
|
|||||||
// artifact in place of the fixed <package>.test stem; -o without -c
|
// artifact in place of the fixed <package>.test stem; -o without -c
|
||||||
// has nothing to name (runs execute from the temp root); one name
|
// has nothing to name (runs execute from the temp root); one name
|
||||||
// cannot fan out over multiple packages (Go's `go test -o` rule).
|
// cannot fan out over multiple packages (Go's `go test -o` rule).
|
||||||
|
@test fn declared_name_identity_and_file_import_scope() void = {
|
||||||
|
let root: str = fresh();
|
||||||
|
let source: str = strings.concat(root, "/source");
|
||||||
|
let tools: str = strings.concat(root, "/tools");
|
||||||
|
let codec: str = strings.concat(source, "/acme/codec");
|
||||||
|
let bridge: str = strings.concat(source, "/acme/bridge");
|
||||||
|
let direct: str = strings.concat(source, "/cmd/direct");
|
||||||
|
let app: str = strings.concat(source, "/cmd/app");
|
||||||
|
let scopeone: str = strings.concat(source, "/scope/one");
|
||||||
|
let scopetwo: str = strings.concat(source, "/scope/two");
|
||||||
|
let scoped: str = strings.concat(source, "/cmd/scoped");
|
||||||
|
let repeated: str = strings.concat(source, "/cmd/repeated");
|
||||||
|
let leafbad: str = strings.concat(source, "/cmd/leafbad");
|
||||||
|
let leak: str = strings.concat(source, "/cmd/leak");
|
||||||
|
let duplicate: str = strings.concat(source, "/cmd/duplicate");
|
||||||
|
let collision: str = strings.concat(source, "/cmd/collision");
|
||||||
|
let crosscollision: str = strings.concat(source, "/cmd/crosscollision");
|
||||||
|
let conflict: str = strings.concat(source, "/conflict/pkg");
|
||||||
|
let leafmain: str = strings.concat(source, "/domain/main");
|
||||||
|
let program: str = strings.concat(source, "/domain/program");
|
||||||
|
let leafmainuser: str = strings.concat(source, "/cmd/leafmain");
|
||||||
|
let programuser: str = strings.concat(source, "/cmd/programuser");
|
||||||
|
let testcodec: str = strings.concat(source, "/testpkg/codec");
|
||||||
|
let testhelper: str = strings.concat(source, "/testonly/helper");
|
||||||
|
let vendored: str = strings.concat(source,
|
||||||
|
"/vend/vendor/short/codec");
|
||||||
|
let vendorclient: str = strings.concat(source, "/vend/client");
|
||||||
|
let dirs: []str = [source, tools, codec, bridge, direct, app, scopeone,
|
||||||
|
scopetwo, scoped, repeated, leafbad, leak, duplicate, collision,
|
||||||
|
crosscollision, conflict, leafmain, program, leafmainuser, programuser, testcodec,
|
||||||
|
testhelper, vendored, vendorclient];
|
||||||
|
let di: i32 = 0;
|
||||||
|
for (di < dirs.len) { mkdirall(dirs[di]); di += 1; };
|
||||||
|
|
||||||
|
let wirebody: str = strings.concat(
|
||||||
|
"package wire;\n",
|
||||||
|
"export fn value() i32 = { return 42; };\n");
|
||||||
|
let cablebody: str = strings.concat(
|
||||||
|
"package cable;\n",
|
||||||
|
"export fn value() i32 = { return 42; };\n");
|
||||||
|
let codecfile: str = strings.concat(codec, "/codec.ww");
|
||||||
|
writefile(codecfile, wirebody);
|
||||||
|
writefile(strings.concat(bridge, "/bridge.ww"), strings.concat(
|
||||||
|
"package bridge;\nimport acme.codec;\n",
|
||||||
|
// WW retains its direct-import bare-declaration convenience. It is
|
||||||
|
// useful here because changing only the dependency declaration leaves
|
||||||
|
// this source unchanged while still forcing its action to reconsider.
|
||||||
|
"export fn bridged() i32 = { return value(); };\n"));
|
||||||
|
writefile(strings.concat(direct, "/main.ww"), strings.concat(
|
||||||
|
"package main;\nimport acme.codec;\n",
|
||||||
|
"fn main() i32 = { return wire.value(); };\n"));
|
||||||
|
writefile(strings.concat(app, "/main.ww"), strings.concat(
|
||||||
|
"package main;\nimport acme.bridge;\n",
|
||||||
|
"fn main() i32 = { return bridge.bridged(); };\n"));
|
||||||
|
|
||||||
|
writefile(strings.concat(scopeone, "/one.ww"),
|
||||||
|
"package same;\nexport fn value() i32 = { return 20; };\n");
|
||||||
|
writefile(strings.concat(scopetwo, "/two.ww"),
|
||||||
|
"package same;\nexport fn value() i32 = { return 22; };\n");
|
||||||
|
writefile(strings.concat(scoped, "/a.ww"), strings.concat(
|
||||||
|
"package main;\nimport scope.one;\n",
|
||||||
|
"fn left() i32 = { return same.value(); };\n"));
|
||||||
|
writefile(strings.concat(scoped, "/b.ww"), strings.concat(
|
||||||
|
"package main;\nimport scope.two;\n",
|
||||||
|
"fn right() i32 = { return same.value(); };\n"));
|
||||||
|
writefile(strings.concat(scoped, "/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return left() + right(); };\n");
|
||||||
|
|
||||||
|
writefile(strings.concat(repeated, "/a.ww"), strings.concat(
|
||||||
|
"package main;\nimport acme.codec;\n",
|
||||||
|
"fn first() i32 = { return wire.value(); };\n"));
|
||||||
|
writefile(strings.concat(repeated, "/b.ww"), strings.concat(
|
||||||
|
"package main;\nimport acme.codec;\n",
|
||||||
|
"fn second() i32 = { return wire.value(); };\n"));
|
||||||
|
writefile(strings.concat(repeated, "/main.ww"), strings.concat(
|
||||||
|
"package main;\n",
|
||||||
|
"fn main() i32 = { return first() - second(); };\n"));
|
||||||
|
|
||||||
|
writefile(strings.concat(leafbad, "/main.ww"), strings.concat(
|
||||||
|
"package main;\nimport acme.codec;\n",
|
||||||
|
"fn main() i32 = { return codec.value(); };\n"));
|
||||||
|
writefile(strings.concat(leak, "/a.ww"), strings.concat(
|
||||||
|
"package main;\nimport acme.codec;\n",
|
||||||
|
"fn anchor() i32 = { return 1; };\n"));
|
||||||
|
writefile(strings.concat(leak, "/b.ww"),
|
||||||
|
"package main;\nfn leaked() i32 = { return wire.value(); };\n");
|
||||||
|
writefile(strings.concat(leak, "/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return leaked(); };\n");
|
||||||
|
writefile(strings.concat(duplicate, "/main.ww"), strings.concat(
|
||||||
|
"package main;\nimport scope.one;\nimport scope.two;\n",
|
||||||
|
"fn main() i32 = { return same.value(); };\n"));
|
||||||
|
writefile(strings.concat(collision, "/main.ww"), strings.concat(
|
||||||
|
"package main;\nimport scope.one;\n",
|
||||||
|
"fn same() i32 = { return 0; };\n",
|
||||||
|
"fn main() i32 = { return same(); };\n"));
|
||||||
|
writefile(strings.concat(crosscollision, "/a.ww"), strings.concat(
|
||||||
|
"package main;\nimport scope.one;\n",
|
||||||
|
"fn fromdep() i32 = { return same.value(); };\n"));
|
||||||
|
writefile(strings.concat(crosscollision, "/b.ww"), strings.concat(
|
||||||
|
"package main;\nfn same() i32 = { return 0; };\n",
|
||||||
|
"fn main() i32 = { return fromdep(); };\n"));
|
||||||
|
writefile(strings.concat(conflict, "/a.ww"),
|
||||||
|
"package first;\nexport fn a() i32 = { return 1; };\n");
|
||||||
|
writefile(strings.concat(conflict, "/b.ww"),
|
||||||
|
"package second;\nexport fn b() i32 = { return 2; };\n");
|
||||||
|
|
||||||
|
writefile(strings.concat(leafmain, "/utility.ww"),
|
||||||
|
"package utility;\nexport fn value() i32 = { return 7; };\n");
|
||||||
|
writefile(strings.concat(program, "/program.ww"),
|
||||||
|
"package main;\nexport fn value() i32 = { return 9; };\n");
|
||||||
|
writefile(strings.concat(leafmainuser, "/main.ww"), strings.concat(
|
||||||
|
"package main;\nimport domain.main;\n",
|
||||||
|
"fn main() i32 = { return utility.value(); };\n"));
|
||||||
|
writefile(strings.concat(programuser, "/main.ww"), strings.concat(
|
||||||
|
"package main;\nimport domain.program;\n",
|
||||||
|
"fn main() i32 = { return main.value(); };\n"));
|
||||||
|
|
||||||
|
writefile(strings.concat(testhelper, "/helper.ww"),
|
||||||
|
"package helper;\nexport fn value() i32 = { return 1; };\n");
|
||||||
|
writefile(strings.concat(testcodec, "/codec.ww"), wirebody);
|
||||||
|
writefile(strings.concat(testcodec, "/internal_test.ww"), strings.concat(
|
||||||
|
"package wire;\nimport testonly.helper;\n",
|
||||||
|
"@test fn internal_name_uses_declaration() void = {\n",
|
||||||
|
" assert(value() + helper.value() == 43);\n};\n"));
|
||||||
|
writefile(strings.concat(testcodec, "/external_test.ww"), strings.concat(
|
||||||
|
"package wire_test;\nimport testpkg.codec;\n",
|
||||||
|
"@test fn external_name_uses_declaration() void = {\n",
|
||||||
|
" assert(wire.value() == 42);\n};\n"));
|
||||||
|
|
||||||
|
writefile(strings.concat(vendored, "/codec.ww"),
|
||||||
|
"package cable;\nexport fn value() i32 = { return 13; };\n");
|
||||||
|
writefile(strings.concat(vendorclient, "/a.ww"), strings.concat(
|
||||||
|
"package main;\nimport short.codec;\n",
|
||||||
|
"fn vendora() i32 = { return cable.value(); };\n"));
|
||||||
|
writefile(strings.concat(vendorclient, "/b.ww"), strings.concat(
|
||||||
|
"package main;\nimport short.codec;\n",
|
||||||
|
"fn vendorb() i32 = { return cable.value(); };\n"));
|
||||||
|
writefile(strings.concat(vendorclient, "/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return vendora(); };\n");
|
||||||
|
|
||||||
|
let compilerwrapper: str = strings.concat(tools, "/w6c.sh");
|
||||||
|
writeexecutable(compilerwrapper, strings.concat(
|
||||||
|
"#!/bin/sh\n",
|
||||||
|
"printf 'BEGIN' >> \"$WW_NAME_COMPILER_TRACE\"\n",
|
||||||
|
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||||
|
"\"$WW_NAME_COMPILER_TRACE\"; done\n",
|
||||||
|
"printf '\\n' >> \"$WW_NAME_COMPILER_TRACE\"\n",
|
||||||
|
"exec \"$WW_NAME_REAL_COMPILER\" \"$@\"\n"));
|
||||||
|
|
||||||
|
let stages: []str = ["ww", "ww_ww"];
|
||||||
|
let compilers: []str = ["w6c", "w6c_ww"];
|
||||||
|
let assemblers: []str = ["w6a", "w6a_ww"];
|
||||||
|
let linkers: []str = ["w6l", "w6l_ww"];
|
||||||
|
let works: []str = [strings.concat(root, "/c-work"),
|
||||||
|
strings.concat(root, "/ww-work")];
|
||||||
|
let traces: []str = [strings.concat(root, "/c-compiler"),
|
||||||
|
strings.concat(root, "/ww-compiler")];
|
||||||
|
let directbins: []str = [strings.concat(root, "/c-direct"),
|
||||||
|
strings.concat(root, "/ww-direct")];
|
||||||
|
let appbins: []str = [strings.concat(root, "/c-app"),
|
||||||
|
strings.concat(root, "/ww-app")];
|
||||||
|
let scopedbins: []str = [strings.concat(root, "/c-scoped"),
|
||||||
|
strings.concat(root, "/ww-scoped")];
|
||||||
|
let repeatedbins: []str = [strings.concat(root, "/c-repeated"),
|
||||||
|
strings.concat(root, "/ww-repeated")];
|
||||||
|
let leafmainbins: []str = [strings.concat(root, "/c-leafmain"),
|
||||||
|
strings.concat(root, "/ww-leafmain")];
|
||||||
|
let vendorbins: []str = [strings.concat(root, "/c-vendor"),
|
||||||
|
strings.concat(root, "/ww-vendor")];
|
||||||
|
let actions: []str = ["acme.codec", "acme.bridge", "cmd.direct",
|
||||||
|
"cmd.app", "scope.one", "scope.two", "cmd.scoped",
|
||||||
|
"cmd.repeated", "domain.main", "cmd.leafmain",
|
||||||
|
"vend.vendor.short.codec", "vend.client"];
|
||||||
|
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
|
||||||
|
let artifactrefs: []str = alloc([], (actions.len * suffixes.len): u64)!;
|
||||||
|
let ari: i32 = 0;
|
||||||
|
for (ari < actions.len * suffixes.len) {
|
||||||
|
append(artifactrefs, "");
|
||||||
|
ari += 1;
|
||||||
|
};
|
||||||
|
let binaryrefs: []str = ["", "", "", "", "", ""];
|
||||||
|
let diagnosticrefs: []str = ["", "", "", "", "", ""];
|
||||||
|
let directtraceref: str = "";
|
||||||
|
let scopedtraceref: str = "";
|
||||||
|
let repeatedtraceref: str = "";
|
||||||
|
let changedtraceref: str = "";
|
||||||
|
let initialwwiref: str = "";
|
||||||
|
let testoutref: str = "";
|
||||||
|
let baseenv: []str = os.getenvs();
|
||||||
|
let si: i32 = 0;
|
||||||
|
for (si < stages.len) {
|
||||||
|
rewritefile(codecfile, wirebody);
|
||||||
|
assert(os.mkdir(works[si], 448i32) == 0);
|
||||||
|
writefile(traces[si], "");
|
||||||
|
let env: []str = alloc([], (baseenv.len + 7): u64)!;
|
||||||
|
let ei: i32 = 0;
|
||||||
|
for (ei < baseenv.len) {
|
||||||
|
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei], "WW_W6A=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei], "WW_SRCLIB=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_NAME_COMPILER_TRACE=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_NAME_REAL_COMPILER=")) {
|
||||||
|
append(env, baseenv[ei]);
|
||||||
|
};
|
||||||
|
ei += 1;
|
||||||
|
};
|
||||||
|
append(env, strings.concat("WW_W6C=", compilerwrapper));
|
||||||
|
append(env, strings.concat("WW_W6A=", driver(assemblers[si])));
|
||||||
|
append(env, strings.concat("WW_W6L=", driver(linkers[si])));
|
||||||
|
append(env, strings.concat("WW_SRCLIB=", repo(), "/lib"));
|
||||||
|
append(env, strings.concat("WW_NAME_COMPILER_TRACE=", traces[si]));
|
||||||
|
append(env, strings.concat("WW_NAME_REAL_COMPILER=",
|
||||||
|
driver(compilers[si])));
|
||||||
|
|
||||||
|
// A directly selected library keeps canonical action/artifact identity
|
||||||
|
// even though its declaration is unrelated to the path leaf.
|
||||||
|
let out: commandout;
|
||||||
|
let selectav: []str = [driver(stages[si]), "build", "-w", works[si],
|
||||||
|
"-I", source, codec];
|
||||||
|
runcommandenv(root, strings.concat("name-select-", stages[si]),
|
||||||
|
selectav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||||
|
assert(os.exists(strings.concat(works[si], "/acme.codec.wwi")));
|
||||||
|
assert(!os.exists(strings.concat(works[si], "/wire.wwi")));
|
||||||
|
let initialwwi: str = readfile(strings.concat(works[si],
|
||||||
|
"/acme.codec.wwi"));
|
||||||
|
assert(has(initialwwi, "//ww:module acme.codec\npackage wire;\n"));
|
||||||
|
if (si == 0) { initialwwiref = strings.dup(initialwwi); }
|
||||||
|
else { assert(same(initialwwiref, initialwwi)); };
|
||||||
|
|
||||||
|
rewritefile(traces[si], "");
|
||||||
|
let directav: []str = [driver(stages[si]), "build", "-w", works[si],
|
||||||
|
"-I", source, "-o", directbins[si], direct];
|
||||||
|
runcommandenv(root, strings.concat("name-direct-", stages[si]),
|
||||||
|
directav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||||
|
let directtrace: str = readfile(traces[si]);
|
||||||
|
let directline: str = linecontaining(directtrace,
|
||||||
|
"cmd.direct.unit.new");
|
||||||
|
assert(occurrences(directline, "<--import><acme.codec>") == 1);
|
||||||
|
assert(!has(directline, "wire.wwi"));
|
||||||
|
let ndirect: str = normalizedtrace(directtrace,
|
||||||
|
strings.concat(works[si], "/"), directbins[si]);
|
||||||
|
if (si == 0) { directtraceref = strings.dup(ndirect); }
|
||||||
|
else { assert(same(directtraceref, ndirect)); };
|
||||||
|
let runav: []str = [directbins[si]];
|
||||||
|
runcommand(root, strings.concat("name-direct-run-", stages[si]), runav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 42);
|
||||||
|
|
||||||
|
// The same declared qualifier belongs to each importing source file,
|
||||||
|
// not to the package-wide namespace.
|
||||||
|
rewritefile(traces[si], "");
|
||||||
|
let scopedav: []str = [driver(stages[si]), "build", "-w", works[si],
|
||||||
|
"-I", source, "-o", scopedbins[si], scoped];
|
||||||
|
runcommandenv(root, strings.concat("name-scoped-", stages[si]),
|
||||||
|
scopedav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
let scopedtrace: str = readfile(traces[si]);
|
||||||
|
let scopedline: str = linecontaining(scopedtrace,
|
||||||
|
"cmd.scoped.unit.new");
|
||||||
|
assert(occurrences(scopedline, "<--import><scope.one>") == 1);
|
||||||
|
assert(occurrences(scopedline, "<--import><scope.two>") == 1);
|
||||||
|
let nscoped: str = normalizedtrace(scopedtrace,
|
||||||
|
strings.concat(works[si], "/"), scopedbins[si]);
|
||||||
|
if (si == 0) { scopedtraceref = strings.dup(nscoped); }
|
||||||
|
else { assert(same(scopedtraceref, nscoped)); };
|
||||||
|
let scopedrun: []str = [scopedbins[si]];
|
||||||
|
runcommand(root, strings.concat("name-scoped-run-", stages[si]),
|
||||||
|
scopedrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 42);
|
||||||
|
|
||||||
|
// Two per-file binding records for one canonical package still form
|
||||||
|
// exactly one direct graph edge and one compiler input.
|
||||||
|
rewritefile(traces[si], "");
|
||||||
|
let repeatedav: []str = [driver(stages[si]), "build", "-w", works[si],
|
||||||
|
"-I", source, "-o", repeatedbins[si], repeated];
|
||||||
|
runcommandenv(root, strings.concat("name-repeated-", stages[si]),
|
||||||
|
repeatedav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
let repeatedunit: str = readfile(strings.concat(works[si],
|
||||||
|
"/cmd.repeated.unit.ww"));
|
||||||
|
assert(occurrences(repeatedunit, "import acme.codec;") == 2);
|
||||||
|
let repeatedtrace: str = readfile(traces[si]);
|
||||||
|
let repeatedline: str = linecontaining(repeatedtrace,
|
||||||
|
"cmd.repeated.unit.new");
|
||||||
|
assert(occurrences(repeatedline, "<--import><acme.codec>") == 1);
|
||||||
|
assert(occurrences(repeatedtrace, "acme.codec.unit.new") == 0);
|
||||||
|
let nrepeated: str = normalizedtrace(repeatedtrace,
|
||||||
|
strings.concat(works[si], "/"), repeatedbins[si]);
|
||||||
|
if (si == 0) { repeatedtraceref = strings.dup(nrepeated); }
|
||||||
|
else { assert(same(repeatedtraceref, nrepeated)); };
|
||||||
|
let repeatedrun: []str = [repeatedbins[si]];
|
||||||
|
runcommand(root, strings.concat("name-repeated-run-", stages[si]),
|
||||||
|
repeatedrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
|
||||||
|
// A path ending in main remains importable when its declaration is not
|
||||||
|
// main. A different path declaring main is rejected by loaded name.
|
||||||
|
let leafmainav: []str = [driver(stages[si]), "build", "-w", works[si],
|
||||||
|
"-I", source, "-o", leafmainbins[si], leafmainuser];
|
||||||
|
runcommandenv(root, strings.concat("name-leafmain-", stages[si]),
|
||||||
|
leafmainav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
let leafmainrun: []str = [leafmainbins[si]];
|
||||||
|
runcommand(root, strings.concat("name-leafmain-run-", stages[si]),
|
||||||
|
leafmainrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 7);
|
||||||
|
|
||||||
|
// Compiler-owned binding failures are deterministic across stages and
|
||||||
|
// never commit an action voucher/artifact or publish a binary.
|
||||||
|
let rejectwork: str = strings.concat(root, "/reject-work-", stages[si]);
|
||||||
|
assert(os.mkdir(rejectwork, 448i32) == 0);
|
||||||
|
let rejecttargets: []str = [leafbad, leak, duplicate, collision,
|
||||||
|
crosscollision, programuser];
|
||||||
|
let rejectactions: []str = ["cmd.leafbad", "cmd.leak",
|
||||||
|
"cmd.duplicate", "cmd.collision", "cmd.crosscollision",
|
||||||
|
"cmd.programuser"];
|
||||||
|
let rejectneedles: []str = ["undefined: codec",
|
||||||
|
"package 'wire' is not directly imported",
|
||||||
|
"same redeclared in this block",
|
||||||
|
"same already declared through import of package same",
|
||||||
|
"same already declared through import of package same",
|
||||||
|
"package domain.program is a program, not an importable package"];
|
||||||
|
let rj: i32 = 0;
|
||||||
|
for (rj < rejecttargets.len) {
|
||||||
|
let badbin: str = strings.concat(root, "/reject-bin-", stages[si],
|
||||||
|
"-", rejectactions[rj]);
|
||||||
|
let badav: []str = [driver(stages[si]), "build", "-w", rejectwork,
|
||||||
|
"-I", source, "-o", badbin, rejecttargets[rj]];
|
||||||
|
runcommandenv(root, strings.concat("name-reject-", stages[si],
|
||||||
|
"-", rejectactions[rj]), badav, env,
|
||||||
|
(120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stderr, rejectneedles[rj]));
|
||||||
|
let normalized: str = normalizedtrace(out.stderr,
|
||||||
|
strings.concat(rejectwork, "/"), badbin);
|
||||||
|
if (rj == 2) {
|
||||||
|
assert(same(normalized, strings.concat(
|
||||||
|
"$WORK/cmd.duplicate.unit.new:4:1: error: same redeclared in this block\n",
|
||||||
|
"\t$WORK/cmd.duplicate.unit.new:3:1: other declaration of same\n",
|
||||||
|
"$WORK/cmd.duplicate.unit.new:4:1: error: \"scope.two\" imported as same and not used\n",
|
||||||
|
"ww: w6c failed for cmd.duplicate\n")));
|
||||||
|
};
|
||||||
|
if (rj == 3) {
|
||||||
|
assert(same(normalized, strings.concat(
|
||||||
|
"$WORK/cmd.collision.unit.new:3:1: error: \"scope.one\" imported as same and not used\n",
|
||||||
|
"$WORK/cmd.collision.unit.new:4:1: error: same already declared through import of package same (\"scope.one\")\n",
|
||||||
|
"\t$WORK/cmd.collision.unit.new:3:1: other declaration of same\n",
|
||||||
|
"ww: w6c failed for cmd.collision\n")));
|
||||||
|
};
|
||||||
|
if (si == 0) { diagnosticrefs[rj] = strings.dup(normalized); }
|
||||||
|
else { assert(same(diagnosticrefs[rj], normalized)); };
|
||||||
|
assert(!os.exists(badbin));
|
||||||
|
let committed: []str = [".unit.ww", ".wwi", ".s", ".o", ".a",
|
||||||
|
".unit.new", ".wwi.new", ".s.new", ".o.new", ".a.new"];
|
||||||
|
let ci: i32 = 0;
|
||||||
|
for (ci < committed.len) {
|
||||||
|
assert(!os.exists(strings.concat(rejectwork, "/",
|
||||||
|
rejectactions[rj], committed[ci])));
|
||||||
|
ci += 1;
|
||||||
|
};
|
||||||
|
rj += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
let conflictav: []str = [driver(stages[si]), "build", "-w",
|
||||||
|
rejectwork, "-I", source, conflict];
|
||||||
|
runcommandenv(root, strings.concat("name-conflict-", stages[si]),
|
||||||
|
conflictav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stderr, "conflicting package names"));
|
||||||
|
assert(!os.exists(strings.concat(rejectwork,
|
||||||
|
"/conflict.pkg.unit.ww")));
|
||||||
|
|
||||||
|
// Production/internal/external naming uses the declaration, while every
|
||||||
|
// action and generated-main artifact retains canonical variant identity.
|
||||||
|
let testwork: str = strings.concat(root, "/test-work-", stages[si]);
|
||||||
|
assert(os.mkdir(testwork, 448i32) == 0);
|
||||||
|
rewritefile(traces[si], "");
|
||||||
|
let testav: []str = [driver(stages[si]), "test", "-w", testwork,
|
||||||
|
"-I", source, testcodec];
|
||||||
|
runcommandenv(root, strings.concat("name-test-", stages[si]), testav,
|
||||||
|
env, (240i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(has(out.stdout, "internal_name_uses_declaration ... ok\n"));
|
||||||
|
assert(has(out.stdout, "external_name_uses_declaration ... ok\n"));
|
||||||
|
assert(out.stderr.len == 0);
|
||||||
|
if (si == 0) { testoutref = strings.dup(out.stdout); }
|
||||||
|
else { assert(same(testoutref, out.stdout)); };
|
||||||
|
let productionunit: str = readfile(strings.concat(testwork,
|
||||||
|
"/testpkg.codec.unit.ww"));
|
||||||
|
let internalunit: str = readfile(strings.concat(testwork,
|
||||||
|
"/testpkg.codec-internal-test.unit.ww"));
|
||||||
|
let externalunit: str = readfile(strings.concat(testwork,
|
||||||
|
"/testpkg.codec_test-external-test.unit.ww"));
|
||||||
|
assert(!has(productionunit, "testonly.helper"));
|
||||||
|
assert(has(internalunit, "import testonly.helper;"));
|
||||||
|
assert(!has(externalunit, "testonly.helper"));
|
||||||
|
assert(has(externalunit, "package wire_test;"));
|
||||||
|
assert(os.exists(strings.concat(testwork,
|
||||||
|
"/testpkg.codec-internal-test-main.a")));
|
||||||
|
assert(os.exists(strings.concat(testwork,
|
||||||
|
"/testpkg.codec_test-external-test-main.a")));
|
||||||
|
assert(os.exists(strings.concat(testwork, "/test.a")));
|
||||||
|
assert(!has(readfile(strings.concat(testwork,
|
||||||
|
"/testpkg.codec-internal-test-main.unit.ww")), "testonly.helper"));
|
||||||
|
assert(!has(readfile(strings.concat(testwork,
|
||||||
|
"/testpkg.codec_test-external-test-main.unit.ww")),
|
||||||
|
"testonly.helper"));
|
||||||
|
|
||||||
|
let recursivebuildwork: str = strings.concat(root,
|
||||||
|
"/recursive-build-", stages[si]);
|
||||||
|
assert(os.mkdir(recursivebuildwork, 448i32) == 0);
|
||||||
|
let recursivebuildav: []str = [driver(stages[si]), "build", "-w",
|
||||||
|
recursivebuildwork, "-I", source,
|
||||||
|
strings.concat(source, "/testpkg/...")];
|
||||||
|
runcommandenv(root, strings.concat("name-recursive-build-", stages[si]),
|
||||||
|
recursivebuildav, env,
|
||||||
|
(180i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(os.exists(strings.concat(recursivebuildwork,
|
||||||
|
"/testpkg.codec.wwi")));
|
||||||
|
let recursivetestwork: str = strings.concat(root,
|
||||||
|
"/recursive-test-", stages[si]);
|
||||||
|
assert(os.mkdir(recursivetestwork, 448i32) == 0);
|
||||||
|
let recursivetestav: []str = [driver(stages[si]), "test", "-w",
|
||||||
|
recursivetestwork, "-I", source,
|
||||||
|
strings.concat(source, "/testpkg/...")];
|
||||||
|
runcommandenv(root, strings.concat("name-recursive-test-", stages[si]),
|
||||||
|
recursivetestav, env,
|
||||||
|
(240i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(has(out.stdout, "external_name_uses_declaration ... ok\n"));
|
||||||
|
|
||||||
|
// Vendor expansion owns the action/map identity; the loaded declaration
|
||||||
|
// independently supplies cable as the source-visible qualifier.
|
||||||
|
rewritefile(traces[si], "");
|
||||||
|
let vendorav: []str = [driver(stages[si]), "build", "-w", works[si],
|
||||||
|
"-I", source, "-o", vendorbins[si], vendorclient];
|
||||||
|
runcommandenv(root, strings.concat("name-vendor-", stages[si]),
|
||||||
|
vendorav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
let vendorunit: str = readfile(strings.concat(works[si],
|
||||||
|
"/vend.client.unit.ww"));
|
||||||
|
assert(occurrences(vendorunit, "import short.codec;") == 2);
|
||||||
|
assert(has(vendorunit, strings.concat(
|
||||||
|
"//ww:import-map short.codec vend.vendor.short.codec ",
|
||||||
|
hexbytes(vendored), "\n")));
|
||||||
|
assert(occurrences(vendorunit,
|
||||||
|
"//ww:import-map short.codec vend.vendor.short.codec ") == 1);
|
||||||
|
let vendortrace: str = readfile(traces[si]);
|
||||||
|
let vendorline: str = linecontaining(vendortrace,
|
||||||
|
"vend.client.unit.new");
|
||||||
|
assert(occurrences(vendorline,
|
||||||
|
"<--import><vend.vendor.short.codec>") == 1);
|
||||||
|
assert(occurrences(vendorline, strings.concat(
|
||||||
|
"<--import-map><short.codec><vend.vendor.short.codec>")) == 1);
|
||||||
|
let vendorwwi: str = readfile(strings.concat(works[si],
|
||||||
|
"/vend.vendor.short.codec.wwi"));
|
||||||
|
assert(has(vendorwwi, strings.concat(
|
||||||
|
"//ww:module vend.vendor.short.codec\npackage cable;\n")));
|
||||||
|
assert(!os.exists(strings.concat(works[si], "/short.codec.a")));
|
||||||
|
let vendorrun: []str = [vendorbins[si]];
|
||||||
|
runcommand(root, strings.concat("name-vendor-run-", stages[si]),
|
||||||
|
vendorrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 13);
|
||||||
|
|
||||||
|
// Build the bare-import bridge and its command, establish a no-op warm
|
||||||
|
// rebuild, then change only the dependency's declared name. The direct
|
||||||
|
// importer is reconsidered; its unchanged export stops propagation.
|
||||||
|
rewritefile(traces[si], "");
|
||||||
|
let appav: []str = [driver(stages[si]), "build", "-w", works[si],
|
||||||
|
"-I", source, "-o", appbins[si], app];
|
||||||
|
runcommandenv(root, strings.concat("name-app-cold-", stages[si]), appav,
|
||||||
|
env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
let apprun: []str = [appbins[si]];
|
||||||
|
runcommand(root, strings.concat("name-app-run-", stages[si]), apprun,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 42);
|
||||||
|
rewritefile(traces[si], "");
|
||||||
|
runcommandenv(root, strings.concat("name-app-warm-", stages[si]), appav,
|
||||||
|
env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(readfile(traces[si]).len == 0);
|
||||||
|
rewritefile(codecfile, cablebody);
|
||||||
|
rewritefile(traces[si], "");
|
||||||
|
runcommandenv(root, strings.concat("name-app-renamed-", stages[si]),
|
||||||
|
appav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
let changedtrace: str = readfile(traces[si]);
|
||||||
|
assert(occurrences(changedtrace, "\n") == 2);
|
||||||
|
assert(occurrences(changedtrace, "/acme.codec.unit.new") == 1);
|
||||||
|
assert(occurrences(changedtrace, "/acme.bridge.unit.new") == 1);
|
||||||
|
assert(!has(changedtrace, "/cmd.app.unit.new"));
|
||||||
|
let nchanged: str = normalizedtrace(changedtrace,
|
||||||
|
strings.concat(works[si], "/"), appbins[si]);
|
||||||
|
if (si == 0) { changedtraceref = strings.dup(nchanged); }
|
||||||
|
else { assert(same(changedtraceref, nchanged)); };
|
||||||
|
let renamedwwi: str = readfile(strings.concat(works[si],
|
||||||
|
"/acme.codec.wwi"));
|
||||||
|
assert(has(renamedwwi, "//ww:module acme.codec\npackage cable;\n"));
|
||||||
|
assert(!has(renamedwwi, "package wire;"));
|
||||||
|
runcommand(root, strings.concat("name-app-renamed-run-", stages[si]),
|
||||||
|
apprun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 42);
|
||||||
|
|
||||||
|
// New semantic artifacts and binaries are byte-identical across the
|
||||||
|
// independently cold Cstage and WWstage work roots.
|
||||||
|
ari = 0;
|
||||||
|
for (ari < actions.len) {
|
||||||
|
let xi: i32 = 0;
|
||||||
|
for (xi < suffixes.len) {
|
||||||
|
let index: i32 = ari * suffixes.len + xi;
|
||||||
|
let bytes: str = readfile(strings.concat(works[si], "/",
|
||||||
|
actions[ari], suffixes[xi]));
|
||||||
|
if (si == 0) { artifactrefs[index] = strings.dup(bytes); }
|
||||||
|
else { assert(same(artifactrefs[index], bytes)); };
|
||||||
|
xi += 1;
|
||||||
|
};
|
||||||
|
ari += 1;
|
||||||
|
};
|
||||||
|
let stagebins: []str = [directbins[si], appbins[si], scopedbins[si],
|
||||||
|
repeatedbins[si], leafmainbins[si], vendorbins[si]];
|
||||||
|
let bini: i32 = 0;
|
||||||
|
for (bini < stagebins.len) {
|
||||||
|
let bytes: str = readfile(stagebins[bini]);
|
||||||
|
if (si == 0) { binaryrefs[bini] = strings.dup(bytes); }
|
||||||
|
else { assert(same(binaryrefs[bini], bytes)); };
|
||||||
|
bini += 1;
|
||||||
|
};
|
||||||
|
si += 1;
|
||||||
|
};
|
||||||
|
clean(root);
|
||||||
|
};
|
||||||
|
|
||||||
@test fn compile_artifact_naming() void = {
|
@test fn compile_artifact_naming() void = {
|
||||||
let root: str = fresh();
|
let root: str = fresh();
|
||||||
let pdir: str = strings.concat(root, "/pkg");
|
let pdir: str = strings.concat(root, "/pkg");
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
testenv.writefile(strings.concat(shared, "/a.ww"), asrc);
|
testenv.writefile(strings.concat(shared, "/a.ww"), asrc);
|
||||||
};
|
};
|
||||||
testenv.writefile(strings.concat(left, "/left.ww"), strings.concat(
|
testenv.writefile(strings.concat(left, "/left.ww"), strings.concat(
|
||||||
"package left;\nimport shared;\nimport shared;\n",
|
"package left;\nimport shared;\n",
|
||||||
"export fn make() shared.token = { return shared.token{value=shared.base() + 1}; };\n"));
|
"export fn make() shared.token = { return shared.token{value=shared.base() + 1}; };\n"));
|
||||||
testenv.writefile(strings.concat(right, "/right.ww"), strings.concat(
|
testenv.writefile(strings.concat(right, "/right.ww"), strings.concat(
|
||||||
"package right;\nimport shared;\n",
|
"package right;\nimport shared;\n",
|
||||||
@@ -424,7 +424,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
let rightiface: str = testenv.readfile(strings.concat(scratch,
|
let rightiface: str = testenv.readfile(strings.concat(scratch,
|
||||||
"right.wwi"));
|
"right.wwi"));
|
||||||
if (testenv.occurrences(leftiface, "import shared;") != 1) {
|
if (testenv.occurrences(leftiface, "import shared;") != 1) {
|
||||||
fail("diamond", "duplicate import escaped into export data");
|
fail("diamond", "direct import is missing or duplicated in export data");
|
||||||
};
|
};
|
||||||
if (testenv.occurrences(leftiface, "export type token") != 1
|
if (testenv.occurrences(leftiface, "export type token") != 1
|
||||||
|| testenv.occurrences(rightiface, "export type token") != 1
|
|| testenv.occurrences(rightiface, "export type token") != 1
|
||||||
@@ -907,7 +907,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
"/.wwtool.w6a")), testenv.readfile(assembler))
|
"/.wwtool.w6a")), testenv.readfile(assembler))
|
||||||
|| !testenv.same(testenv.readfile(strings.concat(work,
|
|| !testenv.same(testenv.readfile(strings.concat(work,
|
||||||
"/.wwtool.stamp")),
|
"/.wwtool.stamp")),
|
||||||
"ww workdir fmt 13 mode build asm 0\n")) {
|
"ww workdir fmt 14 mode build asm 0\n")) {
|
||||||
fail("driver-identity", "persistent artifacts or identities are incomplete");
|
fail("driver-identity", "persistent artifacts or identities are incomplete");
|
||||||
};
|
};
|
||||||
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
|
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
|
||||||
@@ -1293,7 +1293,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
"// ROOT_A\n",
|
"// ROOT_A\n",
|
||||||
"export fn value() i32 = { return dep.value() + 2; };\n"));
|
"export fn value() i32 = { return dep.value() + 2; };\n"));
|
||||||
testenv.writefile(strings.concat(bar, "/z.ww"), strings.concat(
|
testenv.writefile(strings.concat(bar, "/z.ww"), strings.concat(
|
||||||
"package bar;\nimport foo.dep;\n",
|
"package bar;\n",
|
||||||
"// ROOT_Z\n",
|
"// ROOT_Z\n",
|
||||||
"export fn other() i32 = { return 9; };\n"));
|
"export fn other() i32 = { return 9; };\n"));
|
||||||
testenv.writefile(strings.concat(commanddir, "/main.ww"), strings.concat(
|
testenv.writefile(strings.concat(commanddir, "/main.ww"), strings.concat(
|
||||||
@@ -1819,16 +1819,21 @@ fn writediamond(td: str, reverse: bool) str = {
|
|||||||
@test fn generated_test_hook_is_not_a_user_exemption() void = {
|
@test fn generated_test_hook_is_not_a_user_exemption() void = {
|
||||||
let td: str = testenv.fresh();
|
let td: str = testenv.fresh();
|
||||||
let src: str = strings.concat(td, "/case.ww");
|
let src: str = strings.concat(td, "/case.ww");
|
||||||
|
let iface: str = strings.concat(td, "/test.wwi");
|
||||||
testenv.writefile(src, strings.concat(
|
testenv.writefile(src, strings.concat(
|
||||||
"package probe;\nimport test;\n",
|
"package probe;\nimport test;\n",
|
||||||
"fn bad() void = { test.run(); };\n",
|
"fn bad() void = { test.run(); };\n",
|
||||||
"@test fn one() void = {};\n"));
|
"@test fn one() void = {};\n"));
|
||||||
|
testenv.writefile(iface, strings.concat(
|
||||||
|
"//ww:module test\n",
|
||||||
|
"package test;\n",
|
||||||
|
"export fn placeholder() void;\n"));
|
||||||
let compilers: []str = ["w6c", "w6c_ww"];
|
let compilers: []str = ["w6c", "w6c_ww"];
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < compilers.len) {
|
for (i < compilers.len) {
|
||||||
let asm: str = strings.concat(td, "/case-", compilers[i], ".s");
|
let asm: str = strings.concat(td, "/case-", compilers[i], ".s");
|
||||||
let av: []str = [testenv.driver(compilers[i]), "-T", "-c", "-o",
|
let av: []str = [testenv.driver(compilers[i]), "-T", "-c",
|
||||||
asm, src];
|
"--import", "test", iface, "-o", asm, src];
|
||||||
let co: testenv.commandout;
|
let co: testenv.commandout;
|
||||||
command(td, strings.concat("test_hook_", compilers[i]), av, &co);
|
command(td, strings.concat("test_hook_", compilers[i]), av, &co);
|
||||||
if (co.termination != exec.termination.EXIT || co.code == 0
|
if (co.termination != exec.termination.EXIT || co.code == 0
|
||||||
|
|||||||
@@ -220,8 +220,8 @@ export fn occurrences(haystack: str, needle: str) i32 = {
|
|||||||
// Expected semantic identity for a canonical absolute directory that is not
|
// Expected semantic identity for a canonical absolute directory that is not
|
||||||
// representable below an active source root. Keep this independent observer
|
// representable below an active source root. Keep this independent observer
|
||||||
// byte-for-byte aligned with the documented driver protocol.
|
// byte-for-byte aligned with the documented driver protocol.
|
||||||
export fn localpackageidentity(dir: str, leaf: str) str = {
|
export fn localpackageidentity(dir: str, declaredname: str) str = {
|
||||||
let out: []u8 = alloc([], (dir.len * 4 + leaf.len + 16): u64)!;
|
let out: []u8 = alloc([], (dir.len * 4 + 16): u64)!;
|
||||||
let prefix: str = "__wwlocal.p";
|
let prefix: str = "__wwlocal.p";
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < prefix.len) { append(out, prefix[i]); i += 1; };
|
for (i < prefix.len) { append(out, prefix[i]); i += 1; };
|
||||||
@@ -244,9 +244,6 @@ export fn localpackageidentity(dir: str, leaf: str) str = {
|
|||||||
};
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
append(out, '.');
|
|
||||||
i = 0;
|
|
||||||
for (i < leaf.len) { append(out, leaf[i]); i += 1; };
|
|
||||||
return strings.frombytes(out);
|
return strings.frombytes(out);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//ww:error "does not match import path"
|
//ww:compile
|
||||||
//ww:module foo
|
//ww:module foo
|
||||||
package bar;
|
package bar;
|
||||||
export fn x() i32 = { return 0; };
|
export fn x() i32 = { return 0; };
|
||||||
@@ -22,11 +22,12 @@ package direnum_test;
|
|||||||
// source order); the two stages' units are byte-identical.
|
// source order); the two stages' units are byte-identical.
|
||||||
//
|
//
|
||||||
// rejects — the authoritative loader-reject table over private trees:
|
// rejects — the authoritative loader-reject table over private trees:
|
||||||
// root-conflict ("conflicting package names"), import-leaf ("does
|
// root-conflict ("conflicting package names"), root-missing and
|
||||||
// not match import path"), root-missing and root-invalid ("invalid
|
// root-invalid ("invalid or missing package clause"), attest-noncanon
|
||||||
// or missing package clause"), attest-noncanon ("@test declaration
|
// ("@test declaration outside *_test.ww" — Go's test-file contract);
|
||||||
// outside *_test.ww" — Go's test-file contract); per row both stages
|
// per row both stages fail, carry the needle, and their captured stderr is
|
||||||
// fail, carry the needle, and their captured stderr is byte-identical.
|
// byte-identical. The former import-leaf rejection is now an accepted
|
||||||
|
// path/name-decoupling case and uses the imported declaration as qualifier.
|
||||||
//
|
//
|
||||||
// Dropped C machinery, not assertions: the ww_ww-absent skip gate
|
// Dropped C machinery, not assertions: the ww_ww-absent skip gate
|
||||||
// (the Make target declares both drivers) and the unlink/rmdir
|
// (the Make target declares both drivers) and the unlink/rmdir
|
||||||
@@ -179,7 +180,7 @@ fn rejectpair(label: str, td: str, target: str, needle: str) void = {
|
|||||||
"package other;\nfn spare() i32 = { return 0; };\n");
|
"package other;\nfn spare() i32 = { return 0; };\n");
|
||||||
testenv.writefile(strings.concat(importbad, "/entry.ww"),
|
testenv.writefile(strings.concat(importbad, "/entry.ww"),
|
||||||
strings.concat("package main;\nimport wanted;\n",
|
strings.concat("package main;\nimport wanted;\n",
|
||||||
"fn main() i32 = { return wanted.value(); };\n"));
|
"fn main() i32 = { return other.value(); };\n"));
|
||||||
testenv.writefile(strings.concat(wanted, "/a.ww"),
|
testenv.writefile(strings.concat(wanted, "/a.ww"),
|
||||||
"package other;\nexport fn value() i32 = { return 0; };\n");
|
"package other;\nexport fn value() i32 = { return 0; };\n");
|
||||||
testenv.writefile(strings.concat(missing, "/a.ww"),
|
testenv.writefile(strings.concat(missing, "/a.ww"),
|
||||||
@@ -192,12 +193,28 @@ fn rejectpair(label: str, td: str, target: str, needle: str) void = {
|
|||||||
"package attbad;\n",
|
"package attbad;\n",
|
||||||
"@test fn hidden() void = { assert(false); };\n"));
|
"@test fn hidden() void = { assert(false); };\n"));
|
||||||
|
|
||||||
let tags: []str = ["root-conflict", "import-leaf", "root-missing",
|
let drvs: []str = ["ww", "ww_ww"];
|
||||||
|
let s: i32 = 0;
|
||||||
|
for (s < drvs.len) {
|
||||||
|
let out: str = strings.concat(td, "/import-name-", drvs[s]);
|
||||||
|
let av: []str = [testenv.driver(drvs[s]), "build", "-o", out,
|
||||||
|
strings.concat(importbad, "/entry.ww")];
|
||||||
|
if (runcode(td, strings.concat("import-name-build-", drvs[s]), av)
|
||||||
|
!= 0) {
|
||||||
|
fail("import-name", strings.concat(drvs[s], " build failed"));
|
||||||
|
};
|
||||||
|
let rav: []str = [out];
|
||||||
|
if (runcode(td, strings.concat("import-name-run-", drvs[s]), rav)
|
||||||
|
!= 0) {
|
||||||
|
fail("import-name", strings.concat(drvs[s], " run failed"));
|
||||||
|
};
|
||||||
|
s += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
let tags: []str = ["root-conflict", "root-missing",
|
||||||
"root-invalid", "attest-noncanon"];
|
"root-invalid", "attest-noncanon"];
|
||||||
let targets: []str = [rootbad, strings.concat(importbad,
|
let targets: []str = [rootbad, missing, invalid, attbad];
|
||||||
"/entry.ww"), missing, invalid, attbad];
|
|
||||||
let needles: []str = ["conflicting package names",
|
let needles: []str = ["conflicting package names",
|
||||||
"does not match import path",
|
|
||||||
"invalid or missing package clause",
|
"invalid or missing package clause",
|
||||||
"invalid or missing package clause",
|
"invalid or missing package clause",
|
||||||
"@test declaration outside *_test.ww"];
|
"@test declaration outside *_test.ww"];
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ fn userow(label: str, apick: str, onecall: str) void = {
|
|||||||
let rav: []str = [strings.concat(td, "/main")];
|
let rav: []str = [strings.concat(td, "/main")];
|
||||||
if (runcode(td, strings.concat("run_", drvs[s]), rav) != 0) {
|
if (runcode(td, strings.concat("run_", drvs[s]), rav) != 0) {
|
||||||
fail(label, strings.concat(drvs[s], " run-exit != 0 (a ",
|
fail(label, strings.concat(drvs[s], " run-exit != 0 (a ",
|
||||||
"file-global first-match hint routes one math.pick() to ",
|
"cross-file first-match hint routes one math.pick() to ",
|
||||||
"the wrong package -- #40)"));
|
"the wrong package -- #40)"));
|
||||||
};
|
};
|
||||||
testenv.clean(td);
|
testenv.clean(td);
|
||||||
|
|||||||
Reference in New Issue
Block a user