This refactors and improves the `#eval` command, introducing some new
features.
* Now evaluated results can be represented using `ToExpr` and pretty
printing. This means **hoverable output**. If `ToExpr` fails, it then
tries `Repr` and then `ToString`. The `eval.pp` option controls whether
or not to try `ToExpr`.
* There is now **auto-derivation** of `Repr` instances, enabled with the
`pp.derive.repr` option (default to **true**). For example:
```lean
inductive Baz
| a | b
#eval Baz.a
-- Baz.a
```
It simply does `deriving instance Repr for Baz` when there's no way to
represent `Baz`. If core Lean gets `ToExpr` derive handlers, they could
be used here as well.
* The option `eval.type` controls whether or not to include the type in
the output. For now the default is false.
* Now things like `#eval do return 2` work. It tries using
`CommandElabM`, `TermElabM`, or `IO` when the monad is unknown.
* Now there is no longer `Lean.Eval` or `Lean.MetaEval`. These each used
to be responsible for both adapting monads and printing results. The
concerns have been split into two. (1) The `MonadEval` class is
responsible for adapting monads for evaluation (it is similar to
`MonadLift`, but instances are allowed to use default data when
initializing state) and (2) finding a way to represent results is
handled separately.
* Error messages about failed instance synthesis are now more precise.
Once it detects that a `MonadEval` class applies, then the error message
will be specific about missing `ToExpr`/`Repr`/`ToString` instances.
* Fixes a bug where `Repr`/`ToString` instances can't be found by
unfolding types "under the monad". For example, this works now:
```lean
def Foo := List Nat
def Foo.mk (l : List Nat) : Foo := l
#eval show Lean.CoreM Foo from do return Foo.mk [1,2,3]
```
* Elaboration errors now abort evaluation. This eliminates some
not-so-relevant error messages.
* Now evaluating a value of type `m Unit` never prints a blank message.
* Fixes bugs where evaluating `MetaM` and `CoreM` wouldn't collect log
messages.
The `run_cmd`, `run_elab`, and `run_meta` commands are now frontends for
`#eval`.
132 lines
4.2 KiB
Text
132 lines
4.2 KiB
Text
import Lean.Elab.Command
|
||
import Lean.Elab.Open
|
||
/-!
|
||
Issue #2291
|
||
|
||
The following example would cause the pretty printer to panic.
|
||
-/
|
||
|
||
set_option trace.compiler.simp true in
|
||
/--
|
||
info: [compiler.simp] >> _eval
|
||
let _x_21 := `Nat;
|
||
let _x_22 := [];
|
||
let _x_23 := Lean.Expr.const _x_21 _x_22;
|
||
let _x_24 := `List.nil;
|
||
let _x_25 := Lean.levelZero :: _x_22;
|
||
let _x_26 := Lean.Expr.const _x_24 _x_25;
|
||
let _x_27 := _x_26.app _x_23;
|
||
let _x_28 := `List.cons;
|
||
let _x_29 := Lean.Expr.const _x_28 _x_25;
|
||
let _x_30 := _x_29.app _x_23;
|
||
let _x_31 := [];
|
||
let _x_32 := 0 :: _x_31;
|
||
let _x_33 := Lean.List.toExprAux _x_27 _x_30 _x_32;
|
||
Lean.MessageData.ofExpr _x_33
|
||
[compiler.simp] >> _private.Lean.ToExpr.0.Lean.List.toExprAux._at._eval._spec_1
|
||
fun nilFn consFn x =>
|
||
List.casesOn fun head tail =>
|
||
let _x_1 := Lean.mkNatLit head;
|
||
let _x_2 := Lean.List.toExprAux._at._eval._spec_1 nilFn consFn tail;
|
||
Lean.mkAppB consFn _x_1 _x_2
|
||
>> _eval
|
||
let _x_14 := Lean.Name.str._override Lean.Name.anonymous._impl "Nat";
|
||
let _x_15 := List.nil _neutral;
|
||
let _x_16 := Lean.Expr.const._override _x_14 _x_15;
|
||
let _x_17 := `List.nil;
|
||
let _x_18 := List.cons _neutral Lean.levelZero _x_15;
|
||
let _x_19 := Lean.Expr.const._override _x_17 _x_18;
|
||
let _x_20 := Lean.Expr.app._override _x_19 _x_16;
|
||
let _x_21 := `List.cons;
|
||
let _x_22 := Lean.Expr.const._override _x_21 _x_18;
|
||
let _x_23 := Lean.Expr.app._override _x_22 _x_16;
|
||
let _x_24 := List.cons _neutral 0 _x_15;
|
||
let _x_25 := Lean.List.toExprAux._at._eval._spec_1 _x_20 _x_23 _x_24;
|
||
Lean.MessageData.ofExpr _x_25
|
||
[compiler.simp] >> _private.Lean.ToExpr.0.Lean.List.toExprAux._at._eval._spec_1
|
||
fun nilFn consFn x =>
|
||
List.casesOn fun head tail =>
|
||
let _x_1 := Lean.mkNatLit head;
|
||
let _x_2 := Lean.List.toExprAux._at._eval._spec_1 nilFn consFn tail;
|
||
Lean.mkAppB consFn _x_1 _x_2
|
||
>> _eval
|
||
let _x_1 := Lean.Name.str._override Lean.Name.anonymous._impl "Nat";
|
||
let _x_2 := List.nil _neutral;
|
||
let _x_3 := Lean.Expr.const._override _x_1 _x_2;
|
||
let _x_4 := `List.nil;
|
||
let _x_5 := List.cons _neutral Lean.levelZero _x_2;
|
||
let _x_6 := Lean.Expr.const._override _x_4 _x_5;
|
||
let _x_7 := Lean.Expr.app._override _x_6 _x_3;
|
||
let _x_8 := `List.cons;
|
||
let _x_9 := Lean.Expr.const._override _x_8 _x_5;
|
||
let _x_10 := Lean.Expr.app._override _x_9 _x_3;
|
||
let _x_11 := List.cons _neutral 0 _x_2;
|
||
let _x_12 := Lean.List.toExprAux._at._eval._spec_1 _x_7 _x_10 _x_11;
|
||
Lean.MessageData.ofExpr _x_12
|
||
[compiler.simp] >> _private.Lean.ToExpr.0.Lean.List.toExprAux._at._eval._spec_1
|
||
fun nilFn consFn x =>
|
||
List.casesOn fun head tail =>
|
||
let _x_1 := Lean.mkNatLit head;
|
||
let _x_2 := Lean.List.toExprAux._at._eval._spec_1 nilFn consFn tail;
|
||
Lean.mkAppB consFn _x_1 _x_2
|
||
>> _eval._closed_1
|
||
"Nat"
|
||
>> _eval._closed_2
|
||
Lean.Name.str._override Lean.Name.anonymous._impl _eval._closed_1
|
||
>> _eval._closed_3
|
||
let _x_1 := List.nil _neutral;
|
||
Lean.Expr.const._override _eval._closed_2 _x_1
|
||
>> _eval._closed_4
|
||
"List"
|
||
>> _eval._closed_5
|
||
"nil"
|
||
>> _eval._closed_6
|
||
Lean.Name.mkStr2 _eval._closed_4 _eval._closed_5
|
||
>> _eval._closed_7
|
||
let _x_1 := List.nil _neutral;
|
||
List.cons _neutral Lean.levelZero _x_1
|
||
>> _eval._closed_8
|
||
Lean.Expr.const._override _eval._closed_6 _eval._closed_7
|
||
>> _eval._closed_9
|
||
Lean.Expr.app._override _eval._closed_8 _eval._closed_3
|
||
>> _eval._closed_10
|
||
"cons"
|
||
>> _eval._closed_11
|
||
Lean.Name.mkStr2 _eval._closed_4 _eval._closed_10
|
||
>> _eval._closed_12
|
||
Lean.Expr.const._override _eval._closed_11 _eval._closed_7
|
||
>> _eval._closed_13
|
||
Lean.Expr.app._override _eval._closed_12 _eval._closed_3
|
||
>> _eval._closed_14
|
||
let _x_1 := List.nil _neutral;
|
||
List.cons _neutral 0 _x_1
|
||
>> _eval
|
||
let _x_1 :=
|
||
Lean.List.toExprAux._at._eval._spec_1 _eval._closed_9 _eval._closed_13
|
||
_eval._closed_14;
|
||
Lean.MessageData.ofExpr _x_1
|
||
---
|
||
info: [0]
|
||
-/
|
||
#guard_msgs in
|
||
#eval [0]
|
||
|
||
|
||
/-!
|
||
Fixing the above involved changing `Lean.unresolveNameGlobal`.
|
||
Here, we also verify that we do not pretty print using any aliases that have macro scopes.
|
||
-/
|
||
|
||
open Lean in
|
||
elab "add_bad_alias " n:ident : command => withFreshMacroScope do
|
||
let declName ← Elab.OpenDecl.resolveNameUsingNamespaces [← getCurrNamespace] n
|
||
let badName ← MonadQuotation.addMacroScope `bad
|
||
modify fun s => { s with env := addAlias s.env badName declName }
|
||
|
||
def f := 1
|
||
|
||
add_bad_alias f
|
||
|
||
-- Formerly was info: bad✝ : ℕ
|
||
/-- info: f : Nat -/
|
||
#guard_msgs in #check (f)
|