import Lean open Lean open Lean.Elab open Lean.Elab.Term open Lean.Elab.Command open Std.Format open Std open Lean.PrettyPrinter open Lean.PrettyPrinter.Delaborator open Lean.Meta def checkM (stx : TermElabM Syntax) (optionsPerPos : OptionsPerPos := {}) : TermElabM Unit := do let opts ← getOptions let stx ← stx let e ← elabTermAndSynthesize stx none <* throwErrorIfErrors let stx' ← delab e optionsPerPos let f' ← PrettyPrinter.ppTerm stx' let s := f'.pretty' opts IO.println s let env ← getEnv match Parser.runParserCategory env `term s "" with | Except.error e => throwErrorAt stx e | Except.ok stx'' => do let e' ← elabTermAndSynthesize stx'' none <* throwErrorIfErrors unless (← isDefEq e e') do throwErrorAt stx (m!"failed to round-trip" ++ line ++ format e ++ line ++ format e') -- set_option trace.PrettyPrinter.parenthesize true set_option format.width 20 -- #eval checkM `(?m) -- fails round-trip #eval checkM `(Sort) #eval checkM `(Type) #eval checkM `(Type 0) #eval checkM `(Type 1) -- TODO: we need support for parsing `?u` to roundtrip the terms containing universe metavariables. Just pretty printing them as `_` is bad for error and trace messages -- #eval checkM `(Type _) -- #eval checkM `(Type (_ + 2)) #eval checkM `(@max Nat) #eval checkM `(@HEq Nat 1) #eval checkM `(@List.nil) #eval checkM `(Nat) #eval checkM `(List Nat) #eval checkM `(id Nat) #eval checkM `(id (id (id Nat))) section set_option pp.explicit true #eval checkM `(List Nat) #eval checkM `(id Nat) end section set_option pp.universes true #eval checkM `(List Nat) #eval checkM `(id Nat) #eval checkM `(Sum Nat Nat) end #eval checkM `(id (id Nat)) (Lean.RBMap.empty.insert (SubExpr.Pos.ofArray #[1]) $ KVMap.empty.insert `pp.explicit true) -- specify the expected type of `a` in a way that is not erased by the delaborator def typeAs.{u} (α : Type u) (a : α) := () set_option pp.analyze.knowsType false in #eval checkM `(fun (a : Nat) => a) #eval checkM `(fun (a : Nat) => a) #eval checkM `(fun (a b : Nat) => a) #eval checkM `(fun (a : Nat) (b : Bool) => a) #eval checkM `(fun {a b : Nat} => a) -- implicit lambdas work as long as the expected type is preserved #eval checkM `(typeAs ({α : Type} → (a : α) → α) fun a => a) section set_option pp.explicit true #eval checkM `(fun {α : Type} [ToString α] (a : α) => toString a) end #eval checkM `((α : Type) → α) #eval checkM `((α β : Type) → α) -- group #eval checkM `((α β : Type) → Type) -- don't group #eval checkM `((α : Type) → (a : α) → α) #eval checkM `({α : Type} → α) #eval checkM `({α : Type} → [ToString α] → α) #eval checkM `(∀ x : Nat, x = x) #eval checkM `(∀ {x : Nat} [ToString Nat], x = x) set_option pp.piBinderTypes false in #eval checkM `(∀ x : Nat, x = x) -- TODO: hide `ofNat` #eval checkM `(0) #eval checkM `(1) #eval checkM `(42) #eval checkM `("hi") set_option pp.structureInstanceTypes true in #eval checkM `((1,2,3)) #eval checkM `((1,2).fst) #eval checkM `(1 < 2 || true) #eval checkM `(id (fun a => a) 0) #eval checkM `(typeAs (Id Nat) (do let x := 1 discard <| pure 2 let y := 3 return x + y)) #eval checkM `(typeAs (Id Nat) (pure 1 >>= pure)) #eval checkM `((0 ≤ 1) = False) #eval checkM `((0 = 1) = False) #eval checkM `(-(-0))