Skip to content

Narrow the two bare import Mathlib to the modules actually used - #40

Merged
leonardoalt merged 1 commit into
mainfrom
narrow-mathlib-imports
Jul 29, 2026
Merged

Narrow the two bare import Mathlib to the modules actually used#40
leonardoalt merged 1 commit into
mainfrom
narrow-mathlib-imports

Conversation

@leonardoalt

@leonardoalt leonardoalt commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary

YulSemantics/Dialect/EVM.lean and YulSemantics/Basic.lean each had a bare import Mathlib. Every Lean module's initialize_<Module> calls the initializer of each module it imports, and that is a real symbol reference the linker cannot discard, so one bare import Mathlib anywhere in a downstream executable's import closure keeps all ~8,200 Mathlib object files alive at link time.

Dialect.EVM is in the import closure of the yulc executable in powdr-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-symbols games):

bytes objects in yulc.rsp
before 165,277,392 8,724
after 134,841,520 1,112
delta -30,435,872 (-29.0 MiB, -18.4%) -7,612

This library's own lake build graph 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. The set_option linter.unnecessarySeqFocus false in on effects_sound_withExternal is no longer needed and is dropped.
  • Basic.lean: import Mathlib -> import Std.Tactic.BVDecide. bv_decide is a Std tactic; nothing in the file needed Mathlib.
  • 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₂.

Why the (D := evm) annotations are needed

Step and EquivArgs take [DecidableEq D.Value], and these proof terms are elaborated before the expected type fixes D. With Mathlib in scope, DecidableEq (Dialect.Value ?D) was inconclusive rather than failing: LinearOrder.toDecidableEq and the long chain below it leave 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. The proof terms themselves are unchanged.

One statement change, called out explicitly

EvmState.selfdestructs : List (U256 × Bool), so in the finishSelfdestruct test fixture in EVM.lean the expected [0x10] was elaborating through Mathlib's boolean-ring NatCast Bool into [(16, false)]. It is now written [(0x10, false)] directly. This was verified equal to the old elaboration (([0x10] : List (U256 × Bool)) = [(16, false)] closes by decide) 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 (the batteries/runLinter driver CI uses): passes.
  • Integrated against powdr-labs/yul-compiler in 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 pinned rev: full lake 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.EVM will need to add narrow imports of their own; powdr-labs/yul-compiler#138 is the worked example.

🤖 Generated with Claude Code

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
leonardoalt merged commit 4c6f975 into main Jul 29, 2026
1 check passed
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>
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.

1 participant