Narrow the two bare import Mathlib to the modules actually used - #40
Merged
Conversation
Every Lean module's `initialize_<Module>` function calls the initializer of each module it imports. That call is a genuine symbol reference, so the linker cannot discard it: a single bare `import Mathlib` anywhere in a downstream executable's import closure keeps *all* ~8,200 Mathlib object files alive at link time, even though almost none of their code is reachable. A solc statically linked against the Yul compiler's C API was 340 MB, of which 62 MB was Mathlib pulled in this way. This library had two bare imports, and `YulSemantics.Dialect.EVM` is in the import closure of the downstream `yulc` executable, so it alone accounted for the whole 8,200-module drag. * `YulSemantics/Dialect/EVM.lean` — after the EVMOp/EVMExec split this file is metatheory only, and the single Mathlib entry point it needs is the `split_ifs` tactic (`Mathlib.Tactic.SplitIfs`). The `set_option linter.unnecessarySeqFocus false in` on `effects_sound_withExternal` is no longer needed either. * `YulSemantics/Basic.lean` — `bv_decide` is a Std tactic (`Std.Tactic.BVDecide`); nothing here needed Mathlib at all. Fixing the cascade in the modules that were getting Mathlib transitively through `Dialect.EVM`: * `Adequacy.lean` — `Mathlib.Data.Nat.Basic` (`le_rfl` at `Nat`'s `LinearOrder`). * `FibExample.lean` — `Mathlib.Data.Nat.Fib.Basic` (`Nat.fib`). * `Observation.lean`, `ObjectRun.lean`, `Examples.lean`, `Rewrites.lean` — explicit `(D := evm)` on four `Step.block` terms and one `EquivArgs.of_forall₂`. `Step`/`EquivArgs` take `[DecidableEq D.Value]`, and these proof terms are elaborated before the expected type fixes `D`. With Mathlib present, `DecidableEq (Dialect.Value ?D)` was *inconclusive* rather than failing — Mathlib's order hierarchy offers `LinearOrder.toDecidableEq` and a long chain below it, which leaves the search stuck on metavariables — so Lean postponed it until `?D` was known. Without Mathlib there are no candidate instances at all, so it is a hard failure. Naming the dialect makes elaboration independent of which instances happen to be in scope. No tactic block, definition or proof term changed. The only statement change is in an `EVM.lean` test fixture: `EvmState.selfdestructs : List (U256 × Bool)`, so the expected `[0x10]` was elaborating through Mathlib's boolean-ring `NatCast Bool` to `[(16, false)]`. That is now written `[(0x10, false)]` directly — verified equal to the old elaboration before the import was removed. `lake build` goes from 8,578 jobs to 884; `lake lint` still passes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
leonardoalt
pushed a commit
to powdr-labs/yul-compiler
that referenced
this pull request
Jul 29, 2026
powdr-labs/yul-semantics#40 is merged. Move the pin off the unmerged branch commit and onto 4c6f9753 on that repository's main. The two commits have the identical tree (6f559621), so this changes the recorded SHA and nothing else; the build and corpus results measured against the branch commit carry over unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
leonardoalt
pushed a commit
to powdr-labs/solidity
that referenced
this pull request
Jul 30, 2026
0.0.1 predated the Mathlib work in yul-compiler. Mathlib was being linked into the library because every Lean module's initializer references the initializer of each module it imports, so a single bare `import Mathlib` in the runtime closure pulled all of compiled Mathlib in. Narrowing those imports (powdr-labs/yul-compiler#137, argotorg#138 and powdr-labs/yul-semantics#40) took the link closure from 8,724 objects to 1,112. Measured on this branch, rebuilding solc against each release: 0.0.1 0.0.2 delta solc 355,502,216 219,069,328 -136.4 MB solc, stripped 236,446,528 151,078,184 -85.4 MB .text 185,199,409 121,448,177 -63.8 MB defined symbols 1,001,102 570,826 -430k Both binaries compile the block- and object-rooted test inputs to byte-identical bytecode. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Jul 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
YulSemantics/Dialect/EVM.leanandYulSemantics/Basic.leaneach had a bareimport Mathlib. Every Lean module'sinitialize_<Module>calls the initializer of each module it imports, and that is a real symbol reference the linker cannot discard, so one bareimport Mathlibanywhere in a downstream executable's import closure keeps all ~8,200 Mathlib object files alive at link time.Dialect.EVMis in the import closure of theyulcexecutable inpowdr-labs/yul-compiler, so it alone accounted for the entire drag. Measured there with this change plus the companion downstream PR (ordinary runnable link, no--unresolved-symbolsgames):yulc.rspThis library's own
lake buildgraph drops from 8,578 jobs to 884.Changes
Dialect/EVM.lean:import Mathlib->import Mathlib.Tactic.SplitIfs, the only Mathlib entry point the metatheory needs after the earlier EVMOp/EVMExec split. Theset_option linter.unnecessarySeqFocus false inoneffects_sound_withExternalis no longer needed and is dropped.Basic.lean:import Mathlib->import Std.Tactic.BVDecide.bv_decideis a Std tactic; nothing in the file needed Mathlib.Dialect.EVM:Adequacy.lean:Mathlib.Data.Nat.Basic(le_rflatNat'sLinearOrder).FibExample.lean:Mathlib.Data.Nat.Fib.Basic(Nat.fib).Observation.lean,ObjectRun.lean,Examples.lean,Rewrites.lean: explicit(D := evm)on fourStep.blockterms and oneEquivArgs.of_forall₂.Why the
(D := evm)annotations are neededStepandEquivArgstake[DecidableEq D.Value], and these proof terms are elaborated before the expected type fixesD. With Mathlib in scope,DecidableEq (Dialect.Value ?D)was inconclusive rather than failing:LinearOrder.toDecidableEqand the long chain below it leave the search stuck on metavariables, so Lean postponed it until?Dwas known. Without Mathlib there are no candidate instances at all, so it is a hard failure. Naming the dialect makes elaboration independent of which instances happen to be in scope. The proof terms themselves are unchanged.One statement change, called out explicitly
EvmState.selfdestructs : List (U256 × Bool), so in thefinishSelfdestructtest fixture inEVM.leanthe expected[0x10]was elaborating through Mathlib's boolean-ringNatCast Boolinto[(16, false)]. It is now written[(0x10, false)]directly. This was verified equal to the old elaboration (([0x10] : List (U256 × Bool)) = [(16, false)]closes bydecide) before the import was removed. No tactic block, definition or proof term changed anywhere in this PR.Testing
lake build: passes (8,578 jobs -> 884).lake lint(thebatteries/runLinterdriver CI uses): passes.powdr-labs/yul-compilerin the companion draft PR Point yul-semantics at the Mathlib-narrowed rev; 29 MB off yulc yul-compiler#138, with this exact commit as the pinnedrev: fulllake build,lake build yulc, the axiom check (Checks.lean), the spec-closure check (SpecClosure.lean), the YulIR round-trip, and the four Solidity corpora (syntax / interpreter / optimizer / object-compiler / EVM-code-transform) all pass, with no change in pass or known-failure counts.Notes
Downstream consumers that were getting Mathlib lemmas and tactics transitively through
YulSemantics.Dialect.EVMwill need to add narrow imports of their own; powdr-labs/yul-compiler#138 is the worked example.🤖 Generated with Claude Code