Skip to content

Commit b9cdbef

Browse files
committed
Merge remote-tracking branch 'upstream/master' into opaquerepr
2 parents b7f355d + 0bd15be commit b9cdbef

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+516
-244
lines changed

Diff for: RELEASES.md

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ Please check the [releases](https://github.com/leanprover/lean4/releases) page f
1010
v4.3.0 (development in progress)
1111
---------
1212

13+
* **Lake:** Changed `postUpdate?` configuration option to a `post_update` declaration. See the `post_update` syntax docstring for more information on the new syntax.
14+
15+
* [Lake: A manifest is automatically created on workspace load if one does not exists.](https://github.com/leanprover/lean4/pull/2680).
16+
17+
* **Lake:** The `:=` syntax for configuration declarations (i.e., `package`, `lean_lib`, and `lean_exe`) has been deprecated. For example, `package foo := {...}` is deprecated.
18+
1319
v4.2.0
1420
---------
1521

Diff for: src/Init/Data/Fin/Basic.lean

+5-5
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,19 @@ protected def sub : Fin n → Fin n → Fin n
4545
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + (n - b)) % n, mlt h⟩
4646

4747
/-!
48-
Remark: mod/div/modn/land/lor can be defined without using (% n), but
48+
Remark: land/lor can be defined without using (% n), but
4949
we are trying to minimize the number of Nat theorems
5050
needed to bootstrap Lean.
5151
-/
5252

5353
protected def mod : Fin n → Fin n → Fin n
54-
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a % b) % n, mlt h⟩
54+
| ⟨a, h⟩, ⟨b, _⟩ => ⟨a % b, Nat.lt_of_le_of_lt (Nat.mod_le _ _) h⟩
5555

5656
protected def div : Fin n → Fin n → Fin n
57-
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a / b) % n, mlt h⟩
57+
| ⟨a, h⟩, ⟨b, _⟩ => ⟨a / b, Nat.lt_of_le_of_lt (Nat.div_le_self _ _) h⟩
5858

5959
def modn : Fin n → Nat → Fin n
60-
| ⟨a, h⟩, m => ⟨(a % m) % n, mlt h⟩
60+
| ⟨a, h⟩, m => ⟨a % m, Nat.lt_of_le_of_lt (Nat.mod_le _ _) h⟩
6161

6262
def land : Fin n → Fin n → Fin n
6363
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(Nat.land a b) % n, mlt h⟩
@@ -110,7 +110,7 @@ theorem val_ne_of_ne {i j : Fin n} (h : i ≠ j) : val i ≠ val j :=
110110
fun h' => absurd (eq_of_val_eq h') h
111111

112112
theorem modn_lt : ∀ {m : Nat} (i : Fin n), m > 0 → (modn i m).val < m
113-
| _, ⟨_, _⟩, hp => Nat.lt_of_le_of_lt (mod_le _ _) (mod_lt _ hp)
113+
| _, ⟨_, _⟩, hp => by simp [modn]; apply Nat.mod_lt; assumption
114114

115115
theorem val_lt_of_le (i : Fin b) (h : b ≤ n) : i.val < n :=
116116
Nat.lt_of_lt_of_le i.isLt h

Diff for: src/Init/Meta.lean

+5
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,10 @@ structure Config where
12611261
/-- If `failIfUnchanged := true`, then calls to `simp`, `dsimp`, or `simp_all`
12621262
will fail if they do not make progress. -/
12631263
failIfUnchanged : Bool := true
1264+
/-- If `ground := true`, then ground terms are reduced. A term is ground when
1265+
it does not contain free or meta variables. Reduction is interrupted at a function application `f ...`
1266+
if `f` is marked to not be unfolded. -/
1267+
ground : Bool := false
12641268
deriving Inhabited, BEq, Repr
12651269

12661270
-- Configuration object for `simp_all`
@@ -1276,6 +1280,7 @@ def neutralConfig : Simp.Config := {
12761280
decide := false
12771281
arith := false
12781282
autoUnfold := false
1283+
ground := false
12791284
}
12801285

12811286
end Simp

Diff for: src/Lean/Meta/Tactic/Simp.lean

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ builtin_initialize registerTraceClass `Meta.Tactic.simp.congr (inherited := true
1717
builtin_initialize registerTraceClass `Meta.Tactic.simp.discharge (inherited := true)
1818
builtin_initialize registerTraceClass `Meta.Tactic.simp.rewrite (inherited := true)
1919
builtin_initialize registerTraceClass `Meta.Tactic.simp.unify (inherited := true)
20+
builtin_initialize registerTraceClass `Meta.Tactic.simp.ground (inherited := true)
2021
builtin_initialize registerTraceClass `Meta.Tactic.simp.numSteps
2122
builtin_initialize registerTraceClass `Meta.Tactic.simp.heads
2223
builtin_initialize registerTraceClass `Debug.Meta.Tactic.simp

Diff for: src/Lean/Meta/Tactic/Simp/Main.lean

+48-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Lean.Meta.Transform
77
import Lean.Meta.Tactic.Replace
88
import Lean.Meta.Tactic.UnifyEq
99
import Lean.Meta.Tactic.Simp.Rewrite
10+
import Lean.Meta.Match.Value
1011

1112
namespace Lean.Meta
1213
namespace Simp
@@ -145,15 +146,59 @@ where
145146
let f := e.getAppFn
146147
f.isConst && isMatcherCore env f.constName!
147148

149+
/--
150+
Auxiliary function for implementing `ctx.config.ground`: evaluate ground terms eagerly.
151+
We currently use `whnf` to implement this feature, but we want to stop ground evaluation at symbols marked with the `-` modifier.
152+
For example, `simp (config := { ground := true }) [-f]` should not unfold `f` even if the goal contains a ground term such as `f 2`.
153+
-/
154+
private def canUnfoldAtSimpGround (erased : SimpTheoremsArray) (_ : Meta.Config) (info : ConstantInfo) : CoreM Bool := do
155+
return !erased.isErased (.decl info.name)
156+
157+
/--
158+
Try to unfold `e`.
159+
-/
148160
private def unfold? (e : Expr) : SimpM (Option Expr) := do
149161
let f := e.getAppFn
150162
if !f.isConst then
151163
return none
152164
let fName := f.constName!
153-
if (← isProjectionFn fName) then
154-
return none -- should be reduced by `reduceProjFn?`
155165
let ctx ← read
156-
if ctx.config.autoUnfold then
166+
-- TODO: remove `rec` after we switch to new code generator
167+
let rec unfoldGround? : SimpM (Option Expr) := do
168+
unless ctx.config.ground do return none
169+
-- We are assuming that assigned metavariables are going to be instantiated by the main simp loop.
170+
if e.hasExprMVar || e.hasFVar then return none
171+
if ctx.simpTheorems.isErased (.decl fName) then return none
172+
-- TODO: check whether we need more filters
173+
if (← isType e) then return none -- we don't unfold types
174+
if (← isProof e) then return none -- we don't unfold proofs
175+
if (← isInstance fName) then return none -- we don't unfold instances
176+
-- TODO: we must have a notion of `simp` value, or more general solution for Lean
177+
if Meta.isMatchValue e || isOfNatNatLit e then return none
178+
if e.isConst then
179+
-- We don't unfold constants that take arguments
180+
-- TODO: add support for skipping partial applications too.
181+
if let .forallE .. ← whnfD (← inferType e) then
182+
return none
183+
/-
184+
We are currently using `whnf` with a custom `canUnfold?` predicate to reduce ground terms.
185+
This can be inefficient, and produce proofs that are too expensive to type check in the Kernel. Some reasons:
186+
- Functions defined by Well-founded recursion are expensive to reduce here and in the kernel.
187+
- The kernel does not know we may have controlled reduction using `canUnfold?`.
188+
189+
It would be great to reduce the ground term using a to-be-implemented `cbv` tactic which produces a
190+
proof that can be efficiently checked by the kernel.
191+
-/
192+
let eNew ← withDefault <|
193+
withTheReader Meta.Context (fun c => { c with canUnfold? := canUnfoldAtSimpGround ctx.simpTheorems }) <| whnf e
194+
if eNew == e then return none
195+
trace[Meta.Tactic.simp.ground] "{e}\n---->\n{eNew}"
196+
return some eNew
197+
if let some eNew ← unfoldGround? then
198+
return some eNew
199+
else if (← isProjectionFn fName) then
200+
return none -- should be reduced by `reduceProjFn?`
201+
else if ctx.config.autoUnfold then
157202
if ctx.simpTheorems.isErased (.decl fName) then
158203
return none
159204
else if hasSmartUnfoldingDecl (← getEnv) fName then

Diff for: src/Lean/Meta/Tactic/Simp/SimpTheorems.lean

+2-1
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,9 @@ mutual
109109
else if proof.isAppOfArity ``Eq.symm 4 then
110110
-- `Eq.symm` of rfl theorem is a rfl theorem
111111
isRflProofCore type proof.appArg! -- small hack: we don't need to set the exact type
112-
else if proof.isApp && proof.getAppFn.isConst then
112+
else if proof.getAppFn.isConst then
113113
-- The application of a `rfl` theorem is a `rfl` theorem
114+
-- A constant which is a `rfl` theorem is a `rfl` theorem
114115
isRflTheorem proof.getAppFn.constName!
115116
else
116117
return false

Diff for: src/Lean/Meta/Tactic/Subst.lean

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ def substCore (mvarId : MVarId) (hFVarId : FVarId) (symm := false) (fvarSubst :
5252
if clearH then
5353
let mvarId ← mvarId.clear hFVarId
5454
let mvarId ← mvarId.clear aFVarId
55-
pure ({}, mvarId)
55+
pure (fvarSubst, mvarId)
5656
else
57-
pure ({}, mvarId)
57+
pure (fvarSubst, mvarId)
5858
else
5959
mvarId.withContext do
6060
let mvarDecl ← mvarId.getDecl

Diff for: src/Lean/Meta/Tactic/UnifyEq.lean

+7-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ def unifyEq? (mvarId : MVarId) (eqFVarId : FVarId) (subst : FVarSubst := {})
5353
/- Remark: we use `let rec` here because otherwise the compiler would generate an insane amount of code.
5454
We can remove the `rec` after we fix the eagerly inlining issue in the compiler. -/
5555
let rec substEq (symm : Bool) := do
56-
/- Remark: `substCore` fails if the equation is of the form `x = x` -/
57-
if let some (subst, mvarId) ← observing? (substCore mvarId eqFVarId symm subst) then
56+
/-
57+
Remark: `substCore` fails if the equation is of the form `x = x`
58+
We use `(tryToSkip := true)` to ensure we avoid unnecessary `Eq.rec`s in user code.
59+
Recall that `Eq.rec`s can negatively affect term reduction performance in the kernel and elaborator.
60+
See issue https://github.com/leanprover/lean4/issues/2552 for an example.
61+
-/
62+
if let some (subst, mvarId) ← observing? (substCore mvarId eqFVarId symm subst (tryToSkip := true)) then
5863
return some { mvarId, subst }
5964
else if (← isDefEq a b) then
6065
/- Skip equality -/

Diff for: src/lake/Lake/Build/Index.lean

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Copyright (c) 2022 Mac Malone. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Mac Malone
55
-/
6+
import Lake.Build.Targets
67
import Lake.Build.Executable
78
import Lake.Build.Topological
89

@@ -104,5 +105,8 @@ export BuildInfo (build)
104105
@[inline] protected def LeanExe.build (self : LeanExe) : BuildM (BuildJob FilePath) :=
105106
self.exe.build
106107

108+
@[inline] protected def LeanExeConfig.build (self : LeanExeConfig) : BuildM (BuildJob FilePath) := do
109+
(← self.get).build
110+
107111
@[inline] protected def LeanExe.fetch (self : LeanExe) : IndexBuildM (BuildJob FilePath) :=
108112
self.exe.fetch

Diff for: src/lake/Lake/Config/Package.lean

+21-30
Original file line numberDiff line numberDiff line change
@@ -90,32 +90,6 @@ structure PackageConfig extends WorkspaceConfig, LeanConfig where
9090
/-- An `Array` of target names to build whenever the package is used. -/
9191
extraDepTargets : Array Name := #[]
9292

93-
/--
94-
A post-`lake update` hook. The monadic action is run after a successful
95-
`lake update` execution on this package or one of its downstream dependents.
96-
Defaults to `none`.
97-
98-
As an example, Mathlib can use this feature to synchronize the Lean toolchain
99-
and run `cache get`:
100-
101-
```
102-
package mathlib where
103-
postUpdate? := some do
104-
let some pkg ← findPackage? `mathlib
105-
| error "mathlib is missing from workspace"
106-
let wsToolchainFile := (← getRootPackage).dir / "lean-toolchain"
107-
let mathlibToolchain ← IO.FS.readFile <| pkg.dir / "lean-toolchain"
108-
IO.FS.writeFile wsToolchainFile mathlibToolchain
109-
let some exe := pkg.findLeanExe? `cache
110-
| error s!"{pkg.name}: cache is missing from the package"
111-
let exeFile ← runBuild (exe.build >>= (·.await))
112-
let exitCode ← env exeFile.toString #["get"]
113-
if exitCode ≠ 0 then
114-
error s!"{pkg.name}: failed to fetch cache"
115-
```
116-
-/
117-
postUpdate? : Option (LakeT LogIO PUnit) := none
118-
11993
/--
12094
Whether to compile each of the package's module into a native shared library
12195
that is loaded whenever the module is imported. This speeds up evaluation of
@@ -197,6 +171,9 @@ deriving Inhabited
197171
/-! # Package -/
198172
--------------------------------------------------------------------------------
199173

174+
175+
declare_opaque_type OpaquePostUpdateHook (pkg : Name)
176+
200177
/-- A Lake package -- its location plus its configuration. -/
201178
structure Package where
202179
/-- The path to the package's directory. -/
@@ -231,6 +208,8 @@ structure Package where
231208
(i.e., on a bare `lake run` of the package).
232209
-/
233210
defaultScripts : Array Script := #[]
211+
/-- Post-`lake update` hooks for the package. -/
212+
postUpdateHooks : Array (OpaquePostUpdateHook config.name) := #[]
234213

235214
instance : Nonempty Package :=
236215
have : Inhabited Environment := Classical.inhabited_of_nonempty inferInstance
@@ -263,6 +242,22 @@ instance : CoeDep Package pkg (NPackage pkg.name) := ⟨⟨pkg, rfl⟩⟩
263242
/-- The package's name. -/
264243
abbrev NPackage.name (_ : NPackage n) := n
265244

245+
/--
246+
The type of a post-update hooks monad.
247+
`IO` equipped with logging ability and information about the Lake configuration.
248+
-/
249+
abbrev PostUpdateFn (pkgName : Name) := NPackage pkgName → LakeT LogIO PUnit
250+
251+
structure PostUpdateHook (pkgName : Name) where
252+
fn : PostUpdateFn pkgName
253+
deriving Inhabited
254+
255+
hydrate_opaque_type OpaquePostUpdateHook PostUpdateHook name
256+
257+
structure PostUpdateHookDecl where
258+
pkg : Name
259+
fn : PostUpdateFn pkg
260+
266261
namespace Package
267262

268263
/-- The package's direct dependencies. -/
@@ -289,10 +284,6 @@ namespace Package
289284
@[inline] def extraDepTargets (self : Package) : Array Name :=
290285
self.config.extraDepTargets
291286

292-
/-- The package's `postUpdate?` configuration. -/
293-
@[inline] def postUpdate? (self : Package) :=
294-
self.config.postUpdate?
295-
296287
/-- The package's `releaseRepo?` configuration. -/
297288
@[inline] def releaseRepo? (self : Package) : Option String :=
298289
self.config.releaseRepo?

Diff for: src/lake/Lake/DSL/Attributes.lean

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ initialize packageAttr : OrderedTagAttribute ←
1414
initialize packageDepAttr : OrderedTagAttribute ←
1515
registerOrderedTagAttribute `package_dep "mark a definition as a Lake package dependency"
1616

17+
initialize postUpdateAttr : OrderedTagAttribute ←
18+
registerOrderedTagAttribute `post_update "mark a definition as a Lake package post-update hook"
19+
1720
initialize scriptAttr : OrderedTagAttribute ←
1821
registerOrderedTagAttribute `script "mark a definition as a Lake script"
1922

Diff for: src/lake/Lake/DSL/DeclUtil.lean

+23-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Copyright (c) 2021 Mac Malone. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Mac Malone
55
-/
6+
import Lake.DSL.Config
67
import Lake.Util.Binder
78
import Lean.Parser.Command
89

@@ -24,15 +25,21 @@ def expandAttrs (attrs? : Option Attributes) : Array AttrInstance :=
2425
else
2526
#[]
2627

28+
syntax declField :=
29+
ident ":=" term
30+
2731
syntax structVal :=
28-
"{" manyIndent(group(Term.structInstField ", "?)) "}"
32+
"{" manyIndent(group(declField ", "?)) "}"
2933

3034
syntax declValDo :=
3135
ppSpace Term.do (Term.whereDecls)?
3236

3337
syntax declValStruct :=
3438
ppSpace structVal (Term.whereDecls)?
3539

40+
syntax declValWhere :=
41+
" where " sepByIndentSemicolon(declField) (Term.whereDecls)?
42+
3643
syntax declValTyped :=
3744
Term.typeSpec declValSimple
3845

@@ -43,7 +50,7 @@ syntax simpleDeclSig :=
4350
ident Term.typeSpec declValSimple
4451

4552
syntax structDeclSig :=
46-
ident (Command.whereStructInst <|> declValOptTyped <|> declValStruct)?
53+
ident (declValWhere <|> declValOptTyped <|> declValStruct)?
4754

4855
syntax bracketedSimpleBinder :=
4956
"(" ident (" : " term)? ")"
@@ -69,18 +76,25 @@ def fixName (id : Ident) : Option Name → Ident
6976
| some n => mkIdentFrom id n
7077
| none => id
7178

72-
def mkConfigStructDecl (name? : Option Name)
79+
def expandDeclField : TSyntax ``declField → MacroM (TSyntax ``Term.structInstField)
80+
| `(declField| $id :=%$tk $val) => `(Term.structInstField| $id:ident :=%$tk $val)
81+
| x => Macro.throwErrorAt x "ill-formed field declaration"
82+
83+
def mkConfigDecl (name? : Option Name)
7384
(doc? : Option DocComment) (attrs : Array AttrInstance) (ty : Term)
7485
: (spec : Syntax) → MacroM Syntax.Command
7586
| `(structDeclSig| $id:ident) =>
7687
`($[$doc?]? @[$attrs,*] abbrev $(fixName id name?) : $ty :=
7788
{name := $(quote id.getId)})
78-
| `(structDeclSig| $id:ident where $ds;* $[$wds?]?) =>
79-
`($[$doc?]? @[$attrs,*] abbrev $(fixName id name?) : $ty where
80-
name := $(quote id.getId); $ds;* $[$wds?]?)
81-
| `(structDeclSig| $id:ident $[: $ty?]? := $defn $[$wds?]?) =>
82-
`($[$doc?]? @[$attrs,*] abbrev $(fixName id name?) : $(ty?.getD ty) := $defn $[$wds?]?)
89+
| `(structDeclSig| $id:ident where $fs;* $[$wds?]?) => do
90+
let fields ← fs.getElems.mapM expandDeclField
91+
let defn ← `({ name := $(quote id.getId), $fields,* })
92+
`($[$doc?]? @[$attrs,*] abbrev $(fixName id name?) : $ty := $defn $[$wds?]?)
93+
| `(structDeclSig| $id:ident $[: $ty?]? :=%$defTk $defn $[$wds?]?) => do
94+
let notice ← withRef defTk `(#eval IO.eprintln s!" warning: {__dir__}: `:=` syntax for configurations has been deprecated")
95+
`($notice $[$doc?]? @[$attrs,*] abbrev $(fixName id name?) : $ty := $defn $[$wds?]?)
8396
| `(structDeclSig| $id:ident { $[$fs $[,]?]* } $[$wds?]?) => do
84-
let defn ← `({ name := $(quote id.getId), $fs,* })
97+
let fields ← fs.mapM expandDeclField
98+
let defn ← `({ name := $(quote id.getId), $fields,* })
8599
`($[$doc?]? @[$attrs,*] abbrev $(fixName id name?) : $ty := $defn $[$wds?]?)
86100
| stx => Macro.throwErrorAt stx "ill-formed configuration syntax"

0 commit comments

Comments
 (0)