lean4-htt/src/Lean/Meta/ProdN.lean
Sebastian Graf 4278038940
feat: new, extensible do elaborator (#12459)
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.
2026-02-21 17:17:29 +00:00

66 lines
2.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) 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)