Skip to content
Topaz6.0 · Before release
Download

Search documentation

Specification 6.0 · Not released · Tested product 5.21.3

Use arrow keys to choose a result. Press Enter to open.

Type an API name, diagnostic number, rule, or project topic.

    Language · chapter 13 · 25 rules

    Modules and visibility

    Use this page to split a source program into files and choose which declarations other files can access.

    Scope and ownership

    Link

    This page covers source modules, dotted module paths, import bindings, exports, and visibility. Function declarations and bounds belong to Functions and generics. The check command owns entry-file and source-root selection. Dependency acquisition, locks, targets, and individual standard-library APIs have separate owners.

    Import and export syntax

    Link
    EBNF
    1. ModulePath = Identifier ("." Identifier)* ;
    2. ImportItem = NamespaceImport | SelectedImport ;
    3. NamespaceImport = "import" ModulePath ("as" Identifier)? ;
    4. SelectedImport =
    5. "import" ModulePath "{" ImportSpec ("," ImportSpec)* ","? "}" ;
    6. ImportSpec = Identifier ("as" Identifier)? ;
    7. ExportShape = "export" ExportableDeclaration ;

    This source-syntax excerpt is transcribed from the parser. Identifier spelling, statement separators, declaration bodies, and binding patterns use their own productions.

    The complete grammar applies identifier-equality guards to aliases: a namespace alias differs from the final module-path segment, and a selected alias differs from the selected source name. This excerpt shows the production shape; the alias rule specifies that additional constraint.

    Source evidence

    Files and the source program

    Link

    The uniform initialization rules are the recommendation recorded in PR #41 for the remaining 6.0 design work. Current SELF differences are listed as limitations with unchanged expected assertions. The example scope remains Topaz 5.21 / public product 5.21.3 until the separate documentation version split.

    Ruletopaz.rule.modules.source-path

    Source paths and module identity

    An ordinary source module uses a dotted identifier path. Under the selected source root, each dot becomes a path separator and the file name ends in .tpz. For example, geometry.point selects geometry/point.tpz. Its logical identity is the dotted relative path without the extension.

    Why

    A dotted name gives each source module one logical identity independent of the host path separator. The same name determines the source file.

    Source evidence
    Ruletopaz.rule.modules.source-program

    The source program

    The entry file and the source files reached transitively through its imports form the source program.

    Why

    Following imports includes the files needed by the entry program without making unrelated neighboring files part of it.

    Source evidence
    Ruletopaz.rule.modules.import-prologue

    Import placement

    Imports must precede every other top-level item in a file. A later import is rejected with TPZ2010.

    Why

    A single prologue makes dependencies visible before executable items. Import placement then does not suggest an order among those items.

    Source evidence
    Ruletopaz.rule.modules.imported-top-level

    The same statements in every source file

    Entry files and imported files use the same top-level statement grammar. Both admit declarations, free expressions, assignments, and loops. Binding initializers and free expressions use the ordinary effect rules. Import placement, visibility, mutability, control-flow targets, and all other context checks apply equally to both file roles. Importing a file does not add a statement-form restriction.

    Why

    The meaning of a source file should not depend on whether it is selected as the entry or reached through an import. Effectful binding initializers already run during module initialization; deterministic ordering and readiness rules address those effects directly. Uniform statement forms let ordinary general-purpose code move between files without a wrapper function or dummy binding.

    Source evidence
    Ruletopaz.rule.modules.initialization-order

    Dependency order and one initialization

    Resolve the complete source program before initialization. Initialize source modules serially, completing every dependency before its importer. At each step, choose the lexicographically smallest canonical logical module identity among modules whose dependencies have completed; compare identities by Unicode scalar value. Import spelling order and local aliases do not affect this order. After constant processing, execute ordinary top-level items in source order. Every module initializes exactly once per program invocation, including when multiple import paths reach it in a diamond. All importers share the same completed module state. A new program invocation, including a new host invocation of an exported function, creates fresh module state and repeats initialization.

    Why

    A file has one logical identity and one initialized state within an invocation. A dependency must finish before its importer can use it. Choosing the smallest ready identity makes the result stable when import lines or local aliases change, and sharing diamond dependencies prevents duplicate initialization effects.

    Source evidence
    Ruletopaz.rule.modules.initialization-cycle

    Reject cycles before initialization

    A source import cycle, including a module importing itself, is rejected with TPZ3006 during resolution. The diagnostic identifies an import edge in the cycle. No module initialization or entry execution begins for a rejected graph. Break the cycle by moving shared declarations into a dependency or removing the back edge.

    Why

    A cycle has no dependency-first initialization order. Rejecting it before effects begin keeps every import bound to a fully initialized module and avoids a second set of rules for partially initialized exports.

    Source evidence
    Ruletopaz.rule.modules.initialization-readiness

    Read a binding after initialization

    Why

    A file's role does not change the meaning of its bindings.

    Source evidence
    Ruletopaz.rule.modules.initialization-failure

    An initialization fault stops the invocation

    If module initialization faults, abort the program invocation immediately. Do not execute remaining items in that module, initialize later modules, or start a waiting importer. Already completed effects remain visible; initialization provides no rollback. Report the original fault code and primary source location. An added initialization-context message does not change that diagnostic identity.

    Why

    Initialization uses ordinary execution and effects. Stopping at the first fault preserves the dependency guarantee, while retaining the original diagnostic locates the failing operation. General host effects cannot be promised transactional rollback.

    Source evidence

    Namespace and selected imports

    Link
    Ruletopaz.rule.modules.namespace-binding

    Namespace import bindings

    A namespace import binds the final path segment as its local namespace name. An explicit as alias supplies that name instead. Select a declaration with namespace.member.

    Why

    A namespace groups a module's exported names under one local binding. An alias resolves collisions between modules with the same final path segment.

    Source evidence
    Ruletopaz.rule.modules.selected-bindings

    Selected import bindings

    A selected import binds each chosen export directly under its source name or its selection alias. Renaming the local binding preserves which source declaration it denotes. A selection list creates no namespace binding.

    Why

    Selecting exports makes each imported dependency explicit in the local scope. An alias can resolve a local name collision while retaining the source declaration.

    Source evidence
    Ruletopaz.rule.modules.import-alias-name

    An alias changes the local name

    Omit as when an import keeps its default binding name. A namespace alias must differ from the final module-path segment; a selected alias must differ from that selected source name. An explicit alias repeating the default identifier is rejected with TPZ2009 during parsing, at the alias identifier. An alias that changes the local name remains permitted under the ordinary import visibility and collision rules.

    The intended new diagnostic message is “redundant import alias {name}; omit as {name}”. Here {name} is the alias identifier. This is the proposed contract, not an observed current SELF message. Current SELF accepts the redundant form, as recorded in the limitation. TPZ2009 already canonically identifies unsupported module export/import composition; this rule adds a distinct cause within that identity.

    Why

    The default namespace or selected source name already defines the local binding. Repeating that name after as creates a second spelling for exactly the same import without adding information. Omitting a redundant alias keeps one spelling for the default binding, while an actual rename remains available to choose a different local name.

    Source evidence
    Ruletopaz.rule.modules.selection-list

    Selection-list requirements

    A selection list must contain at least one name. Selected source names and resulting local names must each be unique. Violating these requirements is rejected with TPZ2011.

    Why

    An empty selection introduces no names. Repeated source or local names would duplicate an import or leave a local binding ambiguous.

    Source evidence
    Ruletopaz.rule.modules.import-form-choice

    Choose a namespace or selection

    A namespace alias and a selection list cannot appear in the same import item. Their combination is rejected with TPZ2009.

    Why

    A namespace binding and a selection introduce different local names. Separating them keeps one import item from creating both sets implicitly.

    Source evidence
    Ruletopaz.rule.modules.repeated-module

    One import item per module

    A logical module may appear in at most one import item in an importing file. Repeating it is rejected with TPZ3017.

    Why

    One import item keeps a module's dependency and local naming choices together. Repeated items would split the same dependency across declarations.

    Source evidence

    Exports and read-only import bindings

    Link
    Ruletopaz.rule.modules.declaration-visibility

    Public and private declarations

    Prefix an otherwise valid function, let, const, type alias, enum, record, newtype, or protocol declaration with export to publish its binding. Without that prefix, the declaration remains module-private.

    Why

    Private declarations can change without changing a module's public names. Placing export on the declaration gives each published binding one visible definition.

    Source evidence
    Ruletopaz.rule.modules.exported-let-shape

    The shape of an exported binding

    An exported immutable let uses an ordinary let pattern and optional type annotation. The pattern must bind at least one name; otherwise TPZ2007 rejects it during parsing. Every bound name becomes an immutable export with its module-and-name identity. Evaluate the initializer once, match the complete pattern, then install all bindings. Ordinary pattern typing, duplicate-name, and refutability checks still apply. If evaluation or matching faults, install no binding from that pattern and stop module initialization; earlier external effects remain. Check every resolved bound type for private nominal exposure. Public types are the extracted binding types, not the temporary initializer container. Module exports are published after successful initialization.

    Why

    Export changes visibility, so an immutable binding uses the same pattern and type rules in a private or public declaration. Requiring temporary private bindings would repeat the same decomposition. Each bound name is a public module binding; a pattern without a name publishes nothing and uses plain let. The initializer and pattern match therefore stay one operation, independent of how many names become public.

    Source evidence
    Ruletopaz.rule.modules.exported-let-mutability

    Exported bindings are immutable

    An exported let binding must be immutable. The form export let mut is rejected with TPZ3011 during resolution.

    Why

    An immutable exported binding prevents another module from depending on reassignment of shared module state. Updates can pass through an exported function with an explicit interface.

    Source evidence
    Ruletopaz.rule.modules.selected-visibility

    Namespace imports and selected exports

    A namespace import may target a module with an empty export table. That module initializes normally and the bound namespace has no public members. Selecting a private or absent name is rejected with TPZ3009 during resolution, including when the target exports no names. Initialization does not require a dummy export or a separate import form.

    Why

    Imports expose only public declarations, so selecting a name must consult the export table. Initialization is independent of that table: a module used for its effects needs the same namespace import as any other module, without a dummy export or a separate side-effect import syntax.

    Source evidence
    Ruletopaz.rule.modules.namespace-visibility

    Visibility through a namespace

    A value or type selected through a namespace must name an exported declaration. The requirement applies in every context, including record field defaults. A private or absent member is rejected with TPZ3009 during resolution.

    Why

    Namespace access must respect the same public names as selected imports. Qualification must not grant access to private module declarations.

    Source evidence
    Ruletopaz.rule.modules.import-assignment

    Rebinding imported declarations

    Direct replacement of a selected imported binding, including an alias, or an imported namespace member is rejected during resolution with TPZ3015. This rejection precedes the immutable-root check. Data mutation and mutable local values follow the imported value rule.

    See imported values for data mutation and mutable local values.

    Why

    An imported binding belongs to its defining module. Rejecting replacement prevents an importing module from changing what other readers observe through that name.

    Source evidence
    Ruletopaz.rule.modules.public-type-surface

    Resolved public type visibility

    An exported declaration publishes its resolved type, whether that type is annotated or inferred. Expand transparent type aliases before checking visibility. Every reachable record, enum, or newtype identity must be exported by its defining module. Check nested type components and type arguments recursively, including collections, structural records, unions, and function types. The rule covers function parameters and results, let and const bindings, type aliases, enum payloads, record fields, newtype bases, and exported protocol method parameters and results. A private alias whose expansion contains accessible types is accepted. A reachable private nominal type is rejected with TPZ3014 in the resolve phase. The primary location is the offending exported type reference when annotated, or the exported declaration's name when inferred.

    Why

    Exporters publish the same type whether an annotation or inference determines it. Checking resolved identities prevents annotation spelling from changing visibility. Transparent aliases introduce no new identity, so callers need the expanded type rather than the private alias name.

    Source evidence
    Ruletopaz.rule.modules.record-default-visibility

    Record defaults respect module privacy

    Why

    Field defaults are ordinary expression contexts.

    Source evidence

    An exported function may expose an exported user protocol bound

    Link
    example.tpzAn exported function may expose an exported user protocol boundOpen in Playground
    1. export protocol Labelled { function label(value: Self) -> string }
    2. export function describe<T: Labelled>(value: T) -> string { Labelled.label(value) }
    Expected outputexit 0
    No stdout.
    $ topaz check example.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    A private protocol is not selected through import

    Link
    example.tpzA private protocol is not selected through importOpen in Playground
    1. import contracts { Hidden }
    Expected outputNonzero exit
    No stdout.
    $ topaz check example.tpz --format json · target product 5.21.3
    contracts.tpzA private protocol is not selected through importOpen in Playground
    1. protocol Hidden { function label(value: Self) -> string }
    2. export let marker = 0
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3009 protocol-name-not-exported at example.tpz:1:20
    Source evidence

    An exported protocol cannot expose a private nominal parameter type

    Link
    example.tpzAn exported protocol cannot expose a private nominal parameter typeOpen in Playground
    1. record Hidden { n: int }
    2. export protocol Render { function render(value: Self, input: Hidden) -> string }
    Expected outputNonzero exit
    No stdout.
    $ topaz check example.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3014 modules-public-private-nominal at example.tpz:2:62
    Source evidence

    An exported protocol signature may use an exported nominal type

    Link
    example.tpzAn exported protocol signature may use an exported nominal typeOpen in Playground
    1. export record Input { n: int }
    2. export protocol Render { function render(value: Self, input: Input) -> string }
    Expected outputexit 0
    No stdout.
    $ topaz check example.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence
    Ruletopaz.rule.modules.imported-values

    Imported values

    An imported value is an immutable binding. The importing module cannot change its data through that binding. let mut local = imported receives an independent data value under collection value semantics. Changing the local leaves the exported value unchanged. Imported host resource handles, such as File, retain shared resource state.

    Imported data follows collection value semantics. Import assignment rejects replacement. Immutable assignment rejects writes through an immutable root.

    Why

    Importing a data value follows the same value semantics as assigning it. A mutable local therefore cannot change the exporting module's value.

    Source evidence

    Rejected source forms

    Link
    Ruletopaz.rule.modules.reserved-import-forms

    Reserved import spellings

    A use item and a string or template module path are rejected with TPZ2008.

    Why

    Dotted imports give source dependencies one spelling. A second keyword or string path would name the same module through another syntax.

    Source evidence
    Ruletopaz.rule.modules.rejected-export-forms

    Rejected export spellings

    The forms export { name } and export import module are rejected with TPZ2009.

    Why

    An export prefix keeps visibility at the declaration. Separate export lists or import exports would give publication another place and spelling.

    Source evidence

    Complete import and export examples

    Link

    Save the complete file set shown for an example, then use its displayed command.

    Select exports and rename a local binding

    Link
    main.tpzSelect exports and rename a local bindingOpen in Playground
    1. import helpers { double as twice, increment }
    2. let result: int = twice(20) + increment
    Recorded outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · recorded with topaz 5.21.3
    helpers.tpzSelect exports and rename a local bindingOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Observed assertions · passed · 5.21.3

    Exit code 0.

    No stdout.

    No stderr.

    • Passed · expected 0; observed 0
    • Passed · stdout matches the authored expectation
    • Passed · stderr matches the authored expectation

    Save helpers.tpz beside main.tpz. The following run example uses the same selected import and prints its result.

    Source evidence

    Run a selected import with an alias

    Link
    main.tpzRun a selected import with an aliasOpen in Playground
    1. import std.io { writeLine }
    2. import helpers { double as twice, increment }
    3. let result: int = twice(20) + increment
    4. writeLine("{result}")
    Recorded outputexit 0
    41
    
    $ topaz run main.tpz --compiler self · recorded with topaz 5.21.3
    helpers.tpzRun a selected import with an aliasOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 41
    Observed assertions · passed · 5.21.3

    Exit code 0.

    Observed stdout
    1. 41

    No stderr.

    • Passed · expected 0; observed 0
    • Passed · stdout matches the authored expectation
    • Passed · stderr matches the authored expectation
    Source evidence

    Bind a namespace under its final path segment

    Link
    main.tpzBind a namespace under its final path segmentOpen in Playground
    1. import helpers
    2. let result: int = helpers.double(21)
    Recorded outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · recorded with topaz 5.21.3
    helpers.tpzBind a namespace under its final path segmentOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Observed assertions · passed · 5.21.3

    Exit code 0.

    No stdout.

    No stderr.

    • Passed · expected 0; observed 0
    • Passed · stdout matches the authored expectation
    • Passed · stderr matches the authored expectation
    Source evidence

    Choose a namespace name

    Link
    main.tpzChoose a namespace nameOpen in Playground
    1. import helpers as numbers
    2. let result: int = numbers.double(21)
    Recorded outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · recorded with topaz 5.21.3
    helpers.tpzChoose a namespace nameOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Observed assertions · passed · 5.21.3

    Exit code 0.

    No stdout.

    No stderr.

    • Passed · expected 0; observed 0
    • Passed · stdout matches the authored expectation
    • Passed · stderr matches the authored expectation
    Source evidence

    Export an immutable binding

    Link
    main.tpzExport an immutable bindingOpen in Playground
    1. import counters { count }
    2. let value: int = count
    Recorded outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · recorded with topaz 5.21.3
    counters.tpzExport an immutable bindingOpen in Playground
    1. export let count: int = 0
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Observed assertions · passed · 5.21.3

    Exit code 0.

    No stdout.

    No stderr.

    • Passed · expected 0; observed 0
    • Passed · stdout matches the authored expectation
    • Passed · stderr matches the authored expectation
    Source evidence

    Use an exported value in a record default

    Link
    main.tpzUse an exported value in a record defaultOpen in Playground
    1. import std.io
    2. import defaults
    3. record Item {
    4. value: int = defaults.seed
    5. }
    6. let item = Item {}
    7. io.writeLine("{item.value}")
    Expected outputexit 0
    41
    
    $ topaz run main.tpz --compiler self · target product 5.21.3
    defaults.tpzUse an exported value in a record defaultOpen in Playground
    1. export let visible: int = 0
    2. export let seed: int = 41
    3. let mut state: int = 42
    4. type Secret = int
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 41
    Source evidence

    Export the nominal type used by an inferred public result

    Link
    main.tpzExport the nominal type used by an inferred public resultOpen in Playground
    1. import lib
    2. let value: lib.Hidden = lib.make()
    3. let observed: int = value.value
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzExport the nominal type used by an inferred public resultOpen in Playground
    1. export record Hidden { value: int }
    2. export function make() { Hidden { value: 7 } }
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Export the nominal type used by a public binding

    Link
    main.tpzExport the nominal type used by a public bindingOpen in Playground
    1. import lib
    2. let value: lib.Hidden = lib.value
    3. let observed: int = value.value
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzExport the nominal type used by a public bindingOpen in Playground
    1. export record Hidden { value: int }
    2. export let value = Hidden { value: 7 }
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    A private alias of a public type is transparent

    Link
    main.tpzA private alias of a public type is transparentOpen in Playground
    1. import lib
    2. let value: int = lib.count()
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzA private alias of a public type is transparentOpen in Playground
    1. type Count = int
    2. export function count() -> Count { 1 }
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Free calls, assignments, and loops in an entry

    Link
    helpers.tpzFree calls, assignments, and loops in an entryOpen in Playground
    1. import std.io
    2. export let value: int = 1
    3. let mut count: int = 0
    4. io.writeLine("free")
    5. for item in ([1]) {
    6. count = count + item
    7. io.writeLine("loop")
    8. }
    9. io.writeLine("{count}")
    Expected outputexit 0
    free
    loop
    1
    
    $ topaz run helpers.tpz --compiler self · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. free
    2. loop
    3. 1
    Source evidence

    The same source file imported

    Link
    main.tpzThe same source file importedOpen in Playground
    1. import helpers
    2. import std.io
    3. io.writeLine("{helpers.value}")
    Expected outputexit 0
    free
    loop
    1
    1
    
    $ topaz run main.tpz --compiler self · target product 5.21.3
    helpers.tpzThe same source file importedOpen in Playground
    1. import std.io
    2. export let value: int = 1
    3. let mut count: int = 0
    4. io.writeLine("free")
    5. for item in ([1]) {
    6. count = count + item
    7. io.writeLine("loop")
    8. }
    9. io.writeLine("{count}")
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. free
    2. loop
    3. 1
    4. 1
    Source evidence

    A diamond initializes once in ready-identity order

    Link
    main.tpzA diamond initializes once in ready-identity orderOpen in Playground
    1. import a
    2. import b
    3. import std.io
    4. io.writeLine("entry")
    Expected outputexit 0
    shared
    b
    z
    a
    entry
    
    $ topaz run main.tpz --compiler self · target product 5.21.3
    a.tpzA diamond initializes once in ready-identity orderOpen in Playground
    1. import z
    2. import std.io
    3. export let value: int = {
    4. io.writeLine("a")
    5. z.value
    6. }
    b.tpzA diamond initializes once in ready-identity orderOpen in Playground
    1. import shared
    2. import std.io
    3. export let value: int = {
    4. io.writeLine("b")
    5. shared.value
    6. }
    z.tpzA diamond initializes once in ready-identity orderOpen in Playground
    1. import shared
    2. import std.io
    3. export let value: int = {
    4. io.writeLine("z")
    5. shared.value
    6. }
    shared.tpzA diamond initializes once in ready-identity orderOpen in Playground
    1. import std.io
    2. export let value: int = {
    3. io.writeLine("shared")
    4. 1
    5. }
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. shared
    2. b
    3. z
    4. a
    5. entry
    Source evidence

    Reversing import lines preserves the initialization trace

    Link
    main.tpzReversing import lines preserves the initialization traceOpen in Playground
    1. import std.io
    2. import b
    3. import a
    4. io.writeLine("entry")
    Expected outputexit 0
    shared
    b
    z
    a
    entry
    
    $ topaz run main.tpz --compiler self · target product 5.21.3
    a.tpzReversing import lines preserves the initialization traceOpen in Playground
    1. import z
    2. import std.io
    3. export let value: int = {
    4. io.writeLine("a")
    5. z.value
    6. }
    b.tpzReversing import lines preserves the initialization traceOpen in Playground
    1. import shared
    2. import std.io
    3. export let value: int = {
    4. io.writeLine("b")
    5. shared.value
    6. }
    z.tpzReversing import lines preserves the initialization traceOpen in Playground
    1. import shared
    2. import std.io
    3. export let value: int = {
    4. io.writeLine("z")
    5. shared.value
    6. }
    shared.tpzReversing import lines preserves the initialization traceOpen in Playground
    1. import std.io
    2. export let value: int = {
    3. io.writeLine("shared")
    4. 1
    5. }
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. shared
    2. b
    3. z
    4. a
    5. entry
    Source evidence

    A namespace import initializes an export-less module

    Link
    main.tpzA namespace import initializes an export-less moduleOpen in Playground
    1. import setup
    2. import std.io
    3. io.writeLine("entry")
    Expected outputexit 0
    setup
    entry
    
    $ topaz run main.tpz --compiler self · target product 5.21.3
    setup.tpzA namespace import initializes an export-less moduleOpen in Playground
    1. import std.io
    2. let initialized: int = {
    3. io.writeLine("setup")
    4. 1
    5. }
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. setup
    2. entry
    Source evidence

    Removing the back edge gives dependency-first effects

    Link
    main.tpzRemoving the back edge gives dependency-first effectsOpen in Playground
    1. import first
    2. import std.io
    3. io.writeLine("entry")
    Expected outputexit 0
    second
    first
    entry
    
    $ topaz run main.tpz --compiler self · target product 5.21.3
    first.tpzRemoving the back edge gives dependency-first effectsOpen in Playground
    1. import second
    2. import std.io
    3. export let one: int = {
    4. io.writeLine("first")
    5. 1
    6. }
    second.tpzRemoving the back edge gives dependency-first effectsOpen in Playground
    1. import std.io
    2. export let two: int = {
    3. io.writeLine("second")
    4. 2
    5. }
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. second
    2. first
    3. entry
    Source evidence

    Move the dependency before the initializer

    Link
    main.tpzMove the dependency before the initializerOpen in Playground
    1. let second = 1
    2. export let first = second
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    The same source-order repair in an imported file

    Link
    main.tpzThe same source-order repair in an imported fileOpen in Playground
    1. import lib
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzThe same source-order repair in an imported fileOpen in Playground
    1. let second = 1
    2. export let first = second
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Repairing the fault completes the remaining initialization

    Link
    main.tpzRepairing the fault completes the remaining initializationOpen in Playground
    1. import a
    2. import b
    3. import c
    4. import std.io
    5. io.writeLine("entry")
    Expected outputexit 0
    a
    b-before
    b-after
    c
    entry
    
    $ topaz run main.tpz --compiler self · target product 5.21.3
    a.tpzRepairing the fault completes the remaining initializationOpen in Playground
    1. import std.io
    2. export let value: int = {
    3. io.writeLine("a")
    4. 1
    5. }
    b.tpzRepairing the fault completes the remaining initializationOpen in Playground
    1. import std.io
    2. function readAt(index: int) -> int {
    3. let values = [10]
    4. values[index]
    5. }
    6. export let value: int = {
    7. io.writeLine("b-before")
    8. readAt(0)
    9. }
    10. export let after: int = {
    11. io.writeLine("b-after")
    12. 1
    13. }
    c.tpzRepairing the fault completes the remaining initializationOpen in Playground
    1. import std.io
    2. export let value: int = {
    3. io.writeLine("c")
    4. 1
    5. }
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. a
    2. b-before
    3. b-after
    4. c
    5. entry
    Source evidence

    Omit the namespace alias to keep its default name

    Link
    main.tpzOmit the namespace alias to keep its default nameOpen in Playground
    1. import lib
    2. let result: int = lib.value
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzOmit the namespace alias to keep its default nameOpen in Playground
    1. export let value: int = 1
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Omit the selected alias to keep its source name

    Link
    main.tpzOmit the selected alias to keep its source nameOpen in Playground
    1. import lib { value }
    2. let result: int = value
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzOmit the selected alias to keep its source nameOpen in Playground
    1. export let value: int = 1
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Export every record binding after one initializer

    Link
    main.tpzExport every record binding after one initializerOpen in Playground
    1. import lib
    2. import std.io { writeLine }
    3. writeLine("{lib.first}")
    4. writeLine("{lib.second}")
    Expected outputexit 0
    init
    10
    20
    
    $ topaz run main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzExport every record binding after one initializerOpen in Playground
    1. import std.io { writeLine }
    2. function make() -> { first: int, second: int } {
    3. writeLine("init")
    4. { first: 10, second: 20 }
    5. }
    6. export let { first: first, second: second } = make()
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. init
    2. 10
    3. 20
    Source evidence

    An outer pattern annotation supplies each public binding type

    Link
    main.tpzAn outer pattern annotation supplies each public binding typeOpen in Playground
    1. import lib { count, label }
    2. let number: int = count
    3. let text: string = label
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzAn outer pattern annotation supplies each public binding typeOpen in Playground
    1. export let { nested: { count: count }, label: label }: { nested: { count: int }, label: string } = { nested: { count: 4 }, label: "four" }
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Export names from an ordinary nominal record pattern

    Link
    main.tpzExport names from an ordinary nominal record patternOpen in Playground
    1. import lib
    2. import std.io { writeLine }
    3. writeLine("{lib.first + lib.second}")
    Expected outputexit 0
    42
    
    $ topaz run main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzExport names from an ordinary nominal record patternOpen in Playground
    1. record Pair { first: int, second: int }
    2. export let Pair { first: first, second: second } = Pair { first: 20, second: 22 }
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 42
    Source evidence

    A mutable local leaves the exported array unchanged

    Link
    main.tpzA mutable local leaves the exported array unchangedOpen in Playground
    1. import std.io
    2. import helpers { items }
    3. let mut local = items
    4. local.push(3)
    5. io.writeLine("{items.length}:{local.length}")
    Expected outputexit 0
    2:3
    
    $ topaz run main.tpz --compiler self · target product 5.21.3
    helpers.tpzA mutable local leaves the exported array unchangedOpen in Playground
    1. export let items = [1, 2]
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 2:3
    Source evidence

    Rejected forms and boundaries

    Link

    The following files demonstrate rejected imports and exports. Compare their commands with the accepted examples above.

    Use is not an import item

    Link
    main.tpzUse is not an import itemOpen in Playground
    1. use helpers
    Recorded outputexit 1
    No stdout.
    error[TPZ2008]: `use` is reserved and unused; did you mean `import`?
     --> main.tpz:1:1
      |
    1 | use helpers
      | ^^^
    
    main.tpz: 1 diagnostic
    
    $ topaz check main.tpz --compiler self · recorded with topaz 5.21.3
    helpers.tpzUse is not an import itemOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Rejection during parse. Nonzero exit.

    • TPZ2008 reserved-use-item at main.tpz:1:1
    Observed assertions · passed · 5.21.3

    Exit code 1.

    No stdout.

    Observed stderr
    1. error[TPZ2008]: `use` is reserved and unused; did you mean `import`?
    2. --> main.tpz:1:1
    3. |
    4. 1 | use helpers
    5. | ^^^
    6. main.tpz: 1 diagnostic
    • Passed · expected nonzero; observed 1
    • Passed · stdout matches the authored expectation
    • Passed · checking TPZ2008; cause reserved-use-item; primary location asserted; additional diagnostics allow
    Source evidence

    A string is not a module path

    Link
    main.tpzA string is not a module pathOpen in Playground
    1. import "helpers"
    Recorded outputexit 1
    No stdout.
    error[TPZ2008]: string and template module paths are reserved and unused; module paths are dotted identifiers
     --> main.tpz:1:1
      |
    1 | import "helpers"
      | ^^^^^^
    
    main.tpz: 1 diagnostic
    
    $ topaz check main.tpz --compiler self · recorded with topaz 5.21.3
    helpers.tpzA string is not a module pathOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Rejection during parse. Nonzero exit.

    • TPZ2008 reserved-string-module-path at main.tpz:1:1
    Observed assertions · passed · 5.21.3

    Exit code 1.

    No stdout.

    Observed stderr
    1. error[TPZ2008]: string and template module paths are reserved and unused; module paths are dotted identifiers
    2. --> main.tpz:1:1
    3. |
    4. 1 | import "helpers"
    5. | ^^^^^^
    6. main.tpz: 1 diagnostic
    • Passed · expected nonzero; observed 1
    • Passed · stdout matches the authored expectation
    • Passed · checking TPZ2008; cause reserved-string-module-path; primary location asserted; additional diagnostics allow
    Source evidence

    Export lists are rejected

    Link
    main.tpzExport lists are rejectedOpen in Playground
    1. function double(value: int) -> int {
    2. value + value
    3. }
    4. export { double }
    Recorded outputexit 1
    No stdout.
    error[TPZ2009]: export lists are invalid syntax; put `export` on each public declaration
     --> main.tpz:4:1
      |
    4 | export { double }
      | ^^^^^^
    
    main.tpz: 1 diagnostic
    
    $ topaz check main.tpz --compiler self · recorded with topaz 5.21.3
    Expected result

    Expected result

    Rejection during parse. Nonzero exit.

    • TPZ2009 rejected-export-list at main.tpz:4:1
    Observed assertions · passed · 5.21.3

    Exit code 1.

    No stdout.

    Observed stderr
    1. error[TPZ2009]: export lists are invalid syntax; put `export` on each public declaration
    2. --> main.tpz:4:1
    3. |
    4. 4 | export { double }
    5. | ^^^^^^
    6. main.tpz: 1 diagnostic
    • Passed · expected nonzero; observed 1
    • Passed · stdout matches the authored expectation
    • Passed · checking TPZ2009; cause rejected-export-list; primary location asserted; additional diagnostics allow
    Source evidence

    Export import is rejected

    Link
    main.tpzExport import is rejectedOpen in Playground
    1. export import helpers
    Recorded outputexit 1
    No stdout.
    error[TPZ2009]: re-export syntax does not exist (`export import ...` is rejected)
     --> main.tpz:1:1
      |
    1 | export import helpers
      | ^^^^^^
    
    main.tpz: 1 diagnostic
    
    $ topaz check main.tpz --compiler self · recorded with topaz 5.21.3
    helpers.tpzExport import is rejectedOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Rejection during parse. Nonzero exit.

    • TPZ2009 rejected-reexport at main.tpz:1:1
    Observed assertions · passed · 5.21.3

    Exit code 1.

    No stdout.

    Observed stderr
    1. error[TPZ2009]: re-export syntax does not exist (`export import ...` is rejected)
    2. --> main.tpz:1:1
    3. |
    4. 1 | export import helpers
    5. | ^^^^^^
    6. main.tpz: 1 diagnostic
    • Passed · expected nonzero; observed 1
    • Passed · stdout matches the authored expectation
    • Passed · checking TPZ2009; cause rejected-reexport; primary location asserted; additional diagnostics allow
    Source evidence

    A namespace alias and selection do not compose

    Link
    main.tpzA namespace alias and selection do not composeOpen in Playground
    1. import helpers as names { double }
    Recorded outputexit 1
    No stdout.
    error[TPZ2009]: a namespace alias and a selection list do not compose (`import m as ns { x }` is invalid syntax)
     --> main.tpz:1:25
      |
    1 | import helpers as names { double }
      |                         ^
    
    main.tpz: 1 diagnostic
    
    $ topaz check main.tpz --compiler self · recorded with topaz 5.21.3
    helpers.tpzA namespace alias and selection do not composeOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Rejection during parse. Nonzero exit.

    • TPZ2009 namespace-alias-with-selection at main.tpz:1:25
    Observed assertions · passed · 5.21.3

    Exit code 1.

    No stdout.

    Observed stderr
    1. error[TPZ2009]: a namespace alias and a selection list do not compose (`import m as ns { x }` is invalid syntax)
    2. --> main.tpz:1:25
    3. |
    4. 1 | import helpers as names { double }
    5. | ^
    6. main.tpz: 1 diagnostic
    • Passed · expected nonzero; observed 1
    • Passed · stdout matches the authored expectation
    • Passed · checking TPZ2009; cause namespace-alias-with-selection; primary location asserted; additional diagnostics allow
    Source evidence

    Imports precede other items

    Link
    main.tpzImports precede other itemsOpen in Playground
    1. let before: int = 0
    2. import helpers
    Recorded outputexit 1
    No stdout.
    error[TPZ2010]: imports form a prologue: every `import` precedes all other top-level items
     --> main.tpz:2:1
      |
    2 | import helpers
      | ^^^^^^^^^^^^^^
    
    main.tpz: 1 diagnostic
    
    $ topaz check main.tpz --compiler self · recorded with topaz 5.21.3
    helpers.tpzImports precede other itemsOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Rejection during parse. Nonzero exit.

    • TPZ2010 import-after-prologue at main.tpz:2:1
    Observed assertions · passed · 5.21.3

    Exit code 1.

    No stdout.

    Observed stderr
    1. error[TPZ2010]: imports form a prologue: every `import` precedes all other top-level items
    2. --> main.tpz:2:1
    3. |
    4. 2 | import helpers
    5. | ^^^^^^^^^^^^^^
    6. main.tpz: 1 diagnostic
    • Passed · expected nonzero; observed 1
    • Passed · stdout matches the authored expectation
    • Passed · checking TPZ2010; cause import-after-prologue; primary location asserted; additional diagnostics allow
    Source evidence

    A selected name must be exported

    Link
    main.tpzA selected name must be exportedOpen in Playground
    1. import helpers { secret }
    Recorded outputexit 1
    No stdout.
    error[TPZ3009]: `secret` is not exported by `helpers`
     --> main.tpz:1:18
      |
    1 | import helpers { secret }
      |                  ^^^^^^
    
    main.tpz: 1 diagnostic
    
    $ topaz check main.tpz --compiler self · recorded with topaz 5.21.3
    helpers.tpzA selected name must be exportedOpen in Playground
    1. export function double(value: int) -> int {
    2. value + value
    3. }
    4. export let increment: int = 1
    5. let secret: int = 99
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3009 selected-name-not-exported at main.tpz:1:18
    Observed assertions · passed · 5.21.3

    Exit code 1.

    No stdout.

    Observed stderr
    1. error[TPZ3009]: `secret` is not exported by `helpers`
    2. --> main.tpz:1:18
    3. |
    4. 1 | import helpers { secret }
    5. | ^^^^^^
    6. main.tpz: 1 diagnostic
    • Passed · expected nonzero; observed 1
    • Passed · stdout matches the authored expectation
    • Passed · checking TPZ3009; cause selected-name-not-exported; primary location asserted; additional diagnostics allow

    The target exports double and increment. The intended rejection concerns the private secret binding, not an empty export table.

    Source evidence

    Exporting a mutable let is rejected

    Link
    main.tpzExporting a mutable let is rejectedOpen in Playground
    1. export let mut count: int = 0
    Recorded outputexit 1
    No stdout.
    error[TPZ3011]: `export let mut` is a static error: exported bindings are immutable views
     --> main.tpz:1:16
      |
    1 | export let mut count: int = 0
      |                ^^^^^
    
    main.tpz: 1 diagnostic
    
    $ topaz check main.tpz --compiler self · recorded with topaz 5.21.3
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3011 mutable-let-export at main.tpz:1:16
    Observed assertions · passed · 5.21.3

    Exit code 1.

    No stdout.

    Observed stderr
    1. error[TPZ3011]: `export let mut` is a static error: exported bindings are immutable views
    2. --> main.tpz:1:16
    3. |
    4. 1 | export let mut count: int = 0
    5. | ^^^^^
    6. main.tpz: 1 diagnostic
    • Passed · expected nonzero; observed 1
    • Passed · stdout matches the authored expectation
    • Passed · checking TPZ3011; cause mutable-let-export; primary location asserted; additional diagnostics allow
    Source evidence

    A record default cannot read a private mutable value

    Link
    main.tpzA record default cannot read a private mutable valueOpen in Playground
    1. import defaults
    2. record Item {
    3. value: int = defaults.state
    4. }
    5. let item = Item {}
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    defaults.tpzA record default cannot read a private mutable valueOpen in Playground
    1. export let visible: int = 0
    2. let seed: int = 41
    3. let mut state: int = 42
    4. type Secret = int
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3009 record-default-private-mutable-member at main.tpz:3:27
    Source evidence

    A default value does not grant access to a private type

    Link
    main.tpzA default value does not grant access to a private typeOpen in Playground
    1. import defaults
    2. record Item {
    3. value: int = {
    4. let saved: defaults.Secret = 1
    5. saved
    6. }
    7. }
    8. let item = Item {}
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    defaults.tpzA default value does not grant access to a private typeOpen in Playground
    1. export let visible: int = 0
    2. let seed: int = 41
    3. let mut state: int = 42
    4. type Secret = int
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3009 record-default-private-type-member at main.tpz:4:29
    Source evidence

    The private value remains inaccessible outside a default

    Link
    main.tpzThe private value remains inaccessible outside a defaultOpen in Playground
    1. import defaults
    2. let value: int = defaults.seed
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    defaults.tpzThe private value remains inaccessible outside a defaultOpen in Playground
    1. export let visible: int = 0
    2. let seed: int = 41
    3. let mut state: int = 42
    4. type Secret = int
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3009 namespace-private-let-outside-default at main.tpz:2:27
    Source evidence

    Reject a private value in a record default

    Link
    main.tpzReject a private value in a record defaultOpen in Playground
    1. import std.io
    2. import defaults
    3. record Item {
    4. value: int = defaults.seed
    5. }
    6. let item = Item {}
    7. io.writeLine("{item.value}")
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    defaults.tpzReject a private value in a record defaultOpen in Playground
    1. export let visible: int = 0
    2. let seed: int = 41
    3. let mut state: int = 42
    4. type Secret = int
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3009 record-default-private-immutable-member at main.tpz:4:27
    Source evidence

    An explicit public result cannot expose a private nominal type

    Link
    main.tpzAn explicit public result cannot expose a private nominal typeOpen in Playground
    1. import lib
    2. let value = lib.make()
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzAn explicit public result cannot expose a private nominal typeOpen in Playground
    1. record Hidden { value: int }
    2. export function make() -> Hidden { Hidden { value: 7 } }
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3014 modules-public-private-nominal at lib.tpz:2:27
    Source evidence

    An inferred public result obeys the same visibility rule

    Link
    main.tpzAn inferred public result obeys the same visibility ruleOpen in Playground
    1. import lib
    2. let value = lib.make()
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzAn inferred public result obeys the same visibility ruleOpen in Playground
    1. record Hidden { value: int }
    2. export function make() { Hidden { value: 7 } }
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3014 modules-public-private-nominal at lib.tpz:2:17
    Source evidence

    A collection result cannot hide a private element type

    Link
    main.tpzA collection result cannot hide a private element typeOpen in Playground
    1. import lib
    2. let value = lib.make()
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzA collection result cannot hide a private element typeOpen in Playground
    1. record Hidden { value: int }
    2. export function make() { [Hidden { value: 7 }] }
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3014 modules-public-private-nominal at lib.tpz:2:17
    Source evidence

    An annotated exported binding cannot expose a private nominal type

    Link
    main.tpzAn annotated exported binding cannot expose a private nominal typeOpen in Playground
    1. import lib
    2. let value = lib.value
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzAn annotated exported binding cannot expose a private nominal typeOpen in Playground
    1. record Hidden { value: int }
    2. export let value: Hidden = Hidden { value: 7 }
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3014 modules-public-private-nominal at lib.tpz:2:19
    Source evidence

    An inferred exported binding cannot expose a private nominal type

    Link
    main.tpzAn inferred exported binding cannot expose a private nominal typeOpen in Playground
    1. import lib
    2. let value = lib.value
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzAn inferred exported binding cannot expose a private nominal typeOpen in Playground
    1. record Hidden { value: int }
    2. export let value = Hidden { value: 7 }
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3014 modules-public-private-nominal at lib.tpz:2:12
    Source evidence

    An alias expansion cannot hide a private nominal result

    Link
    main.tpzAn alias expansion cannot hide a private nominal resultOpen in Playground
    1. import lib
    2. let value = lib.make()
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzAn alias expansion cannot hide a private nominal resultOpen in Playground
    1. record Hidden { value: int }
    2. type Alias = Hidden
    3. export function make() -> Alias { Hidden { value: 7 } }
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3014 modules-public-private-nominal at lib.tpz:3:27
    Source evidence

    An empty namespace still has no selectable member

    Link
    main.tpzAn empty namespace still has no selectable memberOpen in Playground
    1. import setup { missing }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    setup.tpzAn empty namespace still has no selectable memberOpen in Playground
    1. let value: int = 1
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3009 selected-name-not-exported at main.tpz:1:16
    Source evidence

    An import cycle is rejected before initialization

    Link
    main.tpzAn import cycle is rejected before initializationOpen in Playground
    1. import first
    2. import std.io
    3. io.writeLine("entry")
    Expected outputNonzero exit
    No stdout.
    $ topaz run main.tpz --compiler self · target product 5.21.3
    first.tpzAn import cycle is rejected before initializationOpen in Playground
    1. import second
    2. import std.io
    3. export let one: int = {
    4. io.writeLine("first")
    5. 1
    6. }
    second.tpzAn import cycle is rejected before initializationOpen in Playground
    1. import first
    2. import std.io
    3. export let two: int = {
    4. io.writeLine("second")
    5. 2
    6. }
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3006 module-import-cycle at first.tpz:1:8
    Source evidence

    An entry initializer cannot read a later binding

    Link
    main.tpzAn entry initializer cannot read a later bindingOpen in Playground
    1. export let first = second
    2. let second = 1
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3018 module-initializer-not-ready at main.tpz:1:20
    Source evidence

    The same early read is rejected in an imported file

    Link
    main.tpzThe same early read is rejected in an imported fileOpen in Playground
    1. import lib
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzThe same early read is rejected in an imported fileOpen in Playground
    1. export let first = second
    2. let second = 1
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3018 module-initializer-not-ready at lib.tpz:1:20
    Source evidence

    A fault preserves earlier output and stops remaining initialization

    Link
    main.tpzA fault preserves earlier output and stops remaining initializationOpen in Playground
    1. import a
    2. import b
    3. import c
    4. import std.io
    5. io.writeLine("entry")
    Expected outputNonzero exit
    a
    b-before
    
    $ topaz run main.tpz --compiler self · target product 5.21.3
    a.tpzA fault preserves earlier output and stops remaining initializationOpen in Playground
    1. import std.io
    2. export let value: int = {
    3. io.writeLine("a")
    4. 1
    5. }
    b.tpzA fault preserves earlier output and stops remaining initializationOpen in Playground
    1. import std.io
    2. function readAt(index: int) -> int {
    3. let values = [10]
    4. values[index]
    5. }
    6. export let value: int = {
    7. io.writeLine("b-before")
    8. readAt(1)
    9. }
    10. export let after: int = {
    11. io.writeLine("b-after")
    12. 1
    13. }
    c.tpzA fault preserves earlier output and stops remaining initializationOpen in Playground
    1. import std.io
    2. export let value: int = {
    3. io.writeLine("c")
    4. 1
    5. }
    Expected result

    Expected result

    Rejection during run. Nonzero exit.

    • TPZ4001 diagnostic-tpz4001 at b.tpz:4:5
    Expected stdout
    1. a
    2. b-before
    Source evidence

    Reject a namespace alias repeating its default name

    Link
    main.tpzReject a namespace alias repeating its default nameOpen in Playground
    1. import lib as lib
    2. let result: int = lib.value
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzReject a namespace alias repeating its default nameOpen in Playground
    1. export let value: int = 1
    Expected result

    Expected result

    Rejection during parse. Nonzero exit.

    • TPZ2009 redundant-import-alias at main.tpz:1:15

    This rejection is the intended TPZ2009/parse contract for a redundant alias. The reviewed SELF parser currently accepts the form. The limitation permits only the expected exit and diagnostic assertions to fail; the expected source location is the alias identifier.

    Source evidence

    Reject a selected alias repeating its source name

    Link
    main.tpzReject a selected alias repeating its source nameOpen in Playground
    1. import lib { value as value }
    2. let result: int = value
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzReject a selected alias repeating its source nameOpen in Playground
    1. export let value: int = 1
    Expected result

    Expected result

    Rejection during parse. Nonzero exit.

    • TPZ2009 redundant-import-alias at main.tpz:1:23

    This rejection is the intended TPZ2009/parse contract for a redundant alias. The reviewed SELF parser currently accepts the form. The limitation permits only the expected exit and diagnostic assertions to fail; the expected source location is the alias identifier.

    Source evidence

    Use plain let when a pattern publishes no binding

    Link
    main.tpzUse plain let when a pattern publishes no bindingOpen in Playground
    1. export let _ = 1
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during parse. Nonzero exit.

    • TPZ2007 export-let-no-binding at main.tpz:1:12
    Source evidence

    Export preserves the ordinary refutable-let rejection

    Link
    main.tpzExport preserves the ordinary refutable-let rejectionOpen in Playground
    1. let maybe: Option<int> = None()
    2. export let Some(value) = maybe
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5026 diagnostics-refutable-let-pattern at main.tpz:2:12
    Source evidence

    Each bound name must have a public resolved type

    Link
    main.tpzEach bound name must have a public resolved typeOpen in Playground
    1. import lib
    2. let observed = lib.count
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self --format json · target product 5.21.3
    lib.tpzEach bound name must have a public resolved typeOpen in Playground
    1. record Hidden { value: int }
    2. export let { item: item, count: count } = { item: Hidden { value: 1 }, count: 2 }
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3014 modules-public-private-nominal at lib.tpz:2:20
    Source evidence

    An imported array has an immutable root

    Link
    main.tpzAn imported array has an immutable rootOpen in Playground
    1. import helpers { items }
    2. items[0] = 9
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --compiler self · target product 5.21.3
    helpers.tpzAn imported array has an immutable rootOpen in Playground
    1. export let items = [1, 2]
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5003 bindings-assignment-to-immutable at main.tpz:2:1
    Source evidence

    Pending contracts

    Link

    Related contracts

    Link

    Functions and generics

    check

    Functions and generics owns callable declarations, calls, and exported protocol-bound restrictions. The check command owns invocation, selected entry and root, output channels, and exit status. Module visibility does not redefine those contracts.

    Import after non-import item

    Malformed import list

    Rejected module-adjacent form

    Duplicate import

    Invalid exported let pattern

    Mutable export is rejected

    Name is not exported

    Assignment to imported binding

    Private type in exported surface

    Reserved module form

    Import cycle

    Initializer reads a later binding

    Index out of bounds

    Refutable let pattern

    TPZ5524

    Immutable binding mutation

    Menu

    Download