This PR adds a new, extensible `do` elaborator. Users can opt into the new elaborator by unsetting the option `backward.do.legacy`. New elaborators for the builtin `doElem` syntax category can be registered with attribute `doElem_elab`. For new syntax, additionally a control info handler must be registered with attribute `doElem_control_info` that specifies whether the new syntax `return`s early, `break`s, `continue`s and which `mut` vars it reassigns. Do elaborators have type ``TSyntax `doElem → DoElemCont → DoElabM Expr``, where `DoElabM` is essentially `TermElabM` and the `DoElemCont` represents how the rest of the `do` block is to be elaborated. Consult the docstrings for more details. Breaking Changes: * The syntax for `let pat := rhs | otherwise` and similar now scope over the `doSeq` that follows. Furthermore, `otherwise` and the sequence that follows are now `doSeqIndented` in order not to steal syntax from record syntax. Breaking Changes when opting into the new `do` elaborator by unsetting `backward.do.legacy`: * `do` notation now always requires `Pure`. * `do match` is now always non-dependent. There is `do match (dependent := true)` that expands to a term match as a workaround for some dependent uses.
66 lines
2.3 KiB
Text
66 lines
2.3 KiB
Text
/-
|
||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Sebastian Graf
|
||
-/
|
||
|
||
module
|
||
|
||
prelude
|
||
public import Lean.Meta.InferType
|
||
import Lean.Meta.DecLevel
|
||
import Init.Data.Range.Polymorphic.Iterators
|
||
|
||
public section
|
||
|
||
namespace Lean.Meta
|
||
|
||
/--
|
||
Given types `tᵢ`, return the tuple type `t₁ × t₂ × … × tₙ`.
|
||
For `n = 0`, return `PUnit` with the given level + 1.
|
||
-/
|
||
def mkProdN (ts : Array Expr) (u : Level /- used as `Type u` -/) : MetaM Expr := do
|
||
if h : ts.size > 0 then
|
||
let mut tupleTy := ts.back
|
||
let mut u ← getDecLevel tupleTy
|
||
let mut ts := ts.pop
|
||
for i in 0...ts.size do
|
||
let ty := ts.back!
|
||
let u' ← getDecLevel ty
|
||
tupleTy := mkApp2 (mkConst ``Prod [u', u]) ty tupleTy
|
||
u := (mkLevelMax u u').normalize
|
||
ts := ts.pop
|
||
return tupleTy
|
||
else
|
||
return mkConst ``PUnit [mkLevelSucc u]
|
||
|
||
/--
|
||
Given expressions `eᵢ`, return the tuple `(e₁, e₂, …, eₙ)` and its type `t₁ × t₂ × … × tₙ`.
|
||
For `n = 0`, return `PUnit.unit` with the given level + 1.
|
||
-/
|
||
def mkProdMkN (es : Array Expr) (u : Level /- used as `Type u` -/) : MetaM (Expr × Expr) := do
|
||
if h : es.size > 0 then
|
||
let mut tuple := es.back
|
||
let mut tupleTy ← inferType tuple
|
||
let mut u ← getDecLevel tupleTy
|
||
let mut es := es.pop
|
||
for i in 0...es.size do
|
||
let e := es.back!
|
||
let ty ← inferType e
|
||
let u' ← getDecLevel ty
|
||
tuple := mkApp4 (mkConst ``Prod.mk [u', u]) ty tupleTy e tuple
|
||
tupleTy := mkApp2 (mkConst ``Prod [u', u]) ty tupleTy
|
||
u := (mkLevelMax u u').normalize
|
||
es := es.pop
|
||
return (tuple, tupleTy)
|
||
else
|
||
return (mkConst ``PUnit.unit [mkLevelSucc u], mkConst ``PUnit [mkLevelSucc u])
|
||
|
||
/-- Given a product `(e₁, e₂)` of type `t₁ × t₂`, return `(e₁, t₁, e₂, t₂)`. -/
|
||
def getProdFields (tuple tupleTy : Expr) : MetaM (Expr × Expr × Expr × Expr) := do
|
||
let tupleTy ← instantiateMVarsIfMVarApp tupleTy
|
||
let_expr c@Prod fstTy sndTy := tupleTy
|
||
| throwError "Internal error: Expected Prod, got {tuple} of type {tupleTy}"
|
||
let fst := mkApp3 (mkConst ``Prod.fst c.constLevels!) fstTy sndTy tuple
|
||
let snd := mkApp3 (mkConst ``Prod.snd c.constLevels!) fstTy sndTy tuple
|
||
return (fst, fstTy, snd, sndTy)
|