test: prove package initialization semantics
This commit is contained in:
59
docs/spec.md
59
docs/spec.md
@@ -246,7 +246,8 @@ does not return (e.g. a call to `abort`).
|
||||
```
|
||||
SourceFile = PackageClause { ImportDecl } { TopDecl } .
|
||||
PackageClause = "package" ident ";" .
|
||||
ImportDecl = "import" ( ImportPath | ident ImportPath ) ";" .
|
||||
ImportDecl = "import" ( ImportPath | ImportName ImportPath ) ";" .
|
||||
ImportName = ident .
|
||||
ImportPath = ident { "." ident } .
|
||||
```
|
||||
|
||||
@@ -263,8 +264,18 @@ ImportPath = ident { "." ident } .
|
||||
Neither form exposes an imported declaration as a bare `Name`; ordinary
|
||||
unqualified lookup remains limited to lexical, builtin, and same-package
|
||||
declarations.
|
||||
- `import _ acme.codec;` is a blank side-effect import. The lone `_` creates no
|
||||
qualifier, exposes no bare declaration, and is never diagnosed as unused.
|
||||
It is nevertheless a real import occurrence: resolution and all missing,
|
||||
self-import, cycle, `internal`, vendor, and imported-command checks use the
|
||||
dotted path, and the dependency participates in executable and test package
|
||||
initialization. Repeated blank occurrences and blank plus default/explicit
|
||||
named occurrences of one path are valid; every named occurrence remains
|
||||
independently subject to duplicate-binding and unused checks.
|
||||
The package dependency graph is the sorted, deduplicated union of the real
|
||||
imports in all eligible files. Self-import is rejected.
|
||||
imports in all eligible files. Occurrences retain their owning file and
|
||||
position, but equal canonical targets create one graph edge/package action.
|
||||
Self-import is rejected.
|
||||
- An executable package is one declared `package main` and containing a
|
||||
`fn main`; path and directory spelling do not classify commands. An ordinary
|
||||
import of a package declared `main` is rejected, except for the toolchain's
|
||||
@@ -272,8 +283,8 @@ ImportPath = ident { "." ident } .
|
||||
- Only names marked `export` (§5) are visible across module boundaries.
|
||||
|
||||
Import paths remain unquoted and dotted. Grouped imports, quoted import paths,
|
||||
dot imports, and blank imports are not implemented. In particular, `_` is
|
||||
rejected as an alias rather than being treated as a blank import.
|
||||
and dot imports are not implemented. `_` is reserved here for the blank form;
|
||||
it is not an ordinary alias.
|
||||
|
||||
---
|
||||
|
||||
@@ -298,23 +309,42 @@ The `=` between signature and body is required. A bodiless fn (`;`
|
||||
terminator) declares an external symbol (C FFI); the bare `...` C-style
|
||||
variadic is legal only on a bodiless declaration (§6.3).
|
||||
|
||||
At package scope, exactly `fn init() void = Block;` declares a special package
|
||||
initializer. It must have a body, no parameters, no result, no `export`, and no
|
||||
attribute. Multiple init declarations are permitted and retain owner-file and
|
||||
source order. `init` is not inserted into ordinary package scope: it cannot be
|
||||
called as `init()`, selected as `pkg.init`, exported, or used by another kind
|
||||
of declaration. Package-variable initialization completes before these
|
||||
functions run.
|
||||
|
||||
### 5.2 `let`
|
||||
|
||||
```
|
||||
LetDecl = "let" ident ":" Type [ "=" Expr ] ";" .
|
||||
```
|
||||
|
||||
A mutable binding. Without an initialiser the storage is uninitialised.
|
||||
A mutable binding. Without an initialiser, package-level storage is
|
||||
zero-backed; an uninitialized function-local binding retains the existing
|
||||
uninitialized-local rule.
|
||||
A `static` qualifier (`static let …`) gives function-local storage
|
||||
static lifetime.
|
||||
|
||||
For a package-level `let` with an initializer, values representable by the
|
||||
static-data emitter are installed statically. Every other otherwise valid
|
||||
initializer is evaluated exactly once at runtime. Checked references through
|
||||
package functions contribute variable-dependency edges; dependencies precede
|
||||
dependents, and source declaration order breaks ready ties. Initialization
|
||||
cycles are errors. Runtime package lets execute after imported package tasks and
|
||||
before the package's init functions. `const` and `def` are not broadened by
|
||||
this runtime path.
|
||||
|
||||
### 5.3 `const`
|
||||
|
||||
`const` introduces an immutable binding of the same shape as `let`.
|
||||
|
||||
TODO(spec): pin the exact `const` vs `def` boundary against `cmd/wcc`
|
||||
(both keywords exist; this text takes `def` = compile-time constant
|
||||
[Hare's `def`] and `const` = immutable runtime binding — confirm).
|
||||
`const` introduces an immutable storage binding of the same declaration shape
|
||||
as `let`; assignment to it is rejected. At package scope its initializer stays
|
||||
within the existing static-data forms. A `const` is not entered into the
|
||||
runtime package-variable schedule described above; use mutable `let` when an
|
||||
otherwise valid initializer requires runtime evaluation.
|
||||
|
||||
### 5.4 `def`
|
||||
|
||||
@@ -561,6 +591,15 @@ the program. Two placements, following the Go `foo` / `foo_test` model:
|
||||
};
|
||||
```
|
||||
|
||||
Production, production-plus-white-box-test, external black-box-test, test
|
||||
support, and generated test main are distinct package actions. Before a test
|
||||
function runs, the generated test product initializes its exact reachable
|
||||
variant graph dependency-first and once per canonical action. A white-box
|
||||
variant replaces the colocated production task rather than initializing both;
|
||||
an external variant depends on ordinary production. Imports, runtime lets, and
|
||||
init declarations found only in `*_test.ww` never enter an ordinary production
|
||||
build.
|
||||
|
||||
---
|
||||
|
||||
## 11. Concurrency (reserved)
|
||||
|
||||
Reference in New Issue
Block a user