Skip to content

Commit 2a7175c

Browse files
Khaclaude
andauthored
feat: remove deprecated in-kernel native reduction (#14953)
This PR removes `Lean.reduceBool`, `Lean.reduceNat`, `Lean.ofReduceBool`, `Lean.ofReduceNat` and `Lean.trustCompiler`, along with the kernel's support for reducing applications of the first two by running the compiler. They have been deprecated since 2026-02-01 in favour of asserting native evaluations with axioms, which is what `native_decide` and `bv_decide` already do through `Lean.Meta.nativeEqTrue`. Nothing in the toolchain used them any more. Removing the axioms makes `#print axioms`, and the upcoming `lake check`, mean what it says for the whole environment. `Lean.trustCompiler` was referenced unconditionally from the bodies of `reduceBool` and `reduceNat` so that it would be reported for anything reducing through them, which left it looking used in every environment that merely imported them. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent a57be66 commit 2a7175c

10 files changed

Lines changed: 6 additions & 214 deletions

File tree

src/Init/Core.lean

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,86 +2327,6 @@ instance : Subsingleton (Squash α) where
23272327
trivial
23282328

23292329
namespace Lean
2330-
/-! # Kernel reduction hints -/
2331-
2332-
/--
2333-
Depends on the correctness of the Lean compiler, interpreter, and all `[implemented_by ...]` and `[extern ...]` annotations.
2334-
-/
2335-
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
2336-
axiom trustCompiler : True
2337-
2338-
set_option linter.deprecated false in
2339-
/--
2340-
When the kernel tries to reduce a term `Lean.reduceBool c`, it will invoke the Lean interpreter to evaluate `c`.
2341-
The kernel will not use the interpreter if `c` is not a constant.
2342-
This feature is useful for performing proofs by reflection.
2343-
2344-
Remark: the Lean frontend allows terms of the from `Lean.reduceBool t` where `t` is a term not containing
2345-
free variables. The frontend automatically declares a fresh auxiliary constant `c` and replaces the term with
2346-
`Lean.reduceBool c`. The main motivation is that the code for `t` will be pre-compiled.
2347-
2348-
Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
2349-
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
2350-
external type checkers that do not implement this feature.
2351-
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
2352-
So, you are mainly losing the capability of type checking your development using external checkers.
2353-
2354-
Recall that the compiler trusts the correctness of all `[implemented_by ...]` and `[extern ...]` annotations.
2355-
If an extern function is executed, then the trusted code base will also include the implementation of the associated
2356-
foreign function.
2357-
-/
2358-
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
2359-
opaque reduceBool (b : Bool) : Bool :=
2360-
-- This ensures that `#print axioms` will track use of `reduceBool`.
2361-
have := trustCompiler
2362-
b
2363-
2364-
set_option linter.deprecated false in
2365-
/--
2366-
Similar to `Lean.reduceBool` for closed `Nat` terms.
2367-
2368-
Remark: we do not have plans for supporting a generic `reduceValue {α} (a : α) : α := a`.
2369-
The main issue is that it is non-trivial to convert an arbitrary runtime object back into a Lean expression.
2370-
We believe `Lean.reduceBool` enables most interesting applications (e.g., proof by reflection).
2371-
-/
2372-
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
2373-
opaque reduceNat (n : Nat) : Nat :=
2374-
-- This ensures that `#print axioms` will track use of `reduceNat`.
2375-
have := trustCompiler
2376-
n
2377-
2378-
2379-
set_option linter.deprecated false in
2380-
/--
2381-
The axiom `ofReduceBool` is used to perform proofs by reflection. See `reduceBool`.
2382-
2383-
This axiom is usually not used directly, because it has some syntactic restrictions.
2384-
Instead, the `native_decide` tactic can be used to prove any proposition whose
2385-
decidability instance can be evaluated to `true` using the lean compiler / interpreter.
2386-
2387-
Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
2388-
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
2389-
external type checkers that do not implement this feature.
2390-
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
2391-
So, you are mainly losing the capability of type checking your development using external checkers.
2392-
-/
2393-
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
2394-
axiom ofReduceBool (a b : Bool) (h : reduceBool a = b) : a = b
2395-
2396-
set_option linter.deprecated false in
2397-
/--
2398-
The axiom `ofReduceNat` is used to perform proofs by reflection. See `reduceBool`.
2399-
2400-
Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
2401-
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
2402-
external type checkers that do not implement this feature.
2403-
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
2404-
So, you are mainly losing the capability of type checking your development using external checkers.
2405-
-/
2406-
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
2407-
axiom ofReduceNat (a b : Nat) (h : reduceNat a = b) : a = b
2408-
2409-
24102330
/--
24112331
The term `opaqueId x` will not be reduced by the kernel.
24122332
-/

src/Lean/Environment.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,6 @@ private def asyncConsts (env : Environment) : AsyncConsts :=
640640
Constructs an elaboration environment from a given kernel environment's constants. All constants are
641641
accessible in both the private and public scope. All other data is empty.
642642
-/
643-
@[export lean_elab_environment_of_kernel_env]
644643
def ofKernelEnv (env : Kernel.Environment) : Environment :=
645644
{ base.private := env, base.public := env, importRealizationCtx? := none }
646645

src/Lean/Meta/ExprDefEq.lean

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -233,17 +233,6 @@ private def isDefEqEta (a b : Expr) : MetaM LBool := do
233233
else
234234
return .undef
235235

236-
/-- Support for `Lean.reduceBool` and `Lean.reduceNat` -/
237-
def isDefEqNative (s t : Expr) : MetaM LBool := do
238-
let isDefEq (s t) : MetaM LBool := toLBoolM <| Meta.isExprDefEqAux s t
239-
let s? ← reduceNative? s
240-
let t? ← reduceNative? t
241-
match s?, t? with
242-
| some s, some t => isDefEq s t
243-
| some s, none => isDefEq s t
244-
| none, some t => isDefEq s t
245-
| none, none => pure LBool.undef
246-
247236
/-- Support for reducing Nat basic operations. -/
248237
def isDefEqNat (s t : Expr) : MetaM LBool := do
249238
let isDefEq (s t) : MetaM LBool := toLBoolM <| Meta.isExprDefEqAux s t
@@ -2375,7 +2364,7 @@ private def isDefEqProjInst (t : Expr) (s : Expr) : MetaM LBool := do
23752364

23762365
/--
23772366
The special cases tried *after* the main `isExprDefEqExpensive` machinery has failed, as opposed
2378-
to the early ones (`isDefEqNative`, `isDefEqNat`, `isDefEqOffset`).
2367+
to the early ones (`isDefEqNat`, `isDefEqOffset`).
23792368
23802369
`.false` means one of them decided the terms are *not* definitionally equal, and must not be read
23812370
as "declined". `.undef` means they all declined — note that `isDefEqUnitLike` returning `false`
@@ -2427,7 +2416,6 @@ private def isExprDefEqExpensive (t : Expr) (s : Expr) : MetaM Bool := do
24272416
if t != t' || s != s' then
24282417
Meta.isExprDefEqAux t' s'
24292418
else
2430-
whenUndefDo (isDefEqNative t s) do
24312419
whenUndefDo (isDefEqNat t s) do
24322420
whenUndefDo (isDefEqOffset t s) do
24332421
whenUndefDo (isDefEqDelta t s) do

src/Lean/Meta/WHNF.lean

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -973,23 +973,6 @@ def reduceRecMatcher? (e : Expr) : MetaM (Option Expr) := do
973973
return none
974974
| _ => return none
975975

976-
unsafe def reduceBoolNativeUnsafe (constName : Name) : MetaM Bool := evalConstCheck Bool `Bool constName
977-
unsafe def reduceNatNativeUnsafe (constName : Name) : MetaM Nat := evalConstCheck Nat `Nat constName
978-
@[implemented_by reduceBoolNativeUnsafe] opaque reduceBoolNative (constName : Name) : MetaM Bool
979-
@[implemented_by reduceNatNativeUnsafe] opaque reduceNatNative (constName : Name) : MetaM Nat
980-
981-
def reduceNative? (e : Expr) : MetaM (Option Expr) :=
982-
match e with
983-
| Expr.app (Expr.const fName _) (Expr.const argName _) =>
984-
if fName == ``Lean.reduceBool then do
985-
return toExpr (← reduceBoolNative argName)
986-
else if fName == ``Lean.reduceNat then do
987-
return toExpr (← reduceNatNative argName)
988-
else
989-
return none
990-
| _ =>
991-
return none
992-
993976
@[inline] def withNatValue (a : Expr) (k : Nat → MetaM (Option α)) : MetaM (Option α) := do
994977
if !a.hasExprMVar && a.hasFVar then
995978
return none
@@ -1086,12 +1069,9 @@ partial def whnfImp (e : Expr) : MetaM Expr :=
10861069
match (← reduceNat? e') with
10871070
| some v => cache useCache e v
10881071
| none =>
1089-
match (← reduceNative? e') with
1090-
| some v => cache useCache e v
1091-
| none =>
1092-
match (← unfoldDefinition? e') with
1093-
| some e'' => cache useCache e (← whnfImp e'')
1094-
| none => cache useCache e e'
1072+
match (← unfoldDefinition? e') with
1073+
| some e'' => cache useCache e (← whnfImp e'')
1074+
| none => cache useCache e e'
10951075

10961076
/-- If `e` is a projection function that satisfies `p`, then reduce it -/
10971077
def reduceProjOf? (e : Expr) (p : Name → Bool) : MetaM (Option Expr) := do

src/Lean/Util/TestExtern.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ syntax (name := testExternCmd) "test_extern " term : command
3030
let env ← getEnv
3131
if isExtern env f || (getImplementedBy? env f).isSome then
3232
let t' := (← unfold t f).expr
33-
let r := mkApp (.const ``reduceBool []) (← mkDecide (← mkEq t t'))
33+
let r ← mkDecide (← mkEq t t')
3434
if ! (← evalExpr Bool (.const ``Bool []) r) then
3535
throwError
3636
("native implementation did not agree with reference implementation!\n" ++

src/kernel/type_checker.cpp

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -601,39 +601,9 @@ optional<expr> type_checker::unfold_definition(expr const & e) {
601601
}
602602
}
603603

604-
static expr * g_lean_reduce_bool = nullptr;
605-
static expr * g_lean_reduce_nat = nullptr;
606-
607-
namespace ir {
608-
object * run_boxed_kernel(environment const & env, options const & opts, name const & fn, unsigned n, object **args);
609-
}
610-
611604
expr mk_bool_true();
612605
expr mk_bool_false();
613606

614-
optional<expr> reduce_native(environment const & env, expr const & e) {
615-
if (!is_app(e)) return none_expr();
616-
expr const & arg = app_arg(e);
617-
if (!is_constant(arg)) return none_expr();
618-
if (app_fn(e) == *g_lean_reduce_bool) {
619-
object * r = ir::run_boxed_kernel(env, options(), const_name(arg), 0, nullptr);
620-
if (!lean_is_scalar(r)) {
621-
lean_dec_ref(r);
622-
throw kernel_exception(env, "type checker failure, unexpected result value for 'Lean.reduceBool'");
623-
}
624-
return lean_unbox(r) == 0 ? some_expr(mk_bool_false()) : some_expr(mk_bool_true());
625-
}
626-
if (app_fn(e) == *g_lean_reduce_nat) {
627-
object * r = ir::run_boxed_kernel(env, options(), const_name(arg), 0, nullptr);
628-
if (lean_is_scalar(r) || lean_is_mpz(r)) {
629-
return some_expr(mk_lit(literal(nat(r))));
630-
} else {
631-
throw kernel_exception(env, "type checker failure, unexpected result value for 'Lean.reduceNat'");
632-
}
633-
}
634-
return none_expr();
635-
}
636-
637607
static inline bool is_nat_lit_ext(expr const & e) { return e == *g_nat_zero || is_nat_lit(e); }
638608
static inline nat get_nat_val(expr const & e) {
639609
lean_assert(is_nat_lit_ext(e));
@@ -759,10 +729,7 @@ expr type_checker::whnf(expr const & e) {
759729
expr t = e;
760730
while (true) {
761731
expr t1 = whnf_core(t);
762-
if (auto v = reduce_native(env(), t1)) {
763-
m_st->m_whnf.insert(mk_pair(e, *v));
764-
return *v;
765-
} else if (auto v = reduce_nat(t1)) {
732+
if (auto v = reduce_nat(t1)) {
766733
m_st->m_whnf.insert(mk_pair(e, *v));
767734
return *v;
768735
} else if (auto next_t = unfold_definition(t1)) {
@@ -1098,12 +1065,6 @@ lbool type_checker::lazy_delta_reduction(expr & t_n, expr & s_n) {
10981065
}
10991066
}
11001067

1101-
if (auto t_v = reduce_native(env(), t_n)) {
1102-
return to_lbool(is_def_eq_core(*t_v, s_n));
1103-
} else if (auto s_v = reduce_native(env(), s_n)) {
1104-
return to_lbool(is_def_eq_core(t_n, *s_v));
1105-
}
1106-
11071068
switch (lazy_delta_reduction_step(t_n, s_n)) {
11081069
case reduction_status::Continue: break;
11091070
case reduction_status::DefUnknown: return l_undef;
@@ -1340,8 +1301,6 @@ void initialize_type_checker() {
13401301
g_nat_shiftLeft = new_persistent_expr_const({"Nat", "shiftLeft"});
13411302
g_nat_shiftRight = new_persistent_expr_const({"Nat", "shiftRight"});
13421303
g_string_mk = new_persistent_expr_const({"String", "ofList"});
1343-
g_lean_reduce_bool = new_persistent_expr_const({"Lean", "reduceBool"});
1344-
g_lean_reduce_nat = new_persistent_expr_const({"Lean", "reduceNat"});
13451304
register_name_generator_prefix(*g_kernel_fresh);
13461305
}
13471306

@@ -1367,7 +1326,5 @@ void finalize_type_checker() {
13671326
delete g_nat_shiftLeft;
13681327
delete g_nat_shiftRight;
13691328
delete g_string_mk;
1370-
delete g_lean_reduce_bool;
1371-
delete g_lean_reduce_nat;
13721329
}
13731330
}

src/library/ir_interpreter.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,15 +1165,6 @@ object * run_boxed(elab_environment const & env, options const & opts, name cons
11651165
return interpreter::with_interpreter<object *>(env, opts, fn, [&](interpreter & interp) { return interp.call_boxed(fn, n, args); });
11661166
}
11671167

1168-
extern "C" obj_res lean_elab_environment_of_kernel_env(obj_arg);
1169-
elab_environment elab_environment_of_kernel_env(environment const & env) {
1170-
return elab_environment(lean_elab_environment_of_kernel_env(env.to_obj_arg()));
1171-
}
1172-
1173-
object * run_boxed_kernel(environment const & env, options const & opts, name const & fn, unsigned n, object **args) {
1174-
return run_boxed(elab_environment_of_kernel_env(env), opts, fn, n, args);
1175-
}
1176-
11771168
uint32 run_main(elab_environment const & env, options const & opts, list_ref<string_ref> const & args) {
11781169
return interpreter::with_interpreter<uint32>(env, opts, "main", [&](interpreter & interp) { return interp.run_main(args); });
11791170
}

tests/elab/kernel1.lean

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,35 +21,3 @@ def a3 := 20
2121
/-- info: a1 =?= a3 := false -/
2222
#guard_msgs in
2323
#eval checkDefEq `a1 `a3
24-
25-
def v1 := 100000000000 + 100000000000
26-
def v2 := 200000000000
27-
def v3 := 200000000001
28-
def v4 : Bool := 20000000000 > 200000000001
29-
def v5 := 100000000000 - 100000000000
30-
31-
def c1 := reduceNat v1
32-
def c2 := reduceNat v2
33-
def c3 := reduceNat v3
34-
def c4 := reduceBool v4
35-
def c5 := reduceNat v5
36-
37-
/-- info: c1 =?= c2 := true -/
38-
#guard_msgs in
39-
#eval checkDefEq `c1 `c2
40-
41-
/-- info: c1 =?= c3 := false -/
42-
#guard_msgs in
43-
#eval checkDefEq `c1 `c3
44-
45-
/-- info: c5 =?= Nat.zero := true -/
46-
#guard_msgs in
47-
#eval checkDefEq `c5 `Nat.zero
48-
49-
/-- info: Nat.zero =?= c5 := true -/
50-
#guard_msgs in
51-
#eval checkDefEq `Nat.zero `c5
52-
53-
/-- info: c4 =?= Bool.true := false -/
54-
#guard_msgs in
55-
#eval checkDefEq `c4 `Bool.true

tests/elab/reduceBool.lean

Lines changed: 0 additions & 9 deletions
This file was deleted.

tests/elab/reduceBool.lean.out.expected

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)