This PR adjusts the results of `inferInstanceAs` and the `def` `deriving` handler to conform to recently strengthened restrictions on reducibility. This change ensures that when deriving or inferring an instance for a semireducible type definition, the definition's RHS is not leaked when the instance is reduced at lower than semireducible transparency.
More specifically, given the "source type" and "target type" (the given and expected type for `inferInstanceAs`, the right-hand side and applied left-hand side of the `def` for `deriving`), we synthesize an instance for the source type and then unfold and rewrap its components (fields, nested instances) as necessary to make them compatible with the target type. The individual steps are represented by the following options, which all default to enabled and can be disabled to help with porting:
- `backward.inferInstanceAs.wrap`: master switch for instance adjustment in both `inferInstanceAs` and the default `deriving` handler
- `backward.inferInstanceAs.wrap.reuseSubInstances`: reuse existing instances for the target type for sub-instance fields to avoid non-defeq instance diamonds
- `backward.inferInstanceAs.wrap.instances`: wrap non-reducible instances in auxiliary definitions
- `backward.inferInstanceAs.wrap.data`: wrap data fields in auxiliary definitions (proof fields are always wrapped)
This PR is an extension and rewrite of prior work in Mathlib: https://github.com/leanprover-community/mathlib4/pull/36420
Last(?) part of fix for #9077🤖 Prepared with Claude Code
# Breaking changes
Proofs that relied on the prior "defeq abuse" of these instance or that depended on their specific structure may need adjustments. As `inferInstanceAs A` now needs to know the source and target types exactly before it can continue, it cannot be used anymore as a synonym for `(inferInstance : A)`, use the latter instead when source and target type are identical.
This PR increases Lean's default stack size, including for the main
thread of Lean executables, to 1GB.
As stack pages are allocated dynamically, this should not change the
memory usage of programs but can prevent them from stack overflowing.
The stack size (of any Lean thread) can now be customized via the
`LEAN_STACK_SIZE_KB` environment variable. `main` can be prevented from
running on a new thread by setting `LEAN_MAIN_USE_THREAD=0`, in which
case the default OS stack size management applies to the main thread
again.
This PR enables support for respecting user provided borrow annotations.
This allows user to mark arguments of their definitions or local
functions with `(x : @&Ty)` and have the borrow inference try its best
to preserve this annotation, thus potentially reducing RC pressure. Note
that in some cases this might not be possible. For example, the compiler
prioritizes preserving tail calls over preserving borrow annotations. A
precise reasoning of why the compiler chose to make its inference
decisions can be obtained with `trace.Compiler.inferBorrow`.
The implementation consists of two parts:
1. A propagator in ToLCNF. This is required because the elaborator does
not place the borrow annotations in the function binders themselves but
just in type annotations of let binders/global declarations while LCNF
expects them in the lambda variable binders themselves. Thus ToLCNF now
implements a (very weak but strong enough for this purpose) propagator
of the borrow annotations of a type annotation into the variable binders
of the term affected by the annotations
2. A weakening of the InferBorrow heuristic. It now has a set of
"forced" and "non-forced" reasons to mark a variable as owned instead of
borrowed. If a variable is user annotated as borrowed, it will only be
marked as owned if the reason is a forced one, e.g. preservation of tail
calls.
The ultimate goal of this work is to turn production of `.ir` files into
separate build step so that it does not block non-`meta` imports and can
be skipped entirely when not needed. This PR implements the main logic
of this new `leanir` compiler executable and runs it after `lean` inside
the same Lake build step but leaves its use disabled behind a
`compiler.postponeCompile` flag until further Lake adjustments move it
to a separate facet so that its use can be actually beneficial.
---------
Co-authored-by: Joscha <joscha@plugh.de>
This PR ensures that when a function is marked `export` its borrow
annotations (if present) are always ignored.
This was the previous behavior in the C++ version of this file but
slightly modified when porting to the old IR and thus subsequently
ported to LCNF wrongly as well.
This PR adds support for ignoring user defined borrow annotations. This
can be useful when defining
`extern`/`export` pairs as the `extern` might be infected by borrow
annotations while in `export`
they are already ignored.
This PR ports the C emission pass from IR to LCNF, marking the last step
of the IR/LCNF conversion and thus enabling end-to-end code generation
through the new compilation infrastructure.
This PR optimizes the handling of `match_same_ctor.het` to make it emit
nice match trees as opposed to unoptimized CPS style code.
`match_same_ctor.het` is essentially a specialized kind of matcher where
we know that two objects are built from the same constructor and we wish
to call a continuation on their data. This means for every constructor
that contains data `het` takes one closure as an argument. Then after
matching on one of the objects every closure but the one relevant for
the match is released in every match arm, causing quadratic code
generation. This PR ensures that the `het` declarations get inlined and
then further processed by ordinary matcher and casesOn compilation,
thereby removing all of the continuations from the compiled code.
This PR makes the compiler removes arguments to join points that are
void, avoiding a bunch of dead
stores in the bytecode and the initial C (though LLVM was surely able to
optimize these away further
down the line already).
This PR replaces the `isImplicitReducible` check with `Meta.isInstance`
in the `shouldInline` function within `inlineCandidate?`.
At the base phase, we skip inlining instances tagged with
`[inline]`/`[always_inline]`/`[inline_if_reduce]` because their local
functions will be lambda lifted during the base phase. The goal is to
keep instance code compact so the lambda lifter can extract
cheap-to-inline declarations. Inlining instances prematurely expands the
code and creates extra work for the lambda lifter — producing many
additional lambda-lifted closures.
The previous check used `isImplicitReducible`, which does not capture
the original intent: some `instanceReducible` declarations are not
instances. `Meta.isInstance` correctly targets only actual type class
instances. Although `Meta.isInstance` depends on the scoped extension
state, this is safe because `shouldInline` runs during LCNF compilation
at `addDecl` time — any instance referenced in the code was resolved
during elaboration when the scope was active, and LCNF compilation
occurs before the scope changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This PR ensures the compiler extracts `Array`/`ByteArray`/`FloatArray`
literals as one big closed term to avoid quadratic overhead at closed
term initialization time.
This PR ports the simple ground expression extraction pass from IR to
LCNF.
I locally confirmed that this produces no diff between stage1/stage2 at
the C level (apart from the
changed compiler files) so this should essentially be binary equivalent.
This PR ports the expand reset/reuse pass from IR to LCNF. In addition
it prevents exponential code generation unlike the old one. This results
in a ~15% decrease in binary size and slight speedups across the board.
The change also removes the "is this reset actually used" syntactic
approximation as the previous passes guarantee (at the moment) that all
uses are in the continuation and will thus be caught by this.
This PR reverts commit 9b7a8eb7c8. After
some more contemplation on
the implications of these changes I think this is not the direction we
want to move into.
This PR avoids false-positive error messages on specialization
restrictions under the module system when the declaration is explicitly
marked as not specializable. It could also provide some minor public
size and rebuild savings.
This PR ports the toposorting pass from IR to LCNF.
We can already do this now as the remaining IR pipeline does not insert
any new auxiliary
declarations into the SCC so now is as good a time as ever to do it.
This PR removes the type correction heuristic from the RC pass as it is
already present in the
boxing pass. Previously the boxing pass did not try to correct types so
the RC pass did. We
discovered issues with not doing this in the boxing pass and
accidentally maintained two corrections
for a while. This PR merges both and removes the one from RC.
This PR makes the derived value analysis in RC insertion recognize
`Array.uget` as another kind of
"projection-like" operation. This allows it to reduce reference count
pressure on elements accessed
through uget.
This PR ports the RC insertion from IR to LCNF.
In doing so it makes the entire code monadic as opposed to simulating a
ReaderT StateRefT stack manually.
This PR renames `instance_reducible` to `implicit_reducible` and adds a
new
`backward.isDefEq.implicitBump` option to prepare for treating all
implicit
arguments uniformly during definitional equality checking.
## Changes
**Rename `instance_reducible` → `implicit_reducible`:**
- Rename `ReducibilityStatus.instanceReducible` constructor to
`implicitReducible`
- Register new `[implicit_reducible]` attribute, keep
`[instance_reducible]` as alias
- Rename `isInstanceReducible` → `isImplicitReducible` (with deprecated
aliases)
- Update all references across src/ and tests/
The rename reflects that this reducibility level is used not just for
instances
but for any definition that needs unfolding during implicit argument
resolution
(e.g., `Nat.add`, `Array.size`).
**Add `backward.isDefEq.implicitBump` option:**
- When `true` (+ `respectTransparency`), bumps transparency to
`.instances` for
ALL implicit arguments in `isDefEqArgs`, not just instance-implicit ones
- Defaults to `false` for staging compatibility — will be flipped to
`true` after
stage0 update
- Adds `// update me!` to `stage0/src/stdlib_flags.h` to trigger CI
stage0 update
## Follow-up (after stage0 update)
- Flip `backward.isDefEq.implicitBump` default to `true`
- Fix resulting test/module failures
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This is a mitigation for the fact that the upfront noncomputable checker
currently doesn't error out early enough in certain situations so we
violate invariants later on.
This PR adds a simplification rule for `Task.get (Task.pure x) = x` into
the LCNF simplifier. This
ensures that we avoid touching the runtime for a `Task` that instantly
gets destructed anyways.
This PR uses `getImpureSignature?` instead of the `findEnvDecl` from IR
in the LCNF compiler. We
were previously still relying on the IR function because only IR
contained proper borrow
annotations. Now we infer the borrow annotations on the LCNF level and
can thus use the LCNF
signatures.