Skip to content

feat(compiler): Run frontend passes on library packages#29342

Open
mitchmindtree wants to merge 4 commits intomasterfrom
mitchmindtree/lib-frontend-passes
Open

feat(compiler): Run frontend passes on library packages#29342
mitchmindtree wants to merge 4 commits intomasterfrom
mitchmindtree/lib-frontend-passes

Conversation

@mitchmindtree
Copy link
Copy Markdown
Collaborator

@mitchmindtree mitchmindtree commented Apr 16, 2026

Summary

Run all nine frontend passes (name validation through static analysis) on library packages when they are the primary compilation target. Previously, libraries were parse-only - type errors, undefined names, and interface cycles only surfaced when a downstream program consumed the library.

  • Wire each frontend pass's do_pass to handle Ast::Library via its real visitor/reconstructor instead of a no-op.
  • Add Library.stubs: IndexMap<Symbol, Stub> so imported programs/libraries flow through frontend passes; thread the field through all pass impls.
  • Add Compiler::build_library / build_library_from_directory - parse, resolve import stubs, run frontend passes (no codegen).
  • CLI routes the primary library through build_library; non-primary library deps remain parse-only.
  • Fix missing visit_interface call in TypeChecking::visit_library.

Testing

  • 5 new CLI integration tests: type error, undefined name, interface cycle, valid interface, cross-library dep
  • 1 new compiler unit test: build_library_from_directory_in_memory_rejects_type_error
  • Updated test_library expectations for new "Building library" / "Validated" output

Closes #29211

Follow-up

The `test_network_retries_flag` COMMANDS script escaped hyphens in a
grep pattern (`\-\-network-retries`). Newer grep versions emit "stray \
before -" warnings to stderr, causing the test to fail against its
empty-stderr expectation. Switch to `grep -qF -- '--network-retries'`
for a literal match.
Previously, each frontend pass's library branch was a no-op: library
sources were parsed but not semantically validated, so type errors,
name collisions, and interface cycles only surfaced once a downstream
program consumed the library.

Wire each of the nine frontend passes - NameValidation,
GlobalVarsCollection, PathResolution, GlobalItemsCollection,
CheckInterfaces, TypeChecking, Disambiguate, ProcessingAsync, and
StaticAnalyzing - to invoke its real visitor or reconstructor on
libraries. Replace the `ast.visit` / `ast.map` closure pairs with
direct `match` expressions on the `Ast` enum so both branches can
mutably borrow the visitor.

Close gaps uncovered by enabling the passes:
- `TypeChecking::visit_library` now visits interfaces, matching
  `visit_program_scope`.
- Bespoke `visit_library` implementations in global_vars_collection,
  global_items_collection, check_interfaces, type_checking, and
  static_analysis now walk library stubs.

Add `Library.stubs: IndexMap<Symbol, Stub>` paralleling
`Program.stubs` so imported programs/libraries flow through the
frontend passes. Update the parser constructor, `Display` impl,
default `visit_library` / `reconstruct_library`, and every bespoke
`reconstruct_library` / `consume_library` to thread the new field.
When a library package (`src/lib.leo`) is the primary compilation target,
run the full frontend pipeline (name validation through static analysis)
instead of parse-only. Non-primary library dependencies keep the existing
parse-only path; their semantics are validated when their own package is
built.

- compiler: add `Compiler::build_library` (plus `*_from_directory` helpers)
  that parses, resolves import stubs, and runs `frontend_passes`. Extend
  `add_import_stubs` to populate `Library.stubs`: libraries have no
  explicit `imports` field, so deps are discovered via stubs whose parent
  set contains this library's name.
- cli: route the primary library through `build_library_from_directory`
  when `package.compilation_units.last().name == unit.name`. The validated
  library is still turned into a `Stub::FromLibrary` so downstream tests
  in the same package can reference it.
- tests: update `test_library` expectations to include the new
  "Building library" / "Validated" status lines.
Add CLI integration fixtures exercising the frontend passes that now run
on library primaries:

- test_library_build_type_error: `u32 + bool` rejected by type checking
- test_library_build_undefined_name: unresolved `missing_fn()` call
- test_library_build_interface_cycle: cyclic `interface A: B` / `B: A`
- test_library_build_valid_interface: well-formed interface accepted
- test_library_build_with_dep_lib: cross-library reference via stubs

Add a compiler unit test asserting `build_library_from_directory` surfaces
a type-checking error (`ETYC`) via the error handler. Fix an edge case
where `parse_library` did not seed `Compiler::program_name`, which
`add_import_stubs` relies on when identifying library deps by parent; the
method now adopts the supplied `library_name` when no name was pre-set.
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.

[Feature] Run frontend passes on library packages

1 participant