lean4-htt/tests/elab/eval.lean
Kyle Miller e804829101
feat: have #eval elaborate variables (#11427)
This PR modifies `#eval e` to elaborate `e` with section variables in
scope. While evaluating expressions with free variables is not possible,
this lets `#eval` give a better error message than "unknown identifier."

Example:
```lean
section
variable (n : Nat)
/-- error: Cannot evaluate, contains free variable `n` -/
#guard_msgs in #eval n
end
```

The error is localized to `#eval`. It would be more friendly if the
error were to be placed on uses of free variables.

[Zulip
discussion](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Unknown.20identifier.20error.20messages.20for.20.60.23eval.60/near/560864544)
2026-03-09 04:52:08 +00:00

210 lines
4.1 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Lean
/-!
# Tests of the `#eval` command
-/
set_option eval.type true
/-!
Basic values
-/
/-- info: 2 : Nat -/
#guard_msgs in #eval 2
/-- info: some 2 : Option Nat -/
#guard_msgs in #eval some 2
/-- info: [2, 3, 4] : List Nat -/
#guard_msgs in #eval [1,2,3].map (· + 1)
/-!
Deciding a proposition
-/
/-- info: true : Bool -/
#guard_msgs in #eval True
/-!
Can't evaluate proofs
-/
/-- error: Cannot evaluate, proofs are not computationally relevant -/
#guard_msgs in #eval trivial
/-!
Can't evaluate types
-/
/-- error: Cannot evaluate, types are not computationally relevant -/
#guard_msgs in #eval Nat
/-!
Capturing `dbg_trace` output
-/
def Nat.choose : Nat → Nat → Nat
| _, 0 => dbg_trace "(_, 0)"; 1
| 0, _ + 1 => dbg_trace "(0, _ + 1)"; 0
| n + 1, k + 1 => dbg_trace "(_ + 1, _ + 1)"; choose n k + choose n (k + 1)
/--
info: (_ + 1, _ + 1)
(_ + 1, _ + 1)
(_, 0)
(0, _ + 1)
(_ + 1, _ + 1)
(0, _ + 1)
(0, _ + 1)
---
info: 1 : Nat
-/
#guard_msgs in #eval Nat.choose 2 2
/-!
Custom monad
-/
abbrev MyMonad := ReaderT Nat IO
/--
error: Unable to synthesize `MonadEval` instance to adapt
MyMonad Nat
to `IO` or `Lean.Elab.Command.CommandElabM`.
-/
#guard_msgs in #eval (pure 2 : MyMonad Nat)
-- Note that there is no "this is due to..." diagonostic in this case.
/--
error: Could not synthesize a `ToExpr`, `Repr`, or `ToString` instance for type
MyMonad (Nat → Nat)
-/
#guard_msgs in #eval (pure id : MyMonad (Nat → _))
instance : MonadEval MyMonad IO where
monadEval m := m.run 0
/-- info: 2 : Nat -/
#guard_msgs in #eval (pure 2 : MyMonad Nat)
-- Note that now we have a MonadEval instance, it doesn't mention MyMonad in the error.
/--
error: Could not synthesize a `ToExpr`, `Repr`, or `ToString` instance for type
Nat → Nat
-/
#guard_msgs in #eval (pure id : MyMonad (Nat → _))
/-!
Elaboration error, does not attempt to evaluate.
-/
/-- error: Unknown identifier `x` -/
#guard_msgs in #eval 2 + x
/-!
Defaulting to the CommandElabM monad
-/
/-- info: 2 : Nat -/
#guard_msgs in #eval do pure 2
/-- info: true : Bool -/
#guard_msgs in #eval do return (← Lean.getEnv).contains ``Lean.MessageData
/-!
Defaulting does not affect postponed elaborators.
-/
/-- info: 1 : Nat -/
#guard_msgs in #eval if True then 1 else 2
/-!
Testing that dbg_trace and logs carry over from all the major meta monads.
-/
/--
info: hi
---
info: dbg
-/
#guard_msgs in #eval show Lean.Elab.Term.TermElabM Unit from do dbg_trace "dbg"; Lean.logInfo m!"hi"
/--
info: hi
---
info: dbg
-/
#guard_msgs in #eval show Lean.MetaM Unit from do dbg_trace "dbg"; Lean.logInfo m!"hi"
/--
info: hi
---
info: dbg
-/
#guard_msgs in #eval show Lean.CoreM Unit from do dbg_trace "dbg"; Lean.logInfo m!"hi"
/-!
Testing delta deriving
-/
def Foo := List Nat
def Foo.mk (l : List Nat) : Foo := l
/-- info: [1, 2, 3] : Foo -/
#guard_msgs in #eval Foo.mk [1,2,3]
/-- info: [1, 2, 3] : Foo -/
#guard_msgs in #eval do return Foo.mk [1,2,3]
/-!
Testing auto-deriving
-/
inductive Baz
| a | b
/-- info: Baz.a : Baz -/
#guard_msgs in #eval Baz.a
/-!
Returning after printing
-/
def returns : Lean.CoreM Nat := do
IO.println "hi"
return 2
/--
info: hi
---
info: 2 : Nat
-/
#guard_msgs in #eval returns
/-!
Throwing an exception after printing
-/
def throwsEx : Lean.CoreM Nat := do
IO.println "hi"
throwError "ex"
/--
info: hi
---
error: ex
-/
#guard_msgs in #eval throwsEx
/-!
Let rec support (issue #2374)
-/
/-- info: 37 : Nat -/
#guard_msgs in #eval
let rec bar : Nat := 1
37
/-- info: 120 : Nat -/
#guard_msgs in #eval
let rec fact (n : Nat) : Nat :=
match n with
| 0 => 1
| n' + 1 => n * fact n'
fact 5
/-!
Elaborate `variables` and have a specific error about referenced free variables,
rather than give an "unknown identifier" error while elaborating.
-/
section
variable (m n : Nat) {α : Type} [DecidableEq α] (x y : α)
/-- error: Cannot evaluate, contains free variable `n` -/
#guard_msgs in #eval n
/-- error: Cannot evaluate, contains free variables `m` and `n` -/
#guard_msgs in #eval m + n
/-! Picks up on decidable instances from the `Prop`->`Bool` conversion too. -/
/-- error: Cannot evaluate, contains free variables `α`, `x`, `y`, and `inst✝` -/
#guard_msgs in #eval x = y
end