chore: add elaborator for let_fun and let_delayed
This commit is contained in:
parent
90abace21a
commit
e7140959c4
6 changed files with 18 additions and 14 deletions
|
|
@ -269,7 +269,6 @@ syntax (name := «have») "have " haveDecl : tactic
|
|||
syntax (name := «suffices») "suffices " sufficesDecl : tactic
|
||||
syntax (name := «show») "show " term : tactic
|
||||
syntax (name := «let») "let " letDecl : tactic
|
||||
syntax (name := «let!») "let! " letDecl : tactic
|
||||
syntax (name := letrec) withPosition(atomic(group("let " &"rec ")) letRecDecls) : tactic
|
||||
|
||||
syntax inductionAlt := "| " (group("@"? ident) <|> "_") (ident <|> "_")* " => " (hole <|> syntheticHole <|> tacticSeq)
|
||||
|
|
|
|||
|
|
@ -578,8 +578,8 @@ def elabLetDeclCore (stx : Syntax) (expectedType? : Option Expr) (useLetExpr : B
|
|||
let stxNew ← `(let x : $type := $val; match x with | $pat => $body)
|
||||
let stxNew := match useLetExpr, elabBodyFirst with
|
||||
| true, false => stxNew
|
||||
| true, true => stxNew.setKind `Lean.Parser.Term.«let*»
|
||||
| false, true => stxNew.setKind `Lean.Parser.Term.«let!»
|
||||
| true, true => stxNew.setKind `Lean.Parser.Term.«let_delayed»
|
||||
| false, true => stxNew.setKind `Lean.Parser.Term.«let_fun»
|
||||
| false, false => unreachable!
|
||||
withMacroExpansion stx stxNew <| elabTerm stxNew expectedType?
|
||||
else if letDecl.getKind == `Lean.Parser.Term.letEqnsDecl then
|
||||
|
|
@ -599,6 +599,12 @@ def elabLetDeclCore (stx : Syntax) (expectedType? : Option Expr) (useLetExpr : B
|
|||
@[builtinTermElab «let*»] def elabLetStarDecl : TermElab :=
|
||||
fun stx expectedType? => elabLetDeclCore stx expectedType? true true
|
||||
|
||||
@[builtinTermElab «let_fun»] def elabLetFunDecl : TermElab :=
|
||||
fun stx expectedType? => elabLetDeclCore stx expectedType? false false
|
||||
|
||||
@[builtinTermElab «let_delayed»] def elabLetDelayedDecl : TermElab :=
|
||||
fun stx expectedType? => elabLetDeclCore stx expectedType? true true
|
||||
|
||||
builtin_initialize registerTraceClass `Elab.let
|
||||
|
||||
end Lean.Elab.Term
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ open Meta
|
|||
|
||||
@[builtinMacro Lean.Parser.Term.show] def expandShow : Macro := fun stx =>
|
||||
match stx with
|
||||
| `(show $type from $val) => let thisId := mkIdentFrom stx `this; `(let! $thisId : $type := $val; $thisId)
|
||||
| `(show $type from $val) => let thisId := mkIdentFrom stx `this; `(let_fun $thisId : $type := $val; $thisId)
|
||||
| `(show $type by $tac:tacticSeq) => `(show $type from by $tac:tacticSeq)
|
||||
| _ => Macro.throwUnsupported
|
||||
|
||||
|
|
@ -46,8 +46,8 @@ open Meta
|
|||
let mkId (x? : Option Syntax) : Syntax :=
|
||||
x?.getD <| mkIdentFrom stx `this
|
||||
match stx with
|
||||
| `(have $[$x :]? $type from $val $[;]? $body) => let x := mkId x; `(let! $x : $type := $val; $body)
|
||||
| `(have $[$x :]? $type := $val $[;]? $body) => let x := mkId x; `(let! $x : $type := $val; $body)
|
||||
| `(have $[$x :]? $type from $val $[;]? $body) => let x := mkId x; `(let_fun $x : $type := $val; $body)
|
||||
| `(have $[$x :]? $type := $val $[;]? $body) => let x := mkId x; `(let_fun $x : $type := $val; $body)
|
||||
| `(have $[$x :]? $type by $tac:tacticSeq $[;]? $body) => `(have $[$x :]? $type from by $tac:tacticSeq; $body)
|
||||
| _ => Macro.throwUnsupported
|
||||
|
||||
|
|
|
|||
|
|
@ -950,7 +950,7 @@ def mkJoinPoint (j : Name) (ps : Array (Name × Bool)) (body : Syntax) (k : Synt
|
|||
let pTypes ← ps.mapM fun ⟨id, useTypeOf⟩ => do if useTypeOf then `(typeOf! $(← mkIdentFromRef id)) else `(_)
|
||||
let ps ← ps.mapM fun ⟨id, useTypeOf⟩ => mkIdentFromRef id
|
||||
/-
|
||||
We use `let*` instead of `let` for joinpoints to make sure `$k` is elaborated before `$body`.
|
||||
We use `let_delayed` instead of `let` for joinpoints to make sure `$k` is elaborated before `$body`.
|
||||
By elaborating `$k` first, we "learn" more about `$body`'s type.
|
||||
For example, consider the following example `do` expression
|
||||
```
|
||||
|
|
@ -970,10 +970,10 @@ def mkJoinPoint (j : Name) (ps : Array (Name × Bool)) (body : Syntax) (k : Synt
|
|||
else
|
||||
jp ()
|
||||
```
|
||||
If we use the regular `let` instead of `let*`, the joinpoint `jp` will be elaborated and its type will be inferred to be `Unit → IO (IO.Ref Bool)`.
|
||||
Then, we get a typing error at `jp ()`. By using `let*`, we first elaborate `if x > 0 ...` and learn that `jp` has type `Unit → IO Unit`.
|
||||
If we use the regular `let` instead of `let_delayed`, the joinpoint `jp` will be elaborated and its type will be inferred to be `Unit → IO (IO.Ref Bool)`.
|
||||
Then, we get a typing error at `jp ()`. By using `let_delayed`, we first elaborate `if x > 0 ...` and learn that `jp` has type `Unit → IO Unit`.
|
||||
Then, we get the expected type mismatch error at `IO.mkRef true`. -/
|
||||
`(let* $(← mkIdentFromRef j):ident $[($ps : $pTypes)]* : $((← read).m) _ := $body; $k)
|
||||
`(let_delayed $(← mkIdentFromRef j):ident $[($ps : $pTypes)]* : $((← read).m) _ := $body; $k)
|
||||
|
||||
def mkJmp (ref : Syntax) (j : Name) (args : Array Syntax) : Syntax :=
|
||||
Syntax.mkApp (mkIdentFrom ref j) args
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ private partial def getHeadInfo (alt : Alt) : TermElabM HeadInfo :=
|
|||
match k with
|
||||
| `optional =>
|
||||
let nones := mkArray ids.size (← `(none))
|
||||
`(let* yes _ $ids* := $yes;
|
||||
`(let_delayed yes _ $ids* := $yes;
|
||||
if discr.isNone then yes () $[ $nones]*
|
||||
else match discr with
|
||||
| `($(mkNullNode contents)) => yes () $[ (some $ids)]*
|
||||
|
|
@ -385,7 +385,7 @@ private partial def getHeadInfo (alt : Alt) : TermElabM HeadInfo :=
|
|||
| r => r }
|
||||
| _ => throwErrorAt! pat "match_syntax: unexpected pattern kind {pat}"
|
||||
|
||||
-- Bind right-hand side to new `let*` decl in order to prevent code duplication
|
||||
-- Bind right-hand side to new `let_delayed` decl in order to prevent code duplication
|
||||
private def deduplicate (floatedLetDecls : Array Syntax) : Alt → TermElabM (Array Syntax × Alt)
|
||||
-- NOTE: new macro scope so that introduced bindings do not collide
|
||||
| (pats, rhs) => do
|
||||
|
|
@ -448,7 +448,7 @@ private partial def compileStxMatch (discrs : List Syntax) (alts : List Alt) : T
|
|||
withFreshMacroScope $ compileStxMatch (newDiscrs ++ discrs) yesAlts.toList)
|
||||
(no := withFreshMacroScope $ compileStxMatch (discr::discrs) nonExhaustiveAlts.toList)
|
||||
for d in floatedLetDecls do
|
||||
stx ← `(let* $d:letDecl; $stx)
|
||||
stx ← `(let_delayed $d:letDecl; $stx)
|
||||
`(let discr := $discr; $stx)
|
||||
| _, _ => unreachable!
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ private def liftTermBinderSyntax : Macro := fun stx => do
|
|||
|
||||
@[builtinMacro Lean.Parser.Tactic.have] def expandHaveTactic : Macro := liftTermBinderSyntax
|
||||
@[builtinMacro Lean.Parser.Tactic.let] def expandLetTactic : Macro := liftTermBinderSyntax
|
||||
@[builtinMacro Lean.Parser.Tactic.«let!»] def expandLetBangTactic : Macro := liftTermBinderSyntax
|
||||
@[builtinMacro Lean.Parser.Tactic.suffices] def expandSufficesTactic : Macro := liftTermBinderSyntax
|
||||
@[builtinMacro Lean.Parser.Tactic.letrec] def expandLetRecTactic : Macro := liftTermBinderSyntax
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue