lean4-htt/src/Lean/Elab/LetRec.lean
2020-09-02 18:53:18 -07:00

124 lines
4.3 KiB
Text
Raw 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.

/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.Elab.Attributes
import Lean.Elab.Binders
import Lean.Elab.DeclModifiers
import Lean.Elab.SyntheticMVars
namespace Lean
namespace Elab
namespace Term
open Meta
structure LetRecDeclView :=
(ref : Syntax)
(attrs : Array Attribute)
(shortDeclName : Name)
(declName : Name)
(numParams : Nat)
(type : Expr)
(mvar : Expr) -- auxiliary metavariable used to lift the 'let rec'
(valStx : Syntax)
structure LetRecView :=
(decls : Array LetRecDeclView)
(body : Syntax)
/- group ("let " >> nonReservedSymbol "rec ") >> sepBy1 (group (optional «attributes» >> letDecl)) ", " >> "; " >> termParser -/
private def mkLetRecDeclView (letRec : Syntax) : TermElabM LetRecView := do
decls ← (letRec.getArg 1).getArgs.getSepElems.mapM fun attrDeclStx => do {
let attrStx := attrDeclStx.getArg 0;
attrs ← elabAttrs attrStx;
let decl := (attrDeclStx.getArg 1).getArg 0;
if decl.isOfKind `Lean.Parser.Term.letPatDecl then
throwErrorAt decl "patterns are not allowed in 'let rec' expressions"
else if decl.isOfKind `Lean.Parser.Term.letIdDecl || decl.isOfKind `Lean.Parser.Term.letEqnsDecl then do
let shortDeclName := decl.getIdAt 0;
currDeclName? ← getDeclName?;
let declName := currDeclName?.getD Name.anonymous ++ shortDeclName;
checkNotAlreadyDeclared declName;
applyAttributes declName attrs AttributeApplicationTime.beforeElaboration;
let binders := (decl.getArg 1).getArgs;
let typeStx := expandOptType decl (decl.getArg 2);
(type, numParams) ← elabBinders binders fun xs => do {
type ← elabType typeStx;
type ← mkForallFVars xs type;
pure (type, xs.size)
};
mvar ← mkFreshExprMVar type MetavarKind.syntheticOpaque;
valStx ←
if decl.isOfKind `Lean.Parser.Term.letIdDecl then
pure $ decl.getArg 4
else
liftMacroM $ expandMatchAltsIntoMatch decl (decl.getArg 4);
pure {
ref := decl,
attrs := attrs,
shortDeclName := shortDeclName,
declName := declName,
numParams := numParams,
type := type,
mvar := mvar,
valStx := valStx
: LetRecDeclView }
else
throwUnsupportedSyntax
};
pure {
decls := decls,
body := letRec.getArg 3
}
private partial def withAuxLocalDeclsAux {α} (views : Array LetRecDeclView) (k : Array Expr → TermElabM α) : Nat → Array Expr → TermElabM α
| i, fvars =>
if h : i < views.size then
let view := views.get ⟨i, h⟩;
withLetDecl view.shortDeclName view.type view.mvar fun fvar => withAuxLocalDeclsAux (i+1) (fvars.push fvar)
else
k fvars
private def withAuxLocalDecls {α} (views : Array LetRecDeclView) (k : Array Expr → TermElabM α) : TermElabM α :=
withAuxLocalDeclsAux views k 0 #[]
private def elabLetRecDeclValues (view : LetRecView) : TermElabM (Array Expr) :=
view.decls.mapM fun view => do
forallBoundedTelescope view.type view.numParams fun xs type =>
withDeclName view.declName do
value ← elabTermEnsuringType view.valStx type;
mkLambdaFVars xs value
private def abortIfContainsSyntheticSorry (e : Expr) : TermElabM Unit := do
e ← instantiateMVars e;
when e.hasSyntheticSorry $ throwAbort
private def registerLetRecsToLift (views : Array LetRecDeclView) (fvars : Array Expr) (values : Array Expr) : TermElabM Unit := do
lctx ← getLCtx;
let toLift := views.mapIdx fun i view => {
ref := view.ref,
fvarId := (fvars.get! i).fvarId!,
attrs := view.attrs,
shortDeclName := view.shortDeclName,
declName := view.declName,
lctx := lctx,
type := view.type,
val := values.get! i,
mvarId := view.mvar.mvarId!
: LetRecToLift };
modify fun s => { s with letRecsToLift := toLift.toList ++ s.letRecsToLift }
@[builtinTermElab «letrec»] def elabLetRec : TermElab :=
fun stx expectedType? => do
view ← mkLetRecDeclView stx;
withAuxLocalDecls view.decls fun fvars => do
values ← elabLetRecDeclValues view;
body ← elabTermEnsuringType view.body expectedType?;
registerLetRecsToLift view.decls fvars values;
mkLetFVars fvars body
end Term
end Elab
end Lean