Skip to content

An imported module's top-level statements run from a global constructor (#447) - #500

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix-import-source-toplevel
Oct 4, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
fix-import-source-toplevel

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

A module with a top-level statement (print("module init") beside its exports) failed to compile when another module imported it as source, under every memory model:

Global is referenced by parentless instruction!
ptr @puts

The importer reads such a module in one of two ways:

  • as declarations: its own object file holds the bodies;
  • with its bodies: under the JIT without its cache.

Either way, processStatements generated the module's code statements at the importer's module level, outside any function.

The fix has two parts:

  • The importer: an imported module's code statements are no longer generated at the importer's level (the new skipCode flag on processStatements). Read as declarations, they belong to the module's own object. Included with its bodies, they run from a global constructor of their own (generateModuleInitCode), after the module's variables are initialized.
  • The imported module's own compile: a root that is not the program's entry point runs its top level from a global constructor too. That covers no --entry-point under --emit=obj, a module the JIT cache compiles for an import, and a DLL. Previously generateGlobalEntryCode gave such a root its own main, which was a second main once linked beside the program. The JIT cache already compiled imported modules expecting exactly this ("its top level run from its global constructors").

New tests import-source/import_toplevel.ts + toplevel_module.ts check that the module's statements run once, before main. They run four ways: compiled, -shared, JIT with -shared, and JIT with its cache. The JIT without its cache (--jit-cache=false, the generateModuleInitCode path) prints module init then done. under gc, rc, none and own.

Gate Result
Windows full suite (Release) 3830/3830
Linux (WSL) full suite 3815/3815
DefaultLib build + suite, release + debug, compile + JIT gc 159/159; rc, none 158/159 (weakref_basic is gc-only, as on main)
own corpus (compiled without --entry-point, so through the new path) no flips, no first-error changes (460/618)

Closes #447

🤖 Generated with Claude Code

…or (#447)

A module with a top-level statement (`print("module init")` beside its
exports), imported as source, failed to compile under every memory
model: "Global is referenced by parentless instruction". The importer
reads the module as declarations (its own object holds the bodies) or,
under the JIT without its cache, with its bodies; either way
processStatements generated the module's code statements at the
importer's module level, outside any function.

- An imported module's code statements are no longer generated at the
  importer's level (processStatements' new skipCode). Read as
  declarations, they are its own object's to run; included with its
  bodies, they run from a global constructor of their own
  (generateModuleInitCode), after the module's variables are
  initialized.
- A root that is not the program's entry point (no --entry-point under
  --emit=obj, a module the JIT cache compiles for an import, a DLL)
  runs its top level from a global constructor too, where
  generateGlobalEntryCode gave it a `main` of its own: linked beside
  the program, that was a second `main`.

import-source/import_toplevel.ts and toplevel_module.ts check that the
module's statements run once, before main: compiled, -shared, JIT with
-shared, and JIT with its cache; the JIT without its cache was checked
by hand under every model.

Closes #447

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 01d2136 into main Oct 4, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-import-source-toplevel branch October 4, 2026 23:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A module with a top-level statement, imported as source, fails with "Global is referenced by parentless instruction"

1 participant