Module Artifact And Typechecker Integration
Order
Recommended Issue order: 1. Module-system-local order: 1.
Goal
Introduce the shared module artifact model and make the type checker consume imports through that model. This is the root dependency for later native modules, bytecode modules, stdlib modularization, and cross-module trait impl visibility.
Dependencies
Prerequisites:
- Current parser, typechecker, STUPID, and ORGASM module behavior.
Unblocks:
- Native Module Artifacts
- Bytecode Module Loading
- Standard Library Modularization
- Auto Traits And Derive Traits, for cross-module impl coherence.
Scope
In scope:
ModuleIdwith canonical dotted names.ModuleArtifactas the shared contract between parser, typechecker, STUPID, ORGASM, and later loaders.ModuleResolverand load options for source modules.NG_MODULE_PATHparsing and resolution priority.- Import/export metadata for values, functions, types, type aliases, traits, const predicates, and impl evidence.
- Typechecker import integration through
ModuleRegistry. - Duplicate visible impl diagnostics.
Out of scope:
- Native descriptors.
.ngobinary format.- Stdlib physical reorganization.
- Runtime bytecode import loading.
Core Model
enum class ModuleFormat {
SourceNg,
BytecodeNgo,
Native,
};
struct ModuleId {
Str canonicalName; // e.g. "std.prelude"
Vec<Str> pathSegments; // e.g. ["std", "prelude"]
};
struct ModuleArtifact {
ModuleId id;
ModuleFormat format;
Str originPath;
Str version;
ASTRef<CompileUnit> ast;
TypeIndex typeIndex;
BytecodeModule bytecode;
RuntimeRef<StorageCell> runtimeModule;
ModuleExportIndex exports;
ModuleImportIndex imports;
ModuleTraitIndex traits;
ModuleImplIndex impls;
};The artifact is the contract between stages:
- Parser produces AST for
.ng. - Type checker consumes artifact exports and publishes type/trait/impl metadata.
- ORGASM compiler consumes artifact metadata and may publish bytecode later.
- STUPID consumes runtime module metadata.
Module Identity
Module names are canonical dotted names:
module std.prelude exports *;
import std.prelude (*);Rules:
- The canonical module ID is the dotted import path.
- File path is only a resolution mechanism, not identity.
module foo.bar;inside a file must match import pathfoo.barwhen imported by name.- A source file without a
moduledeclaration gets the canonical ID from its import path or CLI entrypoint. - Module identity must stay stable across source, bytecode, and native modules.
Search Path Resolution
Module resolution uses ordered roots:
- Explicit compiler/interpreter module paths.
NG_MODULE_PATH, split by platform path separator.- Current entry file directory.
- Project
lib/. - Installed standard library roots.
- Registered native module table, after Native Module Artifacts.
For import a.b.c, each filesystem root is probed with:
a/b/c.nga/b/c/module.ng
Bytecode probes are added later by Bytecode Module Loading.
Import Syntax
Keep the existing syntax:
import std.prelude (*);
import std.string (join, split);
import vendor.math as math;
import vendor.math;Normalize grammar:
ImportDecl := ExportPrefix? "import" ModulePath ImportAlias? ImportList? ";"
ExportPrefix := "export"
ImportAlias := "as" Ident
ImportList := "(" ("*" | ImportItem ("," ImportItem)*) ")"
ImportItem := IdentCompatibility rule:
- Existing
import a.b alias (...);remains accepted initially. - New examples and docs should use
as. export import m (*)explicitly re-exports imported symbols. It is the standard facade pattern for modules such asstd.prelude.import m;is a module-only import. The module value is available under the tail name (m) or explicit alias and members are accessed asm.symbol(...).- Symbol-level import aliases are deferred to Symbol Import Aliases.
Import Provenance And Conflicts
Every imported short name carries the canonical source module ID it came from. If a module re-exports an imported symbol, the original source module ID is preserved instead of being rewritten to the facade module.
Rules:
- Re-importing the same short name from the same canonical source module is idempotent.
- Importing the same short name from different canonical source modules is an error.
- If both modules are needed, keep at least one import module-qualified:
import first.module as first; import second.module as second;. use impl Trait for Typeresolves module qualifiers through the same canonical module alias table, souse impl first.Show for Fooremains unambiguous even when another module exports a differentShowimpl.- Short-name aliasing for individual imported symbols is deferred to Symbol Import Aliases.
Export Model
A module exports:
- Values.
- Functions.
- Types and type aliases.
- Traits.
- Trait impl evidence.
- Const predicates.
Export forms:
module m exports *;
export fun f() -> unit { ... }
export type T { ... }
export trait Show { ... }
export impl Show for T { ... }
export import std.string (*);Rules:
exports *exports local public definitions only.- Re-export requires explicit export of imported symbols.
- Imported symbols are not re-exported by
exports *. export importis the explicit re-export form for imported symbols.- Impl evidence is not callable by name, but it participates in trait satisfaction and coherence.
export implis the preferred explicit form for impl evidence.
Trait Impl Visibility
Visible impls come from:
- Local module impls.
- Imported modules' exported impl evidence.
Native module impl evidence is added later.
Rules:
- Duplicate visible exact impl
(Trait, Type)is an error. - Overlapping visible generic/concrete impls are an error unless selected by a later explicit selection feature.
- Diagnostics must include trait name, target type, and candidate module IDs.
Acceptance Criteria
NG_MODULE_PATHaffects source module lookup.import std.prelude (*)resolves throughModuleRegistry.- Source modules expose exported functions, types, traits, and impl evidence to importers.
- Imported impl evidence participates in trait satisfaction.
- Duplicate visible impls from different modules fail deterministically.
- STUPID and ORGASM agree on import/export visibility for source modules.
Implementation Status
Implemented in this phase:
ModuleId,ModuleFormat,ModuleArtifact, export/import/trait/impl indexes, and canonical module-id helpers.- Source module loading through ordered roots, including explicit module paths,
NG_MODULE_PATH, current directory, and stdlib root. - Source probes for both
a/b/c.nganda/b/c/module.ng. - Explicit dotted module declarations, including
module std.prelude exports *;. import vendor.math as math;syntax while preserving the older alias form.export import ...parsing and STUPID runtime re-export support.- Runtime import provenance for de-duplicating same-source imports while rejecting conflicting same-name imports from different modules.
- ORGASM rejects conflicting same-name short imports and supports module-qualified calls for source/bytecode module imports.
- Typechecker publication of exported type metadata, traits, and exported impl evidence into
ModuleRegistry. - Typechecker import consumption through published
ModuleArtifactmetadata, including duplicate visible impl diagnostics with candidate module IDs. - STUPID and ORGASM reuse of registry module entries only when the stage-specific payload exists, avoiding empty runtime/bytecode artifacts.
- ORGASM import tables now store canonical module IDs, and
exports *publishes module functions for bytecode imports.
Still intentionally deferred to later module-system issues:
- Native module descriptors and native artifact publication.
.ngobytecode serialization/deserialization and bytecode-first probing.- Physical stdlib modularization beyond the canonical
std.preludedeclaration. - Symbol-level import aliases, tracked separately in Symbol Import Aliases.
- Full ORGASM bytecode metadata for re-exported imported native/source symbols.