Scope and ownership
LinkThis 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
LinkModulePath = Identifier ("." Identifier)* ;ImportItem = NamespaceImport | SelectedImport ;NamespaceImport = "import" ModulePath ("as" Identifier)? ;SelectedImport ="import" ModulePath "{" ImportSpec ("," ImportSpec)* ","? "}" ;ImportSpec = Identifier ("as" Identifier)? ;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
- parseModulePath, parseImportSpec, parseImportSelection, parseImportAlias, parseImportAtProgram at
af88afbc1d99· 1016-1204 - parseExport, exportDeclarationHead, rejected module forms, parseProgramItem at
af88afbc1d99· 1206-1339 - pull/41 at
271329b482bc
Files and the source program
LinkThe 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.
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 .. For example, geometry. selects geometry/. 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
- modulePath, moduleIdentity at
af88afbc1d99· 51-77 - parseModulePath, parseImportSpec, parseImportSelection, parseImportAlias, parseImportAtProgram at
af88afbc1d99· 1016-1204
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
- discoverModuleGraph at
af88afbc1d99· 835-913
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
- parseModulePath, parseImportSpec, parseImportSelection, parseImportAlias, parseImportAtProgram at
af88afbc1d99· 1016-1204
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
- validateImportedTopLevel at
271329b482bc· 648-678 - emitModuleInit at
271329b482bc· 391-453 - pull/41 at
271329b482bc
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
- discoverModuleGraph at
271329b482bc· 835-894 - dependencyOrder/moduleDependencyCatalog at
271329b482bc· 308-394 - emitModuleInit at
271329b482bc· 391-453 - __topaz_initialize at
271329b482bc· 651-659 - pull/41 at
271329b482bc
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
- diagnoseCycles at
271329b482bc· 465-525 - pull/41 at
271329b482bc
Read a binding after initialization
Why
A file's role does not change the meaning of its bindings.
Source evidence
- validateImportedInitializers at
271329b482bc· 784-827 - initObserveReference at
271329b482bc· 360-389 - emitModuleInit at
271329b482bc· 391-453 - pull/41 at
271329b482bc - reportInitializationViolation/checkTopLevelInitializationOrder at
271329b482bc· 554-595
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
- emitProgramRust at
271329b482bc· 580-599 - pull/41 at
271329b482bc
Namespace and selected imports
LinkNamespace 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..
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
- importBindings at
af88afbc1d99· 143-218
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
- importBindings at
af88afbc1d99· 143-218
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
- parseImportSpec/parseImportAlias/parseImport at
271329b482bc· 1039-1184 - importBindings at
271329b482bc· 148-213 - TPZ2009 rejected_module_form at
271329b482bc· 292-300 - pull/41 at
271329b482bc
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
- parseModulePath, parseImportSpec, parseImportSelection, parseImportAlias, parseImportAtProgram at
af88afbc1d99· 1016-1204
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
- parseModulePath, parseImportSpec, parseImportSelection, parseImportAlias, parseImportAtProgram at
af88afbc1d99· 1016-1204
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
- recordImportEdge at
af88afbc1d99· 678-724
Exports and read-only import bindings
LinkPublic 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
- parseExport, exportDeclarationHead, rejected module forms, parseProgramItem at
af88afbc1d99· 1206-1339 - namedStatementBinding, letBindings, buildTable at
af88afbc1d99· 220-378
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
- parseExport, exportDeclarationHead, rejected module forms, parseProgramItem at
af88afbc1d99· 1206-1339 - parseExport at
72a59a31125f· 1206-1224 - collectPatternBindings and letBindings at
72a59a31125f· 87-135;263-294 - emitPatternLet and installPattern at
72a59a31125f· 2242-2273 - publish exports after module initialization at
72a59a31125f· 580-596 - pull/44 at
72a59a31125f
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
- namedStatementBinding, letBindings, buildTable at
af88afbc1d99· 220-378
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
- validateImportSurfaces at
af88afbc1d99· 174-219 - validateImportSurfaces at
271329b482bc· 174-192 - pull/41 at
271329b482bc
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
- namespaceMemberResolution at
af88afbc1d99· 260-350 - pull/38 at
9b1bbdeceba9
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
- resolveAssignmentIdentifier, rejectNamespaceAssignment at
af88afbc1d99· 694-772 - issues/31 at
1cbf38d3d422
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
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
Record defaults respect module privacy
Why
Field defaults are ordinary expression contexts.
Source evidence
- namespaceMemberResolution at
151141d7bb44· 266-322 - walkNodeChildren record field default context at
151141d7bb44· 1102-1113 - pull/38 at
9b1bbdeceba9
An exported function may expose an exported user protocol bound
Linkexport protocol Labelled { function label(value: Self) -> string }export function describe<T: Labelled>(value: T) -> string { Labelled.label(value) }
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- exportDeclarationHead at
72a59a31125f· 1237-1257 - namedStatementBinding / buildTable at
72a59a31125f· 219-260;317-374 - checkFunctionDeclarationInner exported bound guard at
72a59a31125f· 158-191 - pull/41 at
72a59a31125f
A private protocol is not selected through import
Linkimport contracts { Hidden }
No stdout.
protocol Hidden { function label(value: Self) -> string }export let marker = 0
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3009protocol-name-not-exported atexample.tpz:1:20
Source evidence
- exportDeclarationHead at
72a59a31125f· 1237-1257 - namedStatementBinding / buildTable at
72a59a31125f· 219-260;317-374 - checkFunctionDeclarationInner exported bound guard at
72a59a31125f· 158-191 - pull/41 at
72a59a31125f
An exported protocol cannot expose a private nominal parameter type
Linkrecord Hidden { n: int }export protocol Render { function render(value: Self, input: Hidden) -> string }
No stdout.
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3014modules-public-private-nominal atexample.tpz:2:62
Source evidence
- exportDeclarationHead at
72a59a31125f· 1237-1257 - namedStatementBinding / buildTable at
72a59a31125f· 219-260;317-374 - checkFunctionDeclarationInner exported bound guard at
72a59a31125f· 158-191 - pull/41 at
72a59a31125f
An exported protocol signature may use an exported nominal type
Linkexport record Input { n: int }export protocol Render { function render(value: Self, input: Input) -> string }
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- exportDeclarationHead at
72a59a31125f· 1237-1257 - namedStatementBinding / buildTable at
72a59a31125f· 219-260;317-374 - checkFunctionDeclarationInner exported bound guard at
72a59a31125f· 158-191 - pull/41 at
72a59a31125f
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.
Rejected source forms
LinkReserved 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
- parseExport, exportDeclarationHead, rejected module forms, parseProgramItem at
af88afbc1d99· 1206-1339
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
- parseExport, exportDeclarationHead, rejected module forms, parseProgramItem at
af88afbc1d99· 1206-1339
Complete import and export examples
LinkSave the complete file set shown for an example, then use its displayed command.
Select exports and rename a local binding
Linkimport helpers { double as twice, increment }let result: int = twice(20) + increment
No stdout.
export function double(value: int) -> int {value + value}export let increment: int = 1let 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
- parseModulePath, parseImportSpec, parseImportSelection, parseImportAlias, parseImportAtProgram at
af88afbc1d99· 1016-1204 - importBindings at
af88afbc1d99· 143-218 - validateImportSurfaces at
af88afbc1d99· 174-219
Run a selected import with an alias
Linkimport std.io { writeLine }import helpers { double as twice, increment }let result: int = twice(20) + incrementwriteLine("{result}")
41
export function double(value: int) -> int {value + value}export let increment: int = 1let secret: int = 99
Expected result
Expected result
Execution completes. Exit code 0.
41
Observed assertions · passed · 5.21.3
Exit code 0.
41
No stderr.
- Passed · expected 0; observed 0
- Passed · stdout matches the authored expectation
- Passed · stderr matches the authored expectation
Source evidence
- parseModulePath, parseImportSpec, parseImportSelection, parseImportAlias, parseImportAtProgram at
af88afbc1d99· 1016-1204 - importBindings at
af88afbc1d99· 143-218 - validateImportSurfaces at
af88afbc1d99· 174-219
Bind a namespace under its final path segment
Linkimport helperslet result: int = helpers.double(21)
No stdout.
export function double(value: int) -> int {value + value}export let increment: int = 1let 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
- importBindings at
af88afbc1d99· 143-218 - namespaceMemberResolution at
af88afbc1d99· 260-350
Choose a namespace name
Linkimport helpers as numberslet result: int = numbers.double(21)
No stdout.
export function double(value: int) -> int {value + value}export let increment: int = 1let 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
- importBindings at
af88afbc1d99· 143-218 - namespaceMemberResolution at
af88afbc1d99· 260-350
Export an immutable binding
Linkimport counters { count }let value: int = count
No stdout.
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
- namedStatementBinding, letBindings, buildTable at
af88afbc1d99· 220-378 - importBindings at
af88afbc1d99· 143-218 - validateImportSurfaces at
af88afbc1d99· 174-219
Use an exported value in a record default
Linkimport std.ioimport defaultsrecord Item {value: int = defaults.seed}let item = Item {}io.writeLine("{item.value}")
41
export let visible: int = 0export let seed: int = 41let mut state: int = 42type Secret = int
Expected result
Expected result
Execution completes. Exit code 0.
41
Source evidence
- namespaceMemberResolution at
151141d7bb44· 266-322 - walkNodeChildren record field default context at
151141d7bb44· 1102-1113 - pull/38 at
9b1bbdeceba9
Export the nominal type used by an inferred public result
Linkimport liblet value: lib.Hidden = lib.make()let observed: int = value.value
No stdout.
export record Hidden { value: int }export function make() { Hidden { value: 7 } }
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
Export the nominal type used by a public binding
Linkimport liblet value: lib.Hidden = lib.valuelet observed: int = value.value
No stdout.
export record Hidden { value: int }export let value = Hidden { value: 7 }
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
A private alias of a public type is transparent
Linkimport liblet value: int = lib.count()
No stdout.
type Count = intexport function count() -> Count { 1 }
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
Free calls, assignments, and loops in an entry
Linkimport std.ioexport let value: int = 1let mut count: int = 0io.writeLine("free")for item in ([1]) {count = count + itemio.writeLine("loop")}io.writeLine("{count}")
free loop 1
Expected result
Expected result
Execution completes. Exit code 0.
freeloop1
Source evidence
- validateImportedTopLevel at
271329b482bc· 648-678 - emitModuleInit at
271329b482bc· 391-453 - pull/41 at
271329b482bc
The same source file imported
Linkimport helpersimport std.ioio.writeLine("{helpers.value}")
free loop 1 1
import std.ioexport let value: int = 1let mut count: int = 0io.writeLine("free")for item in ([1]) {count = count + itemio.writeLine("loop")}io.writeLine("{count}")
Expected result
Expected result
Execution completes. Exit code 0.
freeloop11
Source evidence
- validateImportedTopLevel at
271329b482bc· 648-678 - emitModuleInit at
271329b482bc· 391-453 - pull/41 at
271329b482bc
A diamond initializes once in ready-identity order
Linkimport aimport bimport std.ioio.writeLine("entry")
shared b z a entry
import zimport std.ioexport let value: int = {io.writeLine("a")z.value}
import sharedimport std.ioexport let value: int = {io.writeLine("b")shared.value}
import sharedimport std.ioexport let value: int = {io.writeLine("z")shared.value}
import std.ioexport let value: int = {io.writeLine("shared")1}
Expected result
Expected result
Execution completes. Exit code 0.
sharedbzaentry
Source evidence
- discoverModuleGraph at
271329b482bc· 835-894 - dependencyOrder/moduleDependencyCatalog at
271329b482bc· 308-394 - emitModuleInit at
271329b482bc· 391-453 - __topaz_initialize at
271329b482bc· 651-659 - pull/41 at
271329b482bc
Reversing import lines preserves the initialization trace
Linkimport std.ioimport bimport aio.writeLine("entry")
shared b z a entry
import zimport std.ioexport let value: int = {io.writeLine("a")z.value}
import sharedimport std.ioexport let value: int = {io.writeLine("b")shared.value}
import sharedimport std.ioexport let value: int = {io.writeLine("z")shared.value}
import std.ioexport let value: int = {io.writeLine("shared")1}
Expected result
Expected result
Execution completes. Exit code 0.
sharedbzaentry
Source evidence
- discoverModuleGraph at
271329b482bc· 835-894 - dependencyOrder/moduleDependencyCatalog at
271329b482bc· 308-394 - emitModuleInit at
271329b482bc· 391-453 - __topaz_initialize at
271329b482bc· 651-659 - pull/41 at
271329b482bc
A namespace import initializes an export-less module
Linkimport setupimport std.ioio.writeLine("entry")
setup entry
import std.iolet initialized: int = {io.writeLine("setup")1}
Expected result
Expected result
Execution completes. Exit code 0.
setupentry
Source evidence
- validateImportSurfaces at
271329b482bc· 174-192 - dependencyOrder/moduleDependencyCatalog at
271329b482bc· 308-394 - pull/41 at
271329b482bc
Removing the back edge gives dependency-first effects
Linkimport firstimport std.ioio.writeLine("entry")
second first entry
import secondimport std.ioexport let one: int = {io.writeLine("first")1}
import std.ioexport let two: int = {io.writeLine("second")2}
Expected result
Expected result
Execution completes. Exit code 0.
secondfirstentry
Source evidence
- diagnoseCycles at
271329b482bc· 465-525 - dependencyOrder/moduleDependencyCatalog at
271329b482bc· 308-394 - pull/41 at
271329b482bc
Move the dependency before the initializer
Linklet second = 1export let first = second
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- validateImportedInitializers at
271329b482bc· 784-827 - initObserveReference at
271329b482bc· 360-389 - pull/41 at
271329b482bc
The same source-order repair in an imported file
Linkimport lib
No stdout.
let second = 1export let first = second
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- validateImportedInitializers at
271329b482bc· 784-827 - initObserveReference at
271329b482bc· 360-389 - pull/41 at
271329b482bc
Repairing the fault completes the remaining initialization
Linkimport aimport bimport cimport std.ioio.writeLine("entry")
a b-before b-after c entry
import std.ioexport let value: int = {io.writeLine("a")1}
import std.iofunction readAt(index: int) -> int {let values = [10]values[index]}export let value: int = {io.writeLine("b-before")readAt(0)}export let after: int = {io.writeLine("b-after")1}
import std.ioexport let value: int = {io.writeLine("c")1}
Expected result
Expected result
Execution completes. Exit code 0.
ab-beforeb-aftercentry
Source evidence
- emitProgramRust at
271329b482bc· 580-599 - dependencyOrder/moduleDependencyCatalog at
271329b482bc· 308-394 - pull/41 at
271329b482bc
Omit the namespace alias to keep its default name
Linkimport liblet result: int = lib.value
No stdout.
export let value: int = 1
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- parseImportSpec/parseImportAlias/parseImport at
271329b482bc· 1039-1184 - importBindings at
271329b482bc· 148-213 - TPZ2009 rejected_module_form at
271329b482bc· 292-300 - pull/41 at
271329b482bc
Omit the selected alias to keep its source name
Linkimport lib { value }let result: int = value
No stdout.
export let value: int = 1
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- parseImportSpec/parseImportAlias/parseImport at
271329b482bc· 1039-1184 - importBindings at
271329b482bc· 148-213 - TPZ2009 rejected_module_form at
271329b482bc· 292-300 - pull/41 at
271329b482bc
Export every record binding after one initializer
Linkimport libimport std.io { writeLine }writeLine("{lib.first}")writeLine("{lib.second}")
init 10 20
import std.io { writeLine }function make() -> { first: int, second: int } {writeLine("init"){ first: 10, second: 20 }}export let { first: first, second: second } = make()
Expected result
Expected result
Execution completes. Exit code 0.
init1020
Source evidence
- parseExport at
72a59a31125f· 1206-1224 - collectPatternBindings and letBindings at
72a59a31125f· 87-135;263-294 - emitPatternLet and installPattern at
72a59a31125f· 2242-2273 - publish exports after module initialization at
72a59a31125f· 580-596 - pull/44 at
72a59a31125f
An outer pattern annotation supplies each public binding type
Linkimport lib { count, label }let number: int = countlet text: string = label
No stdout.
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
- parseExport at
72a59a31125f· 1206-1224 - collectPatternBindings and letBindings at
72a59a31125f· 87-135;263-294 - emitPatternLet and installPattern at
72a59a31125f· 2242-2273 - publish exports after module initialization at
72a59a31125f· 580-596 - pull/44 at
72a59a31125f
Export names from an ordinary nominal record pattern
Linkimport libimport std.io { writeLine }writeLine("{lib.first + lib.second}")
42
record Pair { first: int, second: int }export let Pair { first: first, second: second } = Pair { first: 20, second: 22 }
Expected result
Expected result
Execution completes. Exit code 0.
42
Source evidence
- parseExport at
72a59a31125f· 1206-1224 - collectPatternBindings and letBindings at
72a59a31125f· 87-135;263-294 - emitPatternLet and installPattern at
72a59a31125f· 2242-2273 - publish exports after module initialization at
72a59a31125f· 580-596 - pull/44 at
72a59a31125f
A mutable local leaves the exported array unchanged
Linkimport std.ioimport helpers { items }let mut local = itemslocal.push(3)io.writeLine("{items.length}:{local.length}")
2:3
export let items = [1, 2]
Expected result
Expected result
Execution completes. Exit code 0.
2:3
Rejected forms and boundaries
LinkThe following files demonstrate rejected imports and exports. Compare their commands with the accepted examples above.
Use is not an import item
Linkuse helpers
No stdout.
error[TPZ2008]: `use` is reserved and unused; did you mean `import`? --> main.tpz:1:1 | 1 | use helpers | ^^^ main.tpz: 1 diagnostic
export function double(value: int) -> int {value + value}export let increment: int = 1let secret: int = 99
Expected result
Observed assertions · passed · 5.21.3
Exit code 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
- 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
- parseExport, exportDeclarationHead, rejected module forms, parseProgramItem at
af88afbc1d99· 1206-1339
A string is not a module path
Linkimport "helpers"
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
export function double(value: int) -> int {value + value}export let increment: int = 1let secret: int = 99
Expected result
Expected result
Rejection during parse. Nonzero exit.
TPZ2008reserved-string-module-path atmain.tpz:1:1
Observed assertions · passed · 5.21.3
Exit code 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
- 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
- parseExport, exportDeclarationHead, rejected module forms, parseProgramItem at
af88afbc1d99· 1206-1339
Export lists are rejected
Linkfunction double(value: int) -> int {value + value}export { double }
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
Expected result
Observed assertions · passed · 5.21.3
Exit code 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
- 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
- parseExport, exportDeclarationHead, rejected module forms, parseProgramItem at
af88afbc1d99· 1206-1339
Export import is rejected
Linkexport import helpers
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
export function double(value: int) -> int {value + value}export let increment: int = 1let secret: int = 99
Expected result
Observed assertions · passed · 5.21.3
Exit code 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
- 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
- parseExport, exportDeclarationHead, rejected module forms, parseProgramItem at
af88afbc1d99· 1206-1339
A namespace alias and selection do not compose
Linkimport helpers as names { double }
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
export function double(value: int) -> int {value + value}export let increment: int = 1let secret: int = 99
Expected result
Expected result
Rejection during parse. Nonzero exit.
TPZ2009namespace-alias-with-selection atmain.tpz:1:25
Observed assertions · passed · 5.21.3
Exit code 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
- 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
- parseModulePath, parseImportSpec, parseImportSelection, parseImportAlias, parseImportAtProgram at
af88afbc1d99· 1016-1204
Imports precede other items
Linklet before: int = 0import helpers
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
export function double(value: int) -> int {value + value}export let increment: int = 1let secret: int = 99
Expected result
Observed assertions · passed · 5.21.3
Exit code 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
- 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
- parseModulePath, parseImportSpec, parseImportSelection, parseImportAlias, parseImportAtProgram at
af88afbc1d99· 1016-1204
A selected name must be exported
Linkimport helpers { secret }
No stdout.
error[TPZ3009]: `secret` is not exported by `helpers`
--> main.tpz:1:18
|
1 | import helpers { secret }
| ^^^^^^
main.tpz: 1 diagnostic
export function double(value: int) -> int {value + value}export let increment: int = 1let secret: int = 99
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3009selected-name-not-exported atmain.tpz:1:18
Observed assertions · passed · 5.21.3
Exit code 1.
No stdout.
error[TPZ3009]: `secret` is not exported by `helpers`--> main.tpz:1:18|1 | import helpers { secret }| ^^^^^^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
- validateImportSurfaces at
af88afbc1d99· 174-219
Exporting a mutable let is rejected
Linkexport let mut count: int = 0
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
Expected result
Observed assertions · passed · 5.21.3
Exit code 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
- 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
- namedStatementBinding, letBindings, buildTable at
af88afbc1d99· 220-378
A record default cannot read a private mutable value
Linkimport defaultsrecord Item {value: int = defaults.state}let item = Item {}
No stdout.
export let visible: int = 0let seed: int = 41let mut state: int = 42type Secret = int
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3009record-default-private-mutable-member atmain.tpz:3:27
Source evidence
- namespaceMemberResolution at
151141d7bb44· 266-322 - walkNodeChildren record field default context at
151141d7bb44· 1102-1113
A default value does not grant access to a private type
Linkimport defaultsrecord Item {value: int = {let saved: defaults.Secret = 1saved}}let item = Item {}
No stdout.
export let visible: int = 0let seed: int = 41let mut state: int = 42type Secret = int
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3009record-default-private-type-member atmain.tpz:4:29
Source evidence
- namespaceMemberResolution at
151141d7bb44· 266-322 - walkNodeChildren record field default context at
151141d7bb44· 1102-1113
The private value remains inaccessible outside a default
Linkimport defaultslet value: int = defaults.seed
No stdout.
export let visible: int = 0let seed: int = 41let mut state: int = 42type Secret = int
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3009namespace-private-let-outside-default atmain.tpz:2:27
Source evidence
- namespaceMemberResolution at
151141d7bb44· 266-322 - walkNodeChildren record field default context at
151141d7bb44· 1102-1113
Reject a private value in a record default
Linkimport std.ioimport defaultsrecord Item {value: int = defaults.seed}let item = Item {}io.writeLine("{item.value}")
No stdout.
export let visible: int = 0let seed: int = 41let mut state: int = 42type Secret = int
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3009record-default-private-immutable-member atmain.tpz:4:27
Source evidence
- namespaceMemberResolution at
151141d7bb44· 266-322 - walkNodeChildren record field default context at
151141d7bb44· 1102-1113 - pull/38 at
9b1bbdeceba9
An explicit public result cannot expose a private nominal type
Linkimport liblet value = lib.make()
No stdout.
record Hidden { value: int }export function make() -> Hidden { Hidden { value: 7 } }
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3014modules-public-private-nominal atlib.tpz:2:27
Source evidence
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
An inferred public result obeys the same visibility rule
Linkimport liblet value = lib.make()
No stdout.
record Hidden { value: int }export function make() { Hidden { value: 7 } }
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3014modules-public-private-nominal atlib.tpz:2:17
Source evidence
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
A collection result cannot hide a private element type
Linkimport liblet value = lib.make()
No stdout.
record Hidden { value: int }export function make() { [Hidden { value: 7 }] }
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3014modules-public-private-nominal atlib.tpz:2:17
Source evidence
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
An annotated exported binding cannot expose a private nominal type
Linkimport liblet value = lib.value
No stdout.
record Hidden { value: int }export let value: Hidden = Hidden { value: 7 }
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3014modules-public-private-nominal atlib.tpz:2:19
Source evidence
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
An inferred exported binding cannot expose a private nominal type
Linkimport liblet value = lib.value
No stdout.
record Hidden { value: int }export let value = Hidden { value: 7 }
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3014modules-public-private-nominal atlib.tpz:2:12
Source evidence
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
An alias expansion cannot hide a private nominal result
Linkimport liblet value = lib.make()
No stdout.
record Hidden { value: int }type Alias = Hiddenexport function make() -> Alias { Hidden { value: 7 } }
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3014modules-public-private-nominal atlib.tpz:3:27
Source evidence
- privatePublicSurfaceTypeBinding, validatePublicTypeTree, validateExportSignature at
af88afbc1d99· 47-160 - checkFunctionDeclarationInner at
271329b482bc· 249-357 - checkBindingStatement at
271329b482bc· 422-505 - parseTypedPattern at
271329b482bc· 509-527 - formNamedType at
271329b482bc· 563-606 - runCheckerPhases, checkerResult at
271329b482bc· 144-199 - pull/41 at
271329b482bc
An empty namespace still has no selectable member
Linkimport setup { missing }
No stdout.
let value: int = 1
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3009selected-name-not-exported atmain.tpz:1:16
Source evidence
- validateImportSurfaces at
271329b482bc· 174-192 - pull/41 at
271329b482bc
An import cycle is rejected before initialization
Linkimport firstimport std.ioio.writeLine("entry")
No stdout.
import secondimport std.ioexport let one: int = {io.writeLine("first")1}
import firstimport std.ioexport let two: int = {io.writeLine("second")2}
Expected result
Source evidence
- diagnoseCycles at
271329b482bc· 465-525 - pull/41 at
271329b482bc
An entry initializer cannot read a later binding
Linkexport let first = secondlet second = 1
No stdout.
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3018module-initializer-not-ready atmain.tpz:1:20
Source evidence
- validateImportedInitializers at
271329b482bc· 784-827 - initObserveReference at
271329b482bc· 360-389 - pull/41 at
271329b482bc - reportInitializationViolation/checkTopLevelInitializationOrder at
271329b482bc· 554-595
The same early read is rejected in an imported file
Linkimport lib
No stdout.
export let first = secondlet second = 1
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3018module-initializer-not-ready atlib.tpz:1:20
Source evidence
- validateImportedInitializers at
271329b482bc· 784-827 - initObserveReference at
271329b482bc· 360-389 - pull/41 at
271329b482bc
A fault preserves earlier output and stops remaining initialization
Linkimport aimport bimport cimport std.ioio.writeLine("entry")
a b-before
import std.ioexport let value: int = {io.writeLine("a")1}
import std.iofunction readAt(index: int) -> int {let values = [10]values[index]}export let value: int = {io.writeLine("b-before")readAt(1)}export let after: int = {io.writeLine("b-after")1}
import std.ioexport let value: int = {io.writeLine("c")1}
Expected result
Expected result
Rejection during run. Nonzero exit.
TPZ4001diagnostic-tpz4001 atb.tpz:4:5
ab-before
Source evidence
- emitProgramRust at
271329b482bc· 580-599 - dependencyOrder/moduleDependencyCatalog at
271329b482bc· 308-394 - pull/41 at
271329b482bc
Reject a namespace alias repeating its default name
Linkimport lib as liblet result: int = lib.value
No stdout.
export let value: int = 1
Expected result
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
- parseImportSpec/parseImportAlias/parseImport at
271329b482bc· 1039-1184 - importBindings at
271329b482bc· 148-213 - TPZ2009 rejected_module_form at
271329b482bc· 292-300 - pull/41 at
271329b482bc
Reject a selected alias repeating its source name
Linkimport lib { value as value }let result: int = value
No stdout.
export let value: int = 1
Expected result
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
- parseImportSpec/parseImportAlias/parseImport at
271329b482bc· 1039-1184 - importBindings at
271329b482bc· 148-213 - TPZ2009 rejected_module_form at
271329b482bc· 292-300 - pull/41 at
271329b482bc
Use plain let when a pattern publishes no binding
Linkexport let _ = 1
No stdout.
Expected result
Source evidence
- parseExport at
72a59a31125f· 1206-1224 - collectPatternBindings and letBindings at
72a59a31125f· 87-135;263-294 - emitPatternLet and installPattern at
72a59a31125f· 2242-2273 - publish exports after module initialization at
72a59a31125f· 580-596 - pull/44 at
72a59a31125f
Export preserves the ordinary refutable-let rejection
Linklet maybe: Option<int> = None()export let Some(value) = maybe
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5026diagnostics-refutable-let-pattern atmain.tpz:2:12
Source evidence
- parseExport at
72a59a31125f· 1206-1224 - collectPatternBindings and letBindings at
72a59a31125f· 87-135;263-294 - emitPatternLet and installPattern at
72a59a31125f· 2242-2273 - publish exports after module initialization at
72a59a31125f· 580-596 - pull/44 at
72a59a31125f
Each bound name must have a public resolved type
Linkimport liblet observed = lib.count
No stdout.
record Hidden { value: int }export let { item: item, count: count } = { item: Hidden { value: 1 }, count: 2 }
Expected result
Expected result
Rejection during resolve. Nonzero exit.
TPZ3014modules-public-private-nominal atlib.tpz:2:20
Source evidence
- parseExport at
72a59a31125f· 1206-1224 - collectPatternBindings and letBindings at
72a59a31125f· 87-135;263-294 - emitPatternLet and installPattern at
72a59a31125f· 2242-2273 - publish exports after module initialization at
72a59a31125f· 580-596 - pull/44 at
72a59a31125f
An imported array has an immutable root
Linkimport helpers { items }items[0] = 9
No stdout.
export let items = [1, 2]
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5003bindings-assignment-to-immutable atmain.tpz:2:1
Source evidence
- issues/31 at
1cbf38d3d422 - assignmentRoot; checkAssignmentRootMutable at
af88afbc1d99· 2178-2220
Pending contracts
LinkRelated contracts
LinkFunctions 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.
Assignment to imported binding
Private type in exported surface