From 2f51d5af491995f1048eb174c380533b5e4932ab Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Mon, 25 Sep 2023 11:33:14 +0200 Subject: [PATCH 01/71] chore: CI: add backport action --- .github/workflows/backport.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/backport.yml diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 000000000000..0ec179e26630 --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,26 @@ +name: Backport +on: + pull_request_target: + types: + - closed + - labeled + +jobs: + backport: + name: Backport + runs-on: ubuntu-latest + # Only react to merged PRs for security reasons. + # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. + if: > + github.event.pull_request.merged + && ( + github.event.action == 'closed' + || ( + github.event.action == 'labeled' + && contains(github.event.label.name, 'backport') + ) + ) + steps: + - uses: tibdex/backport@v2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} From decf7a042a84bebf50a73cd32b17df01263c8d8f Mon Sep 17 00:00:00 2001 From: tydeu Date: Mon, 25 Sep 2023 16:02:20 -0400 Subject: [PATCH 02/71] perf: lake: lazily acquire repo URL/tag in `:release` --- src/lake/Lake/Build/Package.lean | 12 ++++++++++-- src/lake/Lake/Config/Package.lean | 11 ----------- src/lake/Lake/Load/Main.lean | 4 ---- src/lake/Lake/Load/Materialize.lean | 5 ----- 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/lake/Lake/Build/Package.lean b/src/lake/Lake/Build/Package.lean index dec6f6b3d1a6..dccbc6b006fe 100644 --- a/src/lake/Lake/Build/Package.lean +++ b/src/lake/Lake/Build/Package.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Mac Malone. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mac Malone -/ +import Lake.Util.Git import Lake.Util.Sugar import Lake.Build.Common import Lake.Build.Targets @@ -46,8 +47,15 @@ def Package.extraDepFacetConfig : PackageFacetConfig extraDepFacet := /-- Download and unpack the package's prebuilt release archive (from GitHub). -/ def Package.fetchRelease (self : Package) : SchedulerM (BuildJob Unit) := Job.async do - let some (repoUrl, tag) := self.release? | do - logWarning "wanted prebuilt release, but release repository and tag was not known" + let repo := GitRepo.mk self.dir + let repoUrl? := self.releaseRepo? <|> self.remoteUrl? + let some repoUrl := repoUrl? <|> (← repo.getFilteredRemoteUrl?) | do + logWarning <| s!"{self.name}: wanted prebuilt release, " ++ + "but package's repository URL was not known; it may need to set `releaseRepo?`" + return ((), .nil) + let some tag ← repo.findTag? | do + logWarning <| s!"{self.name}: wanted prebuilt release, " ++ + "but could not find an associated tag for the package's revision" return ((), .nil) let url := s!"{repoUrl}/releases/download/{tag}/{self.buildArchive}" let logName := s!"{self.name}/{tag}/{self.buildArchive}" diff --git a/src/lake/Lake/Config/Package.lean b/src/lake/Lake/Config/Package.lean index a71c255c9ddd..a387bba7f266 100644 --- a/src/lake/Lake/Config/Package.lean +++ b/src/lake/Lake/Config/Package.lean @@ -183,8 +183,6 @@ structure Package where leanOpts : Options /-- The URL to this package's Git remote. -/ remoteUrl? : Option String := none - /-- The Git tag of this package. -/ - gitTag? : Option String := none /-- (Opaque references to) the package's direct dependencies. -/ opaqueDeps : Array OpaquePackage := #[] /-- Lean library configurations for the package. -/ @@ -269,15 +267,6 @@ namespace Package @[inline] def releaseRepo? (self : Package) : Option String := self.config.releaseRepo? -/-- -The package's URL × tag release. -Tries `releaseRepo?` first and then falls back to `remoteUrl?`. --/ -def release? (self : Package) : Option (String × String) := do - let url ← self.releaseRepo? <|> self.remoteUrl? - let tag ← self.gitTag? - return (url, tag) - /-- The package's `buildArchive?` configuration. -/ @[inline] def buildArchive? (self : Package) : Option String := self.config.buildArchive? diff --git a/src/lake/Lake/Load/Main.lean b/src/lake/Lake/Load/Main.lean index 65166d64541e..ee34a8f363c7 100644 --- a/src/lake/Lake/Load/Main.lean +++ b/src/lake/Lake/Load/Main.lean @@ -38,7 +38,6 @@ def loadDepPackage (wsDir : FilePath) (dep : MaterializedDep) return { dir, config, configEnv, leanOpts remoteUrl? := dep.remoteUrl? - gitTag? := dep.gitTag? } /-- @@ -103,12 +102,9 @@ def loadWorkspaceRoot (config : LoadConfig) : LogIO Workspace := do let configEnv ← importConfigFile config.rootDir config.rootDir config.configOpts config.leanOpts config.configFile config.reconfigure let pkgConfig ← IO.ofExcept <| PackageConfig.loadFromEnv configEnv config.leanOpts - let repo := GitRepo.mk config.rootDir let root := { configEnv, leanOpts := config.leanOpts dir := config.rootDir, config := pkgConfig - remoteUrl? := ← repo.getFilteredRemoteUrl? - gitTag? := ← repo.findTag? } return { root, lakeEnv := config.env diff --git a/src/lake/Lake/Load/Materialize.lean b/src/lake/Lake/Load/Materialize.lean index c01aae4a70ab..76058b80348f 100644 --- a/src/lake/Lake/Load/Materialize.lean +++ b/src/lake/Lake/Load/Materialize.lean @@ -74,7 +74,6 @@ structure MaterializedDep where /-- Path to the materialized package relative to the workspace's root directory. -/ relPkgDir : FilePath remoteUrl? : Option String - gitTag? : Option String manifestEntry : PackageEntry deriving Inhabited @@ -96,7 +95,6 @@ def Dependency.materialize (dep : Dependency) (inherited : Bool) return { relPkgDir remoteUrl? := none - gitTag? := ← (GitRepo.mk <| wsDir / relPkgDir).findTag? manifestEntry := .path dep.name dep.opts inherited relPkgDir } | .git url inputRev? subDir? => do @@ -109,7 +107,6 @@ def Dependency.materialize (dep : Dependency) (inherited : Bool) return { relPkgDir remoteUrl? := Git.filterUrl? url - gitTag? := ← repo.findTag? manifestEntry := .git dep.name dep.opts inherited url rev inputRev? subDir? } @@ -121,7 +118,6 @@ def PackageEntry.materialize (wsDir relPkgsDir : FilePath) (manifestEntry : Pack return { relPkgDir remoteUrl? := none - gitTag? := ← (GitRepo.mk <| wsDir / relPkgDir).findTag? manifestEntry } | .git name _opts _inherited url rev _inputRev? subDir? => do @@ -147,6 +143,5 @@ def PackageEntry.materialize (wsDir relPkgsDir : FilePath) (manifestEntry : Pack return { relPkgDir remoteUrl? := Git.filterUrl? url - gitTag? := ← repo.findTag? manifestEntry } From 4acdcc4c4063f28d04e1a6d3afa4f39919d80fd7 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Tue, 26 Sep 2023 03:38:59 +0200 Subject: [PATCH 03/71] doc: add token error change to RELEASES.md (#2579) --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 0315f00b0662..fa685d8168d5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -14,6 +14,8 @@ v4.2.0 (development in progress) v4.1.0 --------- +* The error positioning on missing tokens has been [improved](https://github.com/leanprover/lean4/pull/2393). In particular, this should make it easier to spot errors in incomplete tactic proofs. + * After elaborating a configuration file, Lake will now cache the configuration to a `lakefile.olean`. Subsequent runs of Lake will import this OLean instead of elaborating the configuration file. This provides a significant performance improvement (benchmarks indicate that using the OLean cuts Lake's startup time in half), but there are some important details to keep in mind: + Lake will regenerate this OLean after each modification to the `lakefile.lean` or `lean-toolchain`. You can also force a reconfigure by passing the new `--reconfigure` / `-R` option to `lake`. + Lake configuration options (i.e., `-K`) will be fixed at the moment of elaboration. Setting these options when `lake` is using the cached configuration will have no effect. To change options, run `lake` with `-R` / `--reconfigure`. From a5a150a86229e84f3ab3706fbdb2eb20dc22e144 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Tue, 26 Sep 2023 14:18:54 +1000 Subject: [PATCH 04/71] chore: begin development cycle for v4.3.0 (#2585) --- RELEASES.md | 6 +++++- src/CMakeLists.txt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index fa685d8168d5..49f9db7c034e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -7,9 +7,13 @@ only an expectation that breaking changes will be documented in this file. This file contains work-in-progress notes for the upcoming release, as well as previous stable releases. Please check the [releases](https://github.com/leanprover/lean4/releases) page for the current status of each version. -v4.2.0 (development in progress) +v4.3.0 (development in progress) --------- +v4.2.0 +--------- + +No breaking changes. v4.1.0 --------- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2c2425da5f94..edde6915184b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,7 @@ endif() include(ExternalProject) project(LEAN CXX C) set(LEAN_VERSION_MAJOR 4) -set(LEAN_VERSION_MINOR 2) +set(LEAN_VERSION_MINOR 3) set(LEAN_VERSION_PATCH 0) set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise. set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'") From e6fe3bee71f359c866a29766f774864577099778 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Tue, 26 Sep 2023 02:53:50 -0400 Subject: [PATCH 05/71] fix: hover term/tactic confusion --- .../Server/FileWorker/RequestHandling.lean | 3 +- tests/lean/interactive/hover.lean | 10 + .../lean/interactive/hover.lean.expected.out | 217 +++++++++--------- 3 files changed, 126 insertions(+), 104 deletions(-) diff --git a/src/Lean/Server/FileWorker/RequestHandling.lean b/src/Lean/Server/FileWorker/RequestHandling.lean index 4710a2b95e97..d04203f62ba5 100644 --- a/src/Lean/Server/FileWorker/RequestHandling.lean +++ b/src/Lean/Server/FileWorker/RequestHandling.lean @@ -62,7 +62,8 @@ def handleHover (p : HoverParams) let stack? := snap.stx.findStack? (·.getRange?.any (·.contains hoverPos)) let stxDoc? ← match stack? with | some stack => stack.findSomeM? fun (stx, _) => do - return (← findDocString? snap.env stx.getKind).map (·, stx.getRange?.get!) + let .node _ kind _ := stx | pure none + return (← findDocString? snap.env kind).map (·, stx.getRange?.get!) | none => pure none -- now try info tree diff --git a/tests/lean/interactive/hover.lean b/tests/lean/interactive/hover.lean index cc9e69cac5be..2c3aeb49891d 100644 --- a/tests/lean/interactive/hover.lean +++ b/tests/lean/interactive/hover.lean @@ -168,6 +168,8 @@ def foo.bar : Nat := 1 --^ textDocument/hover --^ textDocument/hover +end Bar + example : Nat → Nat → Nat := fun x y => --^ textDocument/hover @@ -205,6 +207,7 @@ example : Nat := Id.run do (← 1) #check (· + ·) --^ textDocument/hover --^ textDocument/hover +/-- my_intro tactic -/ macro "my_intro" x:(ident <|> "_") : tactic => match x with | `($x:ident) => `(tactic| intro $x:ident) @@ -216,9 +219,16 @@ example : α → α := by intro _; assumption --^ textDocument/hover example : α → α := by my_intro x; assumption --^ textDocument/hover + --v textDocument/hover example : α → α := by my_intro _; assumption --^ textDocument/hover +/-- my_intro term -/ +def my_intro : Nat := 1 + + --v textDocument/hover +example : α → α := by my_intro _; assumption + example : Nat → True := by intro x --^ textDocument/hover diff --git a/tests/lean/interactive/hover.lean.expected.out b/tests/lean/interactive/hover.lean.expected.out index de0490371aa1..ff621866146b 100644 --- a/tests/lean/interactive/hover.lean.expected.out +++ b/tests/lean/interactive/hover.lean.expected.out @@ -312,263 +312,274 @@ "end": {"line": 166, "character": 11}}, "contents": {"value": "```lean\nBar.foo.bar : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 171, "character": 6}} + "position": {"line": 173, "character": 6}} {"range": - {"start": {"line": 171, "character": 6}, "end": {"line": 171, "character": 7}}, + {"start": {"line": 173, "character": 6}, "end": {"line": 173, "character": 7}}, "contents": {"value": "```lean\nx : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 174, "character": 4}} + "position": {"line": 176, "character": 4}} [{"targetUri": "file://hover.lean", "targetSelectionRange": - {"start": {"line": 171, "character": 6}, - "end": {"line": 171, "character": 7}}, + {"start": {"line": 173, "character": 6}, + "end": {"line": 173, "character": 7}}, "targetRange": - {"start": {"line": 171, "character": 6}, - "end": {"line": 171, "character": 7}}, + {"start": {"line": 173, "character": 6}, + "end": {"line": 173, "character": 7}}, "originSelectionRange": - {"start": {"line": 174, "character": 4}, - "end": {"line": 174, "character": 5}}}] + {"start": {"line": 176, "character": 4}, + "end": {"line": 176, "character": 5}}}] {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 174, "character": 4}} + "position": {"line": 176, "character": 4}} {"range": - {"start": {"line": 174, "character": 4}, "end": {"line": 174, "character": 5}}, + {"start": {"line": 176, "character": 4}, "end": {"line": 176, "character": 5}}, "contents": {"value": "```lean\nx : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 178, "character": 12}} + "position": {"line": 180, "character": 12}} {"range": - {"start": {"line": 178, "character": 11}, - "end": {"line": 178, "character": 33}}, + {"start": {"line": 180, "character": 11}, + "end": {"line": 180, "character": 33}}, "contents": {"value": "enable the 'unused variables' linter", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 181, "character": 8}} + "position": {"line": 183, "character": 8}} {"range": - {"start": {"line": 181, "character": 8}, "end": {"line": 181, "character": 9}}, + {"start": {"line": 183, "character": 8}, "end": {"line": 183, "character": 9}}, "contents": {"value": "```lean\nx : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 184, "character": 8}} + "position": {"line": 186, "character": 8}} [{"targetUri": "file://hover.lean", "targetSelectionRange": - {"start": {"line": 181, "character": 8}, - "end": {"line": 181, "character": 9}}, + {"start": {"line": 183, "character": 8}, + "end": {"line": 183, "character": 9}}, "targetRange": - {"start": {"line": 181, "character": 8}, - "end": {"line": 181, "character": 9}}, + {"start": {"line": 183, "character": 8}, + "end": {"line": 183, "character": 9}}, "originSelectionRange": - {"start": {"line": 184, "character": 8}, - "end": {"line": 184, "character": 9}}}] + {"start": {"line": 186, "character": 8}, + "end": {"line": 186, "character": 9}}}] {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 184, "character": 8}} + "position": {"line": 186, "character": 8}} {"range": - {"start": {"line": 184, "character": 8}, "end": {"line": 184, "character": 9}}, + {"start": {"line": 186, "character": 8}, "end": {"line": 186, "character": 9}}, "contents": {"value": "```lean\nx : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 189, "character": 25}} + "position": {"line": 191, "character": 25}} {"range": - {"start": {"line": 189, "character": 25}, - "end": {"line": 189, "character": 26}}, + {"start": {"line": 191, "character": 25}, + "end": {"line": 191, "character": 26}}, "contents": {"value": "```lean\nn : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 192, "character": 2}} + "position": {"line": 194, "character": 2}} {"range": - {"start": {"line": 192, "character": 0}, "end": {"line": 192, "character": 9}}, + {"start": {"line": 194, "character": 0}, "end": {"line": 194, "character": 9}}, "contents": {"value": "`declModifiers` is the collection of modifiers on a declaration:\n* a doc comment `/-! ... -/`\n* a list of attributes `@[attr1, attr2]`\n* a visibility specifier, `private` or `protected`\n* `noncomputable`\n* `unsafe`\n* `partial` or `nonrec`\n\nAll modifiers are optional, and have to come in the listed order.\n\n`nestedDeclModifiers` is the same as `declModifiers`, but attributes are printed\non the same line as the declaration. It is used for declarations nested inside other syntax,\nsuch as inductive constructors, structure projections, and `let rec` / `where` definitions. ", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 198, "character": 2}} + "position": {"line": 200, "character": 2}} {"range": - {"start": {"line": 198, "character": 2}, - "end": {"line": 198, "character": 15}}, + {"start": {"line": 200, "character": 2}, + "end": {"line": 200, "character": 15}}, "contents": {"value": "`· tac` focuses on the main goal and tries to solve it using `tac`, or else fails. ", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 201, "character": 28}} + "position": {"line": 203, "character": 28}} {"range": - {"start": {"line": 201, "character": 27}, - "end": {"line": 201, "character": 32}}, + {"start": {"line": 203, "character": 27}, + "end": {"line": 203, "character": 32}}, "contents": {"value": "```lean\nId ℕ\n```\n***\nParentheses, used for grouping expressions (e.g., `a * (b + c)`).\nCan also be used for creating simple functions when combined with `·`. Here are some examples:\n - `(· + 1)` is shorthand for `fun x => x + 1`\n - `(· + ·)` is shorthand for `fun x y => x + y`\n - `(f · a b)` is shorthand for `fun x => f x a b`\n - `(h (· + 1) ·)` is shorthand for `fun x => h (fun y => y + 1) x`\n - also applies to other parentheses-like notations such as `(·, 1)`\n", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 204, "character": 8}} + "position": {"line": 206, "character": 8}} {"range": - {"start": {"line": 204, "character": 8}, "end": {"line": 204, "character": 9}}, + {"start": {"line": 206, "character": 8}, "end": {"line": 206, "character": 9}}, "contents": {"value": "```lean\n?m\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 204, "character": 10}} + "position": {"line": 206, "character": 10}} {"range": - {"start": {"line": 204, "character": 8}, - "end": {"line": 204, "character": 13}}, + {"start": {"line": 206, "character": 8}, + "end": {"line": 206, "character": 13}}, "contents": {"value": "```lean\n?m x✝¹ x✝\n```\n***\n`a + b` computes the sum of `a` and `b`.\nThe meaning of this notation is type-dependent. ", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 212, "character": 28}} + "position": {"line": 215, "character": 28}} {"range": - {"start": {"line": 212, "character": 28}, - "end": {"line": 212, "character": 29}}, + {"start": {"line": 215, "character": 28}, + "end": {"line": 215, "character": 29}}, "contents": {"value": "```lean\nx : α\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 214, "character": 28}} + "position": {"line": 217, "character": 28}} {"range": - {"start": {"line": 214, "character": 28}, - "end": {"line": 214, "character": 29}}, + {"start": {"line": 217, "character": 28}, + "end": {"line": 217, "character": 29}}, "contents": {"value": "```lean\nα\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 216, "character": 31}} + "position": {"line": 219, "character": 31}} {"range": - {"start": {"line": 216, "character": 31}, - "end": {"line": 216, "character": 32}}, + {"start": {"line": 219, "character": 31}, + "end": {"line": 219, "character": 32}}, "contents": {"value": "```lean\nx : α\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 218, "character": 31}} + "position": {"line": 222, "character": 22}} {"range": - {"start": {"line": 218, "character": 31}, - "end": {"line": 218, "character": 32}}, + {"start": {"line": 222, "character": 22}, + "end": {"line": 222, "character": 32}}, + "contents": {"value": "my_intro tactic ", "kind": "markdown"}} +{"textDocument": {"uri": "file://hover.lean"}, + "position": {"line": 222, "character": 31}} +{"range": + {"start": {"line": 222, "character": 31}, + "end": {"line": 222, "character": 32}}, "contents": {"value": "```lean\nα\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 222, "character": 8}} + "position": {"line": 229, "character": 22}} +{"range": + {"start": {"line": 229, "character": 22}, + "end": {"line": 229, "character": 32}}, + "contents": {"value": "my_intro tactic ", "kind": "markdown"}} +{"textDocument": {"uri": "file://hover.lean"}, + "position": {"line": 232, "character": 8}} {"range": - {"start": {"line": 222, "character": 8}, "end": {"line": 222, "character": 9}}, + {"start": {"line": 232, "character": 8}, "end": {"line": 232, "character": 9}}, "contents": {"value": "```lean\nx : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 225, "character": 4}} + "position": {"line": 235, "character": 4}} {"range": - {"start": {"line": 225, "character": 4}, "end": {"line": 225, "character": 8}}, + {"start": {"line": 235, "character": 4}, "end": {"line": 235, "character": 8}}, "contents": {"value": "```lean\nNat.zero : ℕ\n```\n***\n`Nat.zero`, normally written `0 : Nat`, is the smallest natural number.\nThis is one of the two constructors of `Nat`. \n***\n*import Init.Prelude*", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 228, "character": 4}} + "position": {"line": 238, "character": 4}} {"range": - {"start": {"line": 228, "character": 4}, "end": {"line": 228, "character": 8}}, + {"start": {"line": 238, "character": 4}, "end": {"line": 238, "character": 8}}, "contents": {"value": "```lean\nNat.succ (n : ℕ) : ℕ\n```\n***\nThe successor function on natural numbers, `succ n = n + 1`.\nThis is one of the two constructors of `Nat`. \n***\n*import Init.Prelude*", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 228, "character": 9}} + "position": {"line": 238, "character": 9}} {"range": - {"start": {"line": 228, "character": 9}, - "end": {"line": 228, "character": 10}}, + {"start": {"line": 238, "character": 9}, + "end": {"line": 238, "character": 10}}, "contents": {"value": "```lean\nx : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 232, "character": 8}} + "position": {"line": 242, "character": 8}} {"range": - {"start": {"line": 232, "character": 8}, "end": {"line": 232, "character": 9}}, + {"start": {"line": 242, "character": 8}, "end": {"line": 242, "character": 9}}, "contents": {"value": "```lean\nx : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 234, "character": 12}} + "position": {"line": 244, "character": 12}} {"range": - {"start": {"line": 234, "character": 12}, - "end": {"line": 234, "character": 13}}, + {"start": {"line": 244, "character": 12}, + "end": {"line": 244, "character": 13}}, "contents": {"value": "```lean\nx : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 236, "character": 4}} + "position": {"line": 246, "character": 4}} {"range": - {"start": {"line": 236, "character": 4}, "end": {"line": 236, "character": 8}}, + {"start": {"line": 246, "character": 4}, "end": {"line": 246, "character": 8}}, "contents": {"value": "```lean\nNat.zero : ℕ\n```\n***\n`Nat.zero`, normally written `0 : Nat`, is the smallest natural number.\nThis is one of the two constructors of `Nat`. \n***\n*import Init.Prelude*", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 239, "character": 9}} + "position": {"line": 249, "character": 9}} {"range": - {"start": {"line": 239, "character": 9}, - "end": {"line": 239, "character": 10}}, + {"start": {"line": 249, "character": 9}, + "end": {"line": 249, "character": 10}}, "contents": {"value": "```lean\nℕ\n```\n***\nA placeholder term, to be synthesized by unification. ", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 239, "character": 11}} + "position": {"line": 249, "character": 11}} {"range": - {"start": {"line": 239, "character": 11}, - "end": {"line": 239, "character": 13}}, + {"start": {"line": 249, "character": 11}, + "end": {"line": 249, "character": 13}}, "contents": {"value": "```lean\nih : True\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 244, "character": 6}} + "position": {"line": 254, "character": 6}} {"range": - {"start": {"line": 244, "character": 4}, "end": {"line": 244, "character": 9}}, + {"start": {"line": 254, "character": 4}, "end": {"line": 254, "character": 9}}, "contents": {"value": "```lean\nNat.zero : ℕ\n```\n***\n`Nat.zero`, normally written `0 : Nat`, is the smallest natural number.\nThis is one of the two constructors of `Nat`. \n***\n*import Init.Prelude*", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 244, "character": 15}} + "position": {"line": 254, "character": 15}} {"range": - {"start": {"line": 244, "character": 13}, - "end": {"line": 244, "character": 18}}, + {"start": {"line": 254, "character": 13}, + "end": {"line": 254, "character": 18}}, "contents": {"value": "```lean\nNat.zero : ℕ\n```\n***\n`Nat.zero`, normally written `0 : Nat`, is the smallest natural number.\nThis is one of the two constructors of `Nat`. \n***\n*import Init.Prelude*", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 247, "character": 6}} + "position": {"line": 257, "character": 6}} {"range": - {"start": {"line": 247, "character": 4}, "end": {"line": 247, "character": 9}}, + {"start": {"line": 257, "character": 4}, "end": {"line": 257, "character": 9}}, "contents": {"value": "```lean\nNat.succ (n : ℕ) : ℕ\n```\n***\nThe successor function on natural numbers, `succ n = n + 1`.\nThis is one of the two constructors of `Nat`. \n***\n*import Init.Prelude*", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 247, "character": 17}} + "position": {"line": 257, "character": 17}} {"range": - {"start": {"line": 247, "character": 15}, - "end": {"line": 247, "character": 20}}, + {"start": {"line": 257, "character": 15}, + "end": {"line": 257, "character": 20}}, "contents": {"value": "```lean\nNat.succ (n : ℕ) : ℕ\n```\n***\nThe successor function on natural numbers, `succ n = n + 1`.\nThis is one of the two constructors of `Nat`. \n***\n*import Init.Prelude*", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 250, "character": 27}} + "position": {"line": 260, "character": 27}} {"range": - {"start": {"line": 250, "character": 27}, - "end": {"line": 250, "character": 37}}, + {"start": {"line": 260, "character": 27}, + "end": {"line": 260, "character": 37}}, "contents": {"value": "```lean\nInhabited.mk.{u} {α : Sort u} (default : α) : Inhabited α\n```\n***\n*import Init.Prelude*", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 250, "character": 28}} + "position": {"line": 260, "character": 28}} {"range": - {"start": {"line": 250, "character": 28}, - "end": {"line": 250, "character": 36}}, + {"start": {"line": 260, "character": 28}, + "end": {"line": 260, "character": 36}}, "contents": {"value": "```lean\nNat.zero : ℕ\n```\n***\n`Nat.zero`, normally written `0 : Nat`, is the smallest natural number.\nThis is one of the two constructors of `Nat`. \n***\n*import Init.Prelude*", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 256, "character": 2}} + "position": {"line": 266, "character": 2}} {"range": - {"start": {"line": 256, "character": 2}, "end": {"line": 256, "character": 3}}, + {"start": {"line": 266, "character": 2}, "end": {"line": 266, "character": 3}}, "contents": {"value": "```lean\nlet x :=\n match 0 with\n | x => 0;\nℕ\n```\n***\nA placeholder term, to be synthesized by unification. ", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 259, "character": 4}} + "position": {"line": 269, "character": 4}} {"range": - {"start": {"line": 259, "character": 4}, "end": {"line": 259, "character": 8}}, + {"start": {"line": 269, "character": 4}, "end": {"line": 269, "character": 8}}, "contents": - {"value": "```lean\nBar.auto (o : ℕ := by exact 1) : ℕ\n```", - "kind": "markdown"}} + {"value": "```lean\nauto (o : ℕ := by exact 1) : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 264, "character": 22}} + "position": {"line": 274, "character": 22}} {"range": - {"start": {"line": 264, "character": 22}, - "end": {"line": 264, "character": 23}}, + {"start": {"line": 274, "character": 22}, + "end": {"line": 274, "character": 23}}, "contents": {"value": "```lean\nx : ℕ\n```", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, - "position": {"line": 264, "character": 13}} + "position": {"line": 274, "character": 13}} {"range": - {"start": {"line": 264, "character": 13}, - "end": {"line": 264, "character": 15}}, + {"start": {"line": 274, "character": 13}, + "end": {"line": 274, "character": 15}}, "contents": {"value": "```lean\n_e : 1 = x\n```", "kind": "markdown"}} From ae470e038eebb1b96d3bedbe78c2cd3b3a33503b Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Wed, 27 Sep 2023 03:57:40 +0200 Subject: [PATCH 06/71] docs: fix doc comment syntax in declModifiers doc comment (#2590) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hover on `declModifiers` says doc comments are `/-! … -/`, when it should say `/-- … -/`. --- src/Lean/Parser/Command.lean | 2 +- tests/lean/interactive/hover.lean.expected.out | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lean/Parser/Command.lean b/src/Lean/Parser/Command.lean index 9aedcd741791..5bad70f87e18 100644 --- a/src/Lean/Parser/Command.lean +++ b/src/Lean/Parser/Command.lean @@ -72,7 +72,7 @@ def «partial» := leading_parser "partial " def «nonrec» := leading_parser "nonrec " /-- `declModifiers` is the collection of modifiers on a declaration: -* a doc comment `/-! ... -/` +* a doc comment `/-- ... -/` * a list of attributes `@[attr1, attr2]` * a visibility specifier, `private` or `protected` * `noncomputable` diff --git a/tests/lean/interactive/hover.lean.expected.out b/tests/lean/interactive/hover.lean.expected.out index ff621866146b..4b06ae8dc3b1 100644 --- a/tests/lean/interactive/hover.lean.expected.out +++ b/tests/lean/interactive/hover.lean.expected.out @@ -374,7 +374,7 @@ {"start": {"line": 194, "character": 0}, "end": {"line": 194, "character": 9}}, "contents": {"value": - "`declModifiers` is the collection of modifiers on a declaration:\n* a doc comment `/-! ... -/`\n* a list of attributes `@[attr1, attr2]`\n* a visibility specifier, `private` or `protected`\n* `noncomputable`\n* `unsafe`\n* `partial` or `nonrec`\n\nAll modifiers are optional, and have to come in the listed order.\n\n`nestedDeclModifiers` is the same as `declModifiers`, but attributes are printed\non the same line as the declaration. It is used for declarations nested inside other syntax,\nsuch as inductive constructors, structure projections, and `let rec` / `where` definitions. ", + "`declModifiers` is the collection of modifiers on a declaration:\n* a doc comment `/-- ... -/`\n* a list of attributes `@[attr1, attr2]`\n* a visibility specifier, `private` or `protected`\n* `noncomputable`\n* `unsafe`\n* `partial` or `nonrec`\n\nAll modifiers are optional, and have to come in the listed order.\n\n`nestedDeclModifiers` is the same as `declModifiers`, but attributes are printed\non the same line as the declaration. It is used for declarations nested inside other syntax,\nsuch as inductive constructors, structure projections, and `let rec` / `where` definitions. ", "kind": "markdown"}} {"textDocument": {"uri": "file://hover.lean"}, "position": {"line": 200, "character": 2}} From 75f91f372c19522a645dc3e5abb8455c2edcff22 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 27 Sep 2023 18:20:48 +1000 Subject: [PATCH 07/71] chore: add release note about lake startup time (#2597) --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 49f9db7c034e..04401f41ab6f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,7 +13,7 @@ v4.3.0 (development in progress) v4.2.0 --------- -No breaking changes. +* Improvements to Lake startup time ([#2572](https://github.com/leanprover/lean4/pull/2572), [#2573](https://github.com/leanprover/lean4/pull/2573)) v4.1.0 --------- From 06e057758e3d63f286b023e3f6ef0468d7b0441e Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Sun, 24 Sep 2023 17:39:59 +0200 Subject: [PATCH 08/71] chore: Remove unused variables from kernel when I build lean locally, I get a nice and warning-free build experience with the exception of these two unused variables. They can probably go? --- src/kernel/inductive.cpp | 2 -- src/library/compiler/csimp.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/kernel/inductive.cpp b/src/kernel/inductive.cpp index de61345659a5..1bf7ba7789da 100644 --- a/src/kernel/inductive.cpp +++ b/src/kernel/inductive.cpp @@ -614,7 +614,6 @@ class add_inductive_fn { d_idx++; } /* First, populate the field m_minors */ - unsigned minor_idx = 1; d_idx = 0; for (inductive_type const & ind_type : m_ind_types) { name ind_type_name = ind_type.get_name(); @@ -666,7 +665,6 @@ class add_inductive_fn { name minor_name = cnstr_name.replace_prefix(ind_type_name, name()); expr minor = mk_local_decl(minor_name, minor_ty); m_rec_infos[d_idx].m_minors.push_back(minor); - minor_idx++; } d_idx++; } diff --git a/src/library/compiler/csimp.cpp b/src/library/compiler/csimp.cpp index 84ffd974eb8b..252d87807ac4 100644 --- a/src/library/compiler/csimp.cpp +++ b/src/library/compiler/csimp.cpp @@ -302,12 +302,10 @@ class csimp_fn { } expr get_minor_body(expr e, buffer & xs) { - unsigned i = 0; while (is_lambda(e)) { expr d = instantiate_rev(binding_domain(e), xs.size(), xs.data()); expr x = m_lctx.mk_local_decl(ngen(), binding_name(e), d, binding_info(e)); xs.push_back(x); - i++; e = binding_body(e); } return instantiate_rev(e, xs.size(), xs.data()); From e6292bc0b890aed51447c1f6ef1cd503bd3abf0f Mon Sep 17 00:00:00 2001 From: Denis Gorbachev <829578+DenisGorbachev@users.noreply.github.com> Date: Sat, 30 Sep 2023 18:51:35 +0700 Subject: [PATCH 09/71] doc: fix docstring typos (#2605) * lake: fix a typo in `get_config?` syntax doc * fix a typo in `withImporting` doc --- src/Lean/ImportingFlag.lean | 2 +- src/lake/Lake/DSL/Config.lean | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lean/ImportingFlag.lean b/src/Lean/ImportingFlag.lean index 2a43538dd9b9..16370c0f9495 100644 --- a/src/Lean/ImportingFlag.lean +++ b/src/Lean/ImportingFlag.lean @@ -42,7 +42,7 @@ the `initialize` command to update global references. IMPORTANT: There is no semaphore controlling the access to these global references. We assume these global references are updated by a single execution thread. This is true in the Lean frontend where we process the `import` commands at the beginning -of the execution only. Users must make sure that `importModules` is used, there is only +of the execution only. Users must make sure that when `importModules` is used, there is only one execution thread accessing the global references. -/ def withImporting (x : IO α) : IO α := diff --git a/src/lake/Lake/DSL/Config.lean b/src/lake/Lake/DSL/Config.lean index 05c09499ec08..1ea682f2b70d 100644 --- a/src/lake/Lake/DSL/Config.lean +++ b/src/lake/Lake/DSL/Config.lean @@ -40,7 +40,7 @@ def elabDirConst : TermElab := fun stx expectedType? => do /-- A macro that expands to the specified configuration option (or `none`, -if not the option has not been set) during the Lakefile's elaboration. +if the option has not been set) during the Lakefile's elaboration. Configuration arguments are set either via the Lake CLI (by the `-K` option) or via the `with` clause in a `require` statement. From 8c0f0b5250eef7130522b08263eff455d413ad64 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Mon, 2 Oct 2023 06:38:54 -0400 Subject: [PATCH 10/71] docs: update RELEASES.md for #2502 (#2606) --- RELEASES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 04401f41ab6f..b826d02cd66a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -14,6 +14,9 @@ v4.2.0 --------- * Improvements to Lake startup time ([#2572](https://github.com/leanprover/lean4/pull/2572), [#2573](https://github.com/leanprover/lean4/pull/2573)) +* `refine e` now replaces the main goal with metavariables which were created during elaboration of `e` and no longer captures pre-existing metavariables that occur in `e` ([#2502](https://github.com/leanprover/lean4/pull/2502)). + * This is accomplished via changes to `withCollectingNewGoalsFrom`, which also affects `elabTermWithHoles`, `refine'`, `calc` (tactic), and `specialize`. Likewise, all of these now only include newly-created metavariables in their output. + * Previously, both newly-created and pre-existing metavariables occurring in `e` were returned inconsistently in different edge cases, causing duplicated goals in the infoview (issue [#2495](https://github.com/leanprover/lean4/issues/2495)), erroneously closed goals (issue [#2434](https://github.com/leanprover/lean4/issues/2434)), and unintuitive behavior due to `refine e` capturing previously-created goals appearing unexpectedly in `e` (no issue; see PR). v4.1.0 --------- From 4b47462ccc1af725add7c157adb8101e3c6b4c92 Mon Sep 17 00:00:00 2001 From: Denis Gorbachev <829578+DenisGorbachev@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:59:20 +0700 Subject: [PATCH 11/71] refactor: remove redundant let --- src/Lean/Environment.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Lean/Environment.lean b/src/Lean/Environment.lean index a083b0e6e4f3..a4a9ad16f7bd 100644 --- a/src/Lean/Environment.lean +++ b/src/Lean/Environment.lean @@ -792,7 +792,6 @@ def finalizeImport (s : ImportState) (imports : Array Import) (opts : Options) ( @[export lean_import_modules] def importModules (imports : Array Import) (opts : Options) (trustLevel : UInt32 := 0) : IO Environment := profileitIO "import" opts do - let imports := imports for imp in imports do if imp.module matches .anonymous then throw <| IO.userError "import failed, trying to import module with anonymous name" From 842881e1375b07e6d880bf26b6331c61ed724360 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Mon, 2 Oct 2023 15:03:19 +0200 Subject: [PATCH 12/71] fix: default for `MACOSX_DEPLOYMENT_TARGET` (#2598) Co-authored-by: Scott Morrison --- src/Leanc.lean | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Leanc.lean b/src/Leanc.lean index f45445ae6d16..c516636efa8c 100644 --- a/src/Leanc.lean +++ b/src/Leanc.lean @@ -20,6 +20,13 @@ Interesting options: | none => pure <| (← IO.appDir).parent.get! let rootify s := s.replace "ROOT" root.toString + -- It is difficult to identify the correct minor version here, leading to linking warnings like: + -- `ld64.lld: warning: /usr/lib/system/libsystem_kernel.dylib has version 13.5.0, which is newer than target minimum of 13.0.0` + -- In order to suppress these we set the MACOSX_DEPLOYMENT_TARGET variable into the far future. + let env := match (← IO.getEnv "MACOSX_DEPLOYMENT_TARGET") with + | some _ => #[] + | none => #[("MACOSX_DEPLOYMENT_TARGET", "99.0")] + -- let compileOnly := args.contains "-c" let linkStatic := !args.contains "-shared" @@ -50,5 +57,5 @@ Interesting options: let args := args.filter (!·.isEmpty) |>.map rootify if args.contains "-v" then IO.eprintln s!"{cc} {" ".intercalate args.toList}" - let child ← IO.Process.spawn { cmd := cc, args } + let child ← IO.Process.spawn { cmd := cc, args, env } child.wait From 1572e55f06268a87bc82249f7c4c52dec8f5c3cf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:03:48 +0000 Subject: [PATCH 13/71] doc: update changelog --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index b826d02cd66a..3f84fd947e3f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,6 +10,8 @@ Please check the [releases](https://github.com/leanprover/lean4/releases) page f v4.3.0 (development in progress) --------- +* [Fix linker warnings on macOS](https://github.com/leanprover/lean4/pull/2598). + v4.2.0 --------- From 6b93f05cd172640253ad1ed27935167e5a3af981 Mon Sep 17 00:00:00 2001 From: Arthur Adjedj Date: Tue, 3 Oct 2023 04:17:13 +0200 Subject: [PATCH 14/71] feat : derive `DecidableEq` for mutual inductives (#2591) * feat : derive `DecidableEq` for mutual inductives * doc: document `RELEASES.md` --------- --- RELEASES.md | 1 + src/Lean/Elab/Deriving/DecEq.lean | 39 +++++++++------ tests/lean/decEqMutualInductives.lean | 27 ++++++++++ .../decEqMutualInductives.lean.expected.out | 50 +++++++++++++++++++ 4 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 tests/lean/decEqMutualInductives.lean create mode 100644 tests/lean/decEqMutualInductives.lean.expected.out diff --git a/RELEASES.md b/RELEASES.md index 3f84fd947e3f..7aa09c12e0fb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,6 +10,7 @@ Please check the [releases](https://github.com/leanprover/lean4/releases) page f v4.3.0 (development in progress) --------- +* The derive handler for `DecidableEq` [now handles](https://github.com/leanprover/lean4/pull/2591) mutual inductive types. * [Fix linker warnings on macOS](https://github.com/leanprover/lean4/pull/2598). v4.2.0 diff --git a/src/Lean/Elab/Deriving/DecEq.lean b/src/Lean/Elab/Deriving/DecEq.lean index 9e655ccddf0e..7be9b90ab40b 100644 --- a/src/Lean/Elab/Deriving/DecEq.lean +++ b/src/Lean/Elab/Deriving/DecEq.lean @@ -15,12 +15,12 @@ open Meta def mkDecEqHeader (indVal : InductiveVal) : TermElabM Header := do mkHeader `DecidableEq 2 indVal -def mkMatch (header : Header) (indVal : InductiveVal) (auxFunName : Name) : TermElabM Term := do +def mkMatch (ctx : Context) (header : Header) (indVal : InductiveVal) : TermElabM Term := do let discrs ← mkDiscrs header indVal let alts ← mkAlts `(match $[$discrs],* with $alts:matchAlt*) where - mkSameCtorRhs : List (Ident × Ident × Bool × Bool) → TermElabM Term + mkSameCtorRhs : List (Ident × Ident × Option Name × Bool) → TermElabM Term | [] => ``(isTrue rfl) | (a, b, recField, isProof) :: todo => withFreshMacroScope do let rhs ← if isProof then @@ -30,7 +30,7 @@ where by subst h; exact $(← mkSameCtorRhs todo):term else isFalse (by intro n; injection n; apply h _; assumption)) - if recField then + if let some auxFunName := recField then -- add local instance for `a = b` using the function being defined `auxFunName` `(let inst := $(mkIdent auxFunName) $a $b; $rhs) else @@ -67,8 +67,11 @@ where let b := mkIdent (← mkFreshUserName `b) ctorArgs1 := ctorArgs1.push a ctorArgs2 := ctorArgs2.push b - let recField := (← inferType x).isAppOf indVal.name - let isProof := (← inferType (← inferType x)).isProp + let indValNum := + ctx.typeInfos.findIdx? + ((← inferType x).isAppOf ∘ ConstantVal.name ∘ InductiveVal.toConstantVal) + let recField := indValNum.map (ctx.auxFunNames[·]!) + let isProof := (← inferType (← inferType x)).isProp todo := todo.push (a, b, recField, isProof) patterns := patterns.push (← `(@$(mkIdent ctorName₁):ident $ctorArgs1:term*)) patterns := patterns.push (← `(@$(mkIdent ctorName₁):ident $ctorArgs2:term*)) @@ -81,18 +84,24 @@ where alts := alts.push (← `(matchAltExpr| | $[$patterns:term],* => $rhs:term)) return alts -def mkAuxFunction (ctx : Context) : TermElabM Syntax := do - let auxFunName := ctx.auxFunNames[0]! - let indVal :=ctx.typeInfos[0]! - let header ← mkDecEqHeader indVal - let mut body ← mkMatch header indVal auxFunName - let binders := header.binders - let type ← `(Decidable ($(mkIdent header.targetNames[0]!) = $(mkIdent header.targetNames[1]!))) +def mkAuxFunction (ctx : Context) (auxFunName : Name) (indVal : InductiveVal): TermElabM (TSyntax `command) := do + let header ← mkDecEqHeader indVal + let body ← mkMatch ctx header indVal + let binders := header.binders + let type ← `(Decidable ($(mkIdent header.targetNames[0]!) = $(mkIdent header.targetNames[1]!))) `(private def $(mkIdent auxFunName):ident $binders:bracketedBinder* : $type:term := $body:term) +def mkAuxFunctions (ctx : Context) : TermElabM (TSyntax `command) := do + let mut res : Array (TSyntax `command) := #[] + for i in [:ctx.auxFunNames.size] do + let auxFunName := ctx.auxFunNames[i]! + let indVal := ctx.typeInfos[i]! + res := res.push (← mkAuxFunction ctx auxFunName indVal) + `(command| mutual $[$res:command]* end) + def mkDecEqCmds (indVal : InductiveVal) : TermElabM (Array Syntax) := do let ctx ← mkContext "decEq" indVal.name - let cmds := #[← mkAuxFunction ctx] ++ (← mkInstanceCmds ctx `DecidableEq #[indVal.name] (useAnonCtor := false)) + let cmds := #[← mkAuxFunctions ctx] ++ (← mkInstanceCmds ctx `DecidableEq #[indVal.name] (useAnonCtor := false)) trace[Elab.Deriving.decEq] "\n{cmds}" return cmds @@ -174,9 +183,7 @@ def mkDecEqEnum (declName : Name) : CommandElabM Unit := do elabCommand cmd def mkDecEqInstanceHandler (declNames : Array Name) : CommandElabM Bool := do - if declNames.size != 1 then - return false -- mutually inductive types are not supported yet - else if (← isEnumType declNames[0]!) then + if (← isEnumType declNames[0]!) then mkDecEqEnum declNames[0]! return true else diff --git a/tests/lean/decEqMutualInductives.lean b/tests/lean/decEqMutualInductives.lean new file mode 100644 index 000000000000..fbe0af7e9113 --- /dev/null +++ b/tests/lean/decEqMutualInductives.lean @@ -0,0 +1,27 @@ +/-! Verify that the derive handler for `DecidableEq` handles mutual inductive types-/ + +-- Print the generated derivations +set_option trace.Elab.Deriving.decEq true + +mutual +inductive Tree : Type := + | node : ListTree → Tree + +inductive ListTree : Type := + | nil : ListTree + | cons : Tree → ListTree → ListTree + deriving DecidableEq +end + +mutual +inductive Foo₁ : Type := + | foo₁₁ : Foo₁ + | foo₁₂ : Foo₂ → Foo₁ +deriving DecidableEq + +inductive Foo₂ : Type := + | foo₂ : Foo₃ → Foo₂ + +inductive Foo₃ : Type := + | foo₃ : Foo₁ → Foo₃ +end diff --git a/tests/lean/decEqMutualInductives.lean.expected.out b/tests/lean/decEqMutualInductives.lean.expected.out new file mode 100644 index 000000000000..ed660187e7bb --- /dev/null +++ b/tests/lean/decEqMutualInductives.lean.expected.out @@ -0,0 +1,50 @@ +[Elab.Deriving.decEq] + [mutual + private def decEqTree✝ (x✝ : @Tree✝) (x✝¹ : @Tree✝) : Decidable✝ (x✝ = x✝¹) := + match x✝, x✝¹ with + | @Tree.node a✝, @Tree.node b✝ => + let inst✝ := decEqListTree✝ a✝ b✝; + if h✝ : a✝ = b✝ then by subst h✝; exact isTrue✝ rfl✝ + else isFalse✝ (by intro n✝; injection n✝; apply h✝ _; assumption) + private def decEqListTree✝ (x✝² : @ListTree✝) (x✝³ : @ListTree✝) : Decidable✝ (x✝² = x✝³) := + match x✝², x✝³ with + | @ListTree.nil, @ListTree.nil => isTrue✝¹ rfl✝¹ + | ListTree.nil .., ListTree.cons .. => isFalse✝¹ (by intro h✝¹; injection h✝¹) + | ListTree.cons .., ListTree.nil .. => isFalse✝¹ (by intro h✝¹; injection h✝¹) + | @ListTree.cons a✝¹ a✝², @ListTree.cons b✝¹ b✝² => + let inst✝¹ := decEqTree✝ a✝¹ b✝¹; + if h✝² : a✝¹ = b✝¹ then by subst h✝²; + exact + let inst✝² := decEqListTree✝ a✝² b✝²; + if h✝³ : a✝² = b✝² then by subst h✝³; exact isTrue✝² rfl✝² + else isFalse✝² (by intro n✝¹; injection n✝¹; apply h✝³ _; assumption) + else isFalse✝³ (by intro n✝²; injection n✝²; apply h✝² _; assumption) + end, + instance : DecidableEq✝ (@ListTree✝) := + decEqListTree✝] +[Elab.Deriving.decEq] + [mutual + private def decEqFoo₁✝ (x✝ : @Foo₁✝) (x✝¹ : @Foo₁✝) : Decidable✝ (x✝ = x✝¹) := + match x✝, x✝¹ with + | @Foo₁.foo₁₁, @Foo₁.foo₁₁ => isTrue✝ rfl✝ + | Foo₁.foo₁₁ .., Foo₁.foo₁₂ .. => isFalse✝ (by intro h✝; injection h✝) + | Foo₁.foo₁₂ .., Foo₁.foo₁₁ .. => isFalse✝ (by intro h✝; injection h✝) + | @Foo₁.foo₁₂ a✝, @Foo₁.foo₁₂ b✝ => + let inst✝ := decEqFoo₂✝ a✝ b✝; + if h✝¹ : a✝ = b✝ then by subst h✝¹; exact isTrue✝¹ rfl✝¹ + else isFalse✝¹ (by intro n✝; injection n✝; apply h✝¹ _; assumption) + private def decEqFoo₂✝ (x✝² : @Foo₂✝) (x✝³ : @Foo₂✝) : Decidable✝ (x✝² = x✝³) := + match x✝², x✝³ with + | @Foo₂.foo₂ a✝¹, @Foo₂.foo₂ b✝¹ => + let inst✝¹ := decEqFoo₃✝ a✝¹ b✝¹; + if h✝² : a✝¹ = b✝¹ then by subst h✝²; exact isTrue✝² rfl✝² + else isFalse✝² (by intro n✝¹; injection n✝¹; apply h✝² _; assumption) + private def decEqFoo₃✝ (x✝⁴ : @Foo₃✝) (x✝⁵ : @Foo₃✝) : Decidable✝ (x✝⁴ = x✝⁵) := + match x✝⁴, x✝⁵ with + | @Foo₃.foo₃ a✝², @Foo₃.foo₃ b✝² => + let inst✝² := decEqFoo₁✝ a✝² b✝²; + if h✝³ : a✝² = b✝² then by subst h✝³; exact isTrue✝³ rfl✝³ + else isFalse✝³ (by intro n✝²; injection n✝²; apply h✝³ _; assumption) + end, + instance : DecidableEq✝ (@Foo₁✝) := + decEqFoo₁✝] From 44bc68bdc6052d6db6017f6104634574eea76740 Mon Sep 17 00:00:00 2001 From: Alex J Best Date: Wed, 4 Oct 2023 01:12:43 +0200 Subject: [PATCH 15/71] fix: withLocation should use withMainContext for target (#2607) --- src/Lean/Elab/Tactic/Location.lean | 2 +- tests/lean/withLocation.lean | 15 +++++++++++++++ tests/lean/withLocation.lean.expected.out | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/lean/withLocation.lean create mode 100644 tests/lean/withLocation.lean.expected.out diff --git a/src/Lean/Elab/Tactic/Location.lean b/src/Lean/Elab/Tactic/Location.lean index 6e9134d16e5e..6276f584ca0c 100644 --- a/src/Lean/Elab/Tactic/Location.lean +++ b/src/Lean/Elab/Tactic/Location.lean @@ -49,7 +49,7 @@ def withLocation (loc : Location) (atLocal : FVarId → TacticM Unit) (atTarget let fvarId ← getFVarId hyp atLocal fvarId if type then - atTarget + withMainContext atTarget | Location.wildcard => let worked ← tryTactic <| withMainContext <| atTarget withMainContext do diff --git a/tests/lean/withLocation.lean b/tests/lean/withLocation.lean new file mode 100644 index 000000000000..a0f378575a8b --- /dev/null +++ b/tests/lean/withLocation.lean @@ -0,0 +1,15 @@ +import Lean + +open Lean Elab Tactic +elab "test" : tactic => do + withLocation (.targets #[] true) (fun _ => return ()) + do + let some (_, lhs, _) := (← getMainTarget).eq? | failure + logInfo <| ← FVarId.getUserName (lhs.fvarId!) + (fun _ => return ()) + +example : 1 = 1 := by + let t := 1 + show t = 1 + test + sorry diff --git a/tests/lean/withLocation.lean.expected.out b/tests/lean/withLocation.lean.expected.out new file mode 100644 index 000000000000..e6bba11d86c7 --- /dev/null +++ b/tests/lean/withLocation.lean.expected.out @@ -0,0 +1,2 @@ +t +withLocation.lean:11:0-11:7: warning: declaration uses 'sorry' From 83c7c29075d58c89e6aa12acbc8823fbb2a4d7c5 Mon Sep 17 00:00:00 2001 From: kuruczgy <57020850+kuruczgy@users.noreply.github.com> Date: Wed, 4 Oct 2023 02:51:22 +0200 Subject: [PATCH 16/71] fix: XML parsing bugs (#2601) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: make XML parser handle trailing whitespace in opening tags * fix: make XML parser handle comments correctly --------- Co-authored-by: György Kurucz --- src/Lean/Data/Xml/Parser.lean | 4 ++-- tests/lean/xmlParsing.lean | 10 ++++++++++ tests/lean/xmlParsing.lean.expected.out | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/lean/xmlParsing.lean create mode 100644 tests/lean/xmlParsing.lean.expected.out diff --git a/src/Lean/Data/Xml/Parser.lean b/src/Lean/Data/Xml/Parser.lean index 8b8dd40f415b..7b8d5b0a8fc9 100644 --- a/src/Lean/Data/Xml/Parser.lean +++ b/src/Lean/Data/Xml/Parser.lean @@ -119,7 +119,7 @@ def XMLdecl : Parsec Unit := do def Comment : Parsec String := let notDash := Char.toString <$> satisfy (λ c => c ≠ '-') skipString "" diff --git a/tests/lean/xmlParsing.lean.expected.out b/tests/lean/xmlParsing.lean.expected.out new file mode 100644 index 000000000000..bede94e91476 --- /dev/null +++ b/tests/lean/xmlParsing.lean.expected.out @@ -0,0 +1,2 @@ +ok: +ok: From 7dc1618ca532bc57ee452c9a47eafb01afa75bc3 Mon Sep 17 00:00:00 2001 From: Alexander Bentkamp Date: Wed, 4 Oct 2023 09:04:20 +0200 Subject: [PATCH 17/71] feat: Web Assembly Build (#2599) Co-authored-by: Rujia Liu --- .github/workflows/ci.yml | 24 +++++++++++++++++++-- CMakeLists.txt | 25 ++++++---------------- src/CMakeLists.txt | 37 +++++++++++++++++++-------------- src/bin/lean.in | 4 ++++ src/include/lean/lean.h | 4 ++-- src/lean.mk.in | 2 +- src/library/module.cpp | 6 +++++- src/runtime/io.cpp | 4 +++- src/runtime/stack_overflow.cpp | 6 +----- src/runtime/stackinfo.cpp | 12 +++++++++++ src/shell/CMakeLists.txt | 8 +++++-- src/stdlib.make.in | 10 ++++----- stage0/src/CMakeLists.txt | 37 +++++++++++++++++++-------------- stage0/src/library/module.cpp | 6 +++++- stage0/src/shell/CMakeLists.txt | 10 +++++++-- stage0/src/stdlib.make.in | 10 ++++----- tests/common.sh | 4 ++-- 17 files changed, 129 insertions(+), 80 deletions(-) create mode 100755 src/bin/lean.in diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cdf7ba18dd8b..f686629527d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -168,6 +168,15 @@ jobs: shell: nix-shell --arg pkgsDist "import (fetchTarball \"channel:nixos-19.03\") {{ localSystem.config = \"aarch64-unknown-linux-gnu\"; }}" --run "bash -euxo pipefail {0}" llvm-url: https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-linux-gnu.tar.zst prepare-llvm: EXTRA_FLAGS=--target=aarch64-unknown-linux-gnu ../script/prepare-llvm-linux.sh lean-llvm-aarch64-* lean-llvm-x86_64-* + - name: Web Assembly + os: ubuntu-latest + # Build a native 32bit binary in stage0 and use it to compile the oleans and the wasm build + CMAKE_OPTIONS: -DCMAKE_C_COMPILER_WORKS=1 -DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_CMAKE_CXX_COMPILER=clang++ -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_EXECUTABLE_SUFFIX="" -DUSE_GMP=OFF -DMMAP=OFF -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DCMAKE_AR=../emsdk/emsdk-main/upstream/emscripten/emar -DCMAKE_TOOLCHAIN_FILE=../emsdk/emsdk-main/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake + wasm: true + cross: true + shell: bash -euxo pipefail {0} + # Just a few selected test because wasm is slow + CTEST_OPTIONS: -R "leantest_1007\.lean|leantest_Format\.lean|leanruntest\_1037.lean|leanruntest_ac_rfl\.lean" # complete all jobs fail-fast: false name: ${{ matrix.name }} @@ -192,7 +201,7 @@ jobs: uses: cachix/install-nix-action@v18 with: install_url: https://releases.nixos.org/nix/nix-2.12.0/install - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' && !matrix.wasm - name: Install MSYS2 uses: msys2/setup-msys2@v2 with: @@ -204,6 +213,17 @@ jobs: run: | brew install ccache tree zstd coreutils gmp if: matrix.os == 'macos-latest' + - name: Setup emsdk + uses: mymindstorm/setup-emsdk@v11 + with: + version: 3.1.44 + actions-cache-folder: emsdk + if: matrix.wasm + - name: Install 32bit c libs + run: | + sudo apt-get update + sudo apt-get install -y gcc-multilib g++-multilib ccache + if: matrix.wasm - name: Cache uses: actions/cache@v3 with: @@ -280,7 +300,7 @@ jobs: ulimit -c unlimited # coredumps # exclude nonreproducible test ctest -j4 --output-on-failure ${{ matrix.CTEST_OPTIONS }} < /dev/null - if: ${{ !matrix.cross }} + if: matrix.wasm || !matrix.cross - name: Check Test Binary run: ${{ matrix.binary-check }} tests/compiler/534.lean.out if: ${{ !matrix.cross }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e6c7bcc764d..271ef9c4cdd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,23 +26,10 @@ endforeach() include(ExternalProject) project(LEAN CXX C) -if("${CMAKE_SYSTEM_NAME}" MATCHES "Emscripten") - # For Emscripten, we build GMP before any of the stages and reuse it in all of them. - set(GMP_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/gmp-root) - set(EMSCRIPTEN_FLAGS "-s ALLOW_MEMORY_GROWTH=1 -s MAIN_MODULE=1 -O3") - ExternalProject_Add( - gmp - URL https://gmplib.org/download/gmp/gmp-6.2.1.tar.bz2 - URL_HASH SHA256=eae9326beb4158c386e39a356818031bd28f3124cf915f8c5b1dc4c7a36b4d7c - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND emconfigure ./configure "CFLAGS=${EMSCRIPTEN_FLAGS}" --host=wasm32-unknown-emscripten --disable-assembly --prefix=${GMP_INSTALL_PREFIX} - BUILD_COMMAND emmake make -j4 - INSTALL_COMMAND emmake make install - ) - set(EXTRA_DEPENDS "gmp") - list(APPEND CL_ARGS "-DGMP_INSTALL_PREFIX=${GMP_INSTALL_PREFIX}") - list(APPEND PLATFORM_ARGS "-DGMP_INSTALL_PREFIX=${GMP_INSTALL_PREFIX}") +if(NOT (DEFINED STAGE0_CMAKE_EXECUTABLE_SUFFIX)) + set(STAGE0_CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}") endif() + ExternalProject_add(stage0 SOURCE_DIR "${LEAN_SOURCE_DIR}/stage0" SOURCE_SUBDIR src @@ -57,7 +44,7 @@ ExternalProject_add(stage1 SOURCE_DIR "${LEAN_SOURCE_DIR}" SOURCE_SUBDIR src BINARY_DIR stage1 - CMAKE_ARGS -DSTAGE=1 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage0 ${CL_ARGS} + CMAKE_ARGS -DSTAGE=1 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage0 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${STAGE0_CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS} BUILD_ALWAYS ON INSTALL_COMMAND "" DEPENDS stage0 @@ -66,7 +53,7 @@ ExternalProject_add(stage2 SOURCE_DIR "${LEAN_SOURCE_DIR}" SOURCE_SUBDIR src BINARY_DIR stage2 - CMAKE_ARGS -DSTAGE=2 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage1 ${CL_ARGS} + CMAKE_ARGS -DSTAGE=2 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage1 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS} BUILD_ALWAYS ON INSTALL_COMMAND "" DEPENDS stage1 @@ -76,7 +63,7 @@ ExternalProject_add(stage3 SOURCE_DIR "${LEAN_SOURCE_DIR}" SOURCE_SUBDIR src BINARY_DIR stage3 - CMAKE_ARGS -DSTAGE=3 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage2 ${CL_ARGS} + CMAKE_ARGS -DSTAGE=3 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage2 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS} BUILD_ALWAYS ON INSTALL_COMMAND "" DEPENDS stage2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index edde6915184b..b40444ee2227 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,6 +57,7 @@ option(CUSTOM_ALLOCATORS "CUSTOM_ALLOCATORS" ON) option(SAVE_SNAPSHOT "SAVE_SNAPSHOT" ON) option(SAVE_INFO "SAVE_INFO" ON) option(SMALL_ALLOCATOR "SMALL_ALLOCATOR" ON) +option(MMAP "MMAP" ON) option(LAZY_RC "LAZY_RC" OFF) option(RUNTIME_STATS "RUNTIME_STATS" OFF) option(BSYMBOLIC "Link with -Bsymbolic to reduce call overhead in shared libraries (Linux)" ON) @@ -84,6 +85,10 @@ else() set(NumBits 32) endif() +if ("${MMAP}" MATCHES "ON") + string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_MMAP") +endif() + if ("${RUNTIME_STATS}" MATCHES "ON") string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_RUNTIME_STATS") endif() @@ -93,29 +98,19 @@ if (NOT("${CHECK_OLEAN_VERSION}" MATCHES "ON")) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") - set(MULTI_THREAD OFF) # TODO(WN): code size/performance tradeoffs # - we're using -O3; it's /okay/ - # - -flto crashes at runtime # - -Oz produces quite slow code # - system libraries such as OpenGL are included in the JS but shouldn't be # - we need EMSCRIPTEN_KEEPALIVE annotations on exports to run meta-dce (-s MAIN_MODULE=2) - # - -fexceptions is a slow JS blob, remove when more runtimes support the WASM exceptions spec # From https://emscripten.org/docs/compiling/WebAssembly.html#backends: # > The simple and safe thing is to pass all -s flags at both compile and link time. - set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -s DISABLE_EXCEPTION_CATCHING=0 -s MAIN_MODULE=1 -fexceptions") + set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -fwasm-exceptions -pthread -flto") + string(APPEND LEANC_EXTRA_FLAGS " -pthread") string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_EMSCRIPTEN ${EMSCRIPTEN_SETTINGS}") string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${EMSCRIPTEN_SETTINGS}") endif() -if (CMAKE_CROSSCOMPILING_EMULATOR) - # emscripten likes to quote "node" - string(REPLACE "\"" "" CMAKE_CROSSCOMPILING_EMULATOR ${CMAKE_CROSSCOMPILING_EMULATOR}) - # HACK(WN): lazy compilation makes Node.js startup time a bad but tolerable ~4s - string(APPEND CMAKE_CROSSCOMPILING_EMULATOR " --wasm-lazy-compilation") -else() - set(CMAKE_CROSSCOMPILING_EMULATOR) -endif() # Added for CTest include(CTest) @@ -339,7 +334,7 @@ endif() # get rid of unused parts of C++ stdlib if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,-dead_strip") -else() +elseif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,--gc-sections") endif() @@ -355,18 +350,28 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec") string(APPEND LEANC_EXTRA_FLAGS " -fPIC") string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN") - string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean") elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") string(APPEND CMAKE_CXX_FLAGS " -ftls-model=initial-exec") string(APPEND LEANSHARED_LINKER_FLAGS " -install_name @rpath/libleanshared.dylib") - string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") + string(APPEND CMAKE_CXX_FLAGS " -fPIC") + string(APPEND LEANC_EXTRA_FLAGS " -fPIC") + # We do not use dynamic linking via leanshared for Emscripten to keep things + # simple. (And we are not interested in `Lake` anyway.) To use dynamic + # linking, we would probably have to set MAIN_MODULE=2 on `leanshared`, + # SIDE_MODULE=2 on `lean`, and set CMAKE_SHARED_LIBRARY_SUFFIX to ".js". + string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,--whole-archive -lInit -lLean -lleancpp -lleanrt ${EMSCRIPTEN_SETTINGS} -lnodefs.js -s EXIT_RUNTIME=1 -s MAIN_MODULE=1 -s LINKABLE=1 -s EXPORT_ALL=1") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared") endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") string(APPEND LEAN_EXTRA_LINKER_FLAGS " -ldl") endif() -if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows")) +if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows") AND NOT(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")) # export symbols for the interpreter (done via `LEAN_EXPORT` for Windows) string(APPEND LEAN_DYN_EXE_LINKER_FLAGS " -rdynamic") string(APPEND CMAKE_EXE_LINKER_FLAGS " -rdynamic") diff --git a/src/bin/lean.in b/src/bin/lean.in new file mode 100755 index 000000000000..044b4cef365a --- /dev/null +++ b/src/bin/lean.in @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# ONLY FOR WEB ASSEMBLY BUILD +node --stack-size=8192 ${CMAKE_BINARY_DIR}/bin/lean.js $@ + diff --git a/src/include/lean/lean.h b/src/include/lean/lean.h index 45a4bd0abdd3..d7fc1ee5796b 100644 --- a/src/include/lean/lean.h +++ b/src/include/lean/lean.h @@ -1312,8 +1312,8 @@ LEAN_SHARED lean_obj_res lean_nat_log2(b_lean_obj_arg a); /* Integers */ -#define LEAN_MAX_SMALL_INT (sizeof(void*) == 8 ? INT_MAX : (1 << 30)) -#define LEAN_MIN_SMALL_INT (sizeof(void*) == 8 ? INT_MIN : -(1 << 30)) +#define LEAN_MAX_SMALL_INT (sizeof(void*) == 8 ? INT_MAX : (INT_MAX >> 1)) +#define LEAN_MIN_SMALL_INT (sizeof(void*) == 8 ? INT_MIN : (INT_MIN >> 1)) LEAN_SHARED lean_object * lean_int_big_neg(lean_object * a); LEAN_SHARED lean_object * lean_int_big_add(lean_object * a1, lean_object * a2); LEAN_SHARED lean_object * lean_int_big_sub(lean_object * a1, lean_object * a2); diff --git a/src/lean.mk.in b/src/lean.mk.in index eb3fb1ad574e..90db2de6e9b4 100644 --- a/src/lean.mk.in +++ b/src/lean.mk.in @@ -12,7 +12,7 @@ endif LEAN = lean LEANC = leanc -LEAN_AR = ar +LEAN_AR = @CMAKE_AR@ OUT = build OLEAN_OUT = $(OUT) TEMP_OUT = $(OUT)/temp diff --git a/src/library/module.cpp b/src/library/module.cpp index bb41bbe318d6..7d93ca857c4f 100644 --- a/src/library/module.cpp +++ b/src/library/module.cpp @@ -155,7 +155,9 @@ extern "C" LEAN_EXPORT object * lean_read_module_data(object * fname, object *) if (fd == -1) { return io_result_mk_error((sstream() << "failed to open '" << olean_fn << "': " << strerror(errno)).str()); } +#ifdef LEAN_MMAP buffer = static_cast(mmap(base_addr, size, PROT_READ, MAP_PRIVATE, fd, 0)); +#endif close(fd); free_data = [=]() { if (buffer != MAP_FAILED) { @@ -163,11 +165,13 @@ extern "C" LEAN_EXPORT object * lean_read_module_data(object * fname, object *) } }; #endif - if (buffer == base_addr) { + if (buffer && buffer == base_addr) { buffer += header_size; is_mmap = true; } else { +#ifdef LEAN_MMAP free_data(); +#endif buffer = static_cast(malloc(size - header_size)); free_data = [=]() { free(buffer); diff --git a/src/runtime/io.cpp b/src/runtime/io.cpp index c923a12a38f9..86c206024e69 100644 --- a/src/runtime/io.cpp +++ b/src/runtime/io.cpp @@ -20,8 +20,10 @@ Authors: Leonardo de Moura, Sebastian Ullrich // Linux include files #include // NOLINT #include +#ifndef LEAN_EMSCRIPTEN #include #endif +#endif #ifndef LEAN_WINDOWS #include #endif @@ -433,7 +435,7 @@ extern "C" LEAN_EXPORT obj_res lean_io_get_random_bytes (size_t nbytes, obj_arg #else #if defined(LEAN_EMSCRIPTEN) // `Crypto.getRandomValues` documents `dest` should be at most 65536 bytes. - size_t read_sz = std::min(remain, 65536); + size_t read_sz = std::min(remain, static_cast(65536)); #else size_t read_sz = remain; #endif diff --git a/src/runtime/stack_overflow.cpp b/src/runtime/stack_overflow.cpp index 0e5656d61b75..f1a81f0a00bd 100644 --- a/src/runtime/stack_overflow.cpp +++ b/src/runtime/stack_overflow.cpp @@ -42,10 +42,6 @@ stack_guard::stack_guard() { SetThreadStackGuarantee(&sz); } -stack_guard::~stack_guard() {} -#elif defined(LEAN_EMSCRIPTEN) -stack_guard::stack_guard() {} - stack_guard::~stack_guard() {} #else // Install a segfault signal handler and abort with custom message if address is within stack guard. @@ -105,7 +101,7 @@ void initialize_stack_overflow() { g_stack_guard = new stack_guard(); #ifdef LEAN_WINDOWS AddVectoredExceptionHandler(0, stack_overflow_handler); -#elif !defined(LEAN_EMSCRIPTEN) +#else struct sigaction action; memset(&action, 0, sizeof(struct sigaction)); action.sa_flags = SA_SIGINFO | SA_ONSTACK; diff --git a/src/runtime/stackinfo.cpp b/src/runtime/stackinfo.cpp index 0e7c6ea52a86..48f4c7a3946d 100644 --- a/src/runtime/stackinfo.cpp +++ b/src/runtime/stackinfo.cpp @@ -19,6 +19,10 @@ Author: Leonardo de Moura #include // NOLINT #endif +#if defined(LEAN_EMSCRIPTEN) +#include +#endif + namespace lean { void throw_get_stack_size_failed() { throw exception("failed to retrieve thread stack size"); @@ -45,6 +49,14 @@ size_t get_stack_size(int main) { return lthread::get_thread_stack_size(); } } +#elif defined(LEAN_EMSCRIPTEN) +size_t get_stack_size(int main) { + if (main) { + return emscripten_stack_get_end() - emscripten_stack_get_base(); + } else { + return lthread::get_thread_stack_size(); + } +} #else size_t get_stack_size(int main) { if (main) { diff --git a/src/shell/CMakeLists.txt b/src/shell/CMakeLists.txt index 389bfca006d4..7329b1a772bc 100644 --- a/src/shell/CMakeLists.txt +++ b/src/shell/CMakeLists.txt @@ -46,8 +46,12 @@ add_test(lean_ghash2 "${CMAKE_BINARY_DIR}/bin/lean" --githash) add_test(lean_unknown_option bash "${LEAN_SOURCE_DIR}/cmake/check_failure.sh" "${CMAKE_BINARY_DIR}/bin/lean" "-z") add_test(lean_unknown_file1 bash "${LEAN_SOURCE_DIR}/cmake/check_failure.sh" "${CMAKE_BINARY_DIR}/bin/lean" "boofoo.lean") -# LEANC_OPTS is necessary for macOS c++ to find its headers -set(TEST_VARS "PATH=${LEAN_BIN}:$PATH ${LEAN_TEST_VARS} CXX='${CMAKE_CXX_COMPILER} ${LEANC_OPTS}'") +if(${EMSCRIPTEN}) + configure_file("${LEAN_SOURCE_DIR}/bin/lean.in" "${CMAKE_BINARY_DIR}/bin/lean") +endif() + +# LEANC_OPTS in CXX is necessary for macOS c++ to find its headers +set(TEST_VARS "PATH=${LEAN_BIN}:$PATH ${LEAN_TEST_VARS} CXX='${CMAKE_CXX_COMPILER} ${LEANC_OPTS}' LEANC_OPTS='${LEANC_OPTS}'") # LEAN TESTS file(GLOB LEANTESTS "${LEAN_SOURCE_DIR}/../tests/lean/*.lean") diff --git a/src/stdlib.make.in b/src/stdlib.make.in index e8c876b8ad94..5d192f9ec6c0 100644 --- a/src/stdlib.make.in +++ b/src/stdlib.make.in @@ -12,7 +12,7 @@ export LEAN_ABORT_ON_PANIC=1 # LEAN_OPTS: don't use native code (except for primitives) since it is from the previous stage # MORE_DEPS: rebuild the stdlib whenever the compiler has changed LEANMAKE_OPTS=\ - LEAN="${CMAKE_CROSSCOMPILING_EMULATOR} ${PREV_STAGE}/bin/lean${CMAKE_EXECUTABLE_SUFFIX}"\ + LEAN="${PREV_STAGE}/bin/lean${PREV_STAGE_CMAKE_EXECUTABLE_SUFFIX}"\ LEANC="${CMAKE_BINARY_DIR}/leanc.sh"\ OUT="${LIB}"\ LIB_OUT="${LIB}/lean"\ @@ -21,7 +21,7 @@ LEANMAKE_OPTS=\ LEAN_OPTS+="${LEAN_EXTRA_MAKE_OPTS} -DwarningAsError=true"\ LEANC_OPTS+="${LEANC_OPTS}"\ LEAN_AR="${CMAKE_AR}"\ - MORE_DEPS+="${PREV_STAGE}/bin/lean${CMAKE_EXECUTABLE_SUFFIX}"\ + MORE_DEPS+="${PREV_STAGE}/bin/lean${PREV_STAGE_CMAKE_EXECUTABLE_SUFFIX}"\ ${EXTRA_LEANMAKE_OPTS}\ CMAKE_LIKE_OUTPUT=1 @@ -52,15 +52,15 @@ leanshared: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libleanshared${CMAKE_SHARED_LIBRAR Lake: # lake is in its own subdirectory, so must adjust relative paths... - +"${LEAN_BIN}/leanmake" -C lake bin lib PKG=Lake BIN_NAME=lake${CMAKE_EXECUTABLE_SUFFIX} $(LEANMAKE_OPTS) LINK_OPTS='-lleanshared ${CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE}' OUT="../${LIB}" LIB_OUT="../${LIB}/lean" OLEAN_OUT="../${LIB}/lean" + +"${LEAN_BIN}/leanmake" -C lake bin lib PKG=Lake BIN_NAME=lake${CMAKE_EXECUTABLE_SUFFIX} $(LEANMAKE_OPTS) LINK_OPTS='${CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE}' OUT="../${LIB}" LIB_OUT="../${LIB}/lean" OLEAN_OUT="../${LIB}/lean" ${CMAKE_BINARY_DIR}/bin/lean${CMAKE_EXECUTABLE_SUFFIX}: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libleanshared${CMAKE_SHARED_LIBRARY_SUFFIX} $(LEAN_SHELL) @echo "[ ] Building $@" # on Windows, must remove file before writing a new one (since the old one may be in use) @rm -f $@ - "${CMAKE_BINARY_DIR}/leanc.sh" $(LEAN_SHELL) -lleanshared ${CMAKE_EXE_LINKER_FLAGS_MAKE} ${LEAN_EXE_LINKER_FLAGS} ${LEANC_OPTS} -o $@ + "${CMAKE_BINARY_DIR}/leanc.sh" $(LEAN_SHELL) ${CMAKE_EXE_LINKER_FLAGS_MAKE} ${LEAN_EXE_LINKER_FLAGS} ${LEANC_OPTS} -o $@ lean: ${CMAKE_BINARY_DIR}/bin/lean${CMAKE_EXECUTABLE_SUFFIX} Leanc: - +"${LEAN_BIN}/leanmake" bin PKG=Leanc BIN_NAME=leanc${CMAKE_EXECUTABLE_SUFFIX} $(LEANMAKE_OPTS) LINK_OPTS='-lleanshared ${CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE}' OUT="${CMAKE_BINARY_DIR}" OLEAN_OUT="${CMAKE_BINARY_DIR}" + +"${LEAN_BIN}/leanmake" bin PKG=Leanc BIN_NAME=leanc${CMAKE_EXECUTABLE_SUFFIX} $(LEANMAKE_OPTS) LINK_OPTS='${CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE}' OUT="${CMAKE_BINARY_DIR}" OLEAN_OUT="${CMAKE_BINARY_DIR}" diff --git a/stage0/src/CMakeLists.txt b/stage0/src/CMakeLists.txt index 2c2425da5f94..6e735d8450f7 100644 --- a/stage0/src/CMakeLists.txt +++ b/stage0/src/CMakeLists.txt @@ -57,6 +57,7 @@ option(CUSTOM_ALLOCATORS "CUSTOM_ALLOCATORS" ON) option(SAVE_SNAPSHOT "SAVE_SNAPSHOT" ON) option(SAVE_INFO "SAVE_INFO" ON) option(SMALL_ALLOCATOR "SMALL_ALLOCATOR" ON) +option(MMAP "MMAP" ON) option(LAZY_RC "LAZY_RC" OFF) option(RUNTIME_STATS "RUNTIME_STATS" OFF) option(BSYMBOLIC "Link with -Bsymbolic to reduce call overhead in shared libraries (Linux)" ON) @@ -84,6 +85,10 @@ else() set(NumBits 32) endif() +if ("${MMAP}" MATCHES "ON") + string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_MMAP") +endif() + if ("${RUNTIME_STATS}" MATCHES "ON") string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_RUNTIME_STATS") endif() @@ -93,29 +98,19 @@ if (NOT("${CHECK_OLEAN_VERSION}" MATCHES "ON")) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") - set(MULTI_THREAD OFF) # TODO(WN): code size/performance tradeoffs # - we're using -O3; it's /okay/ - # - -flto crashes at runtime # - -Oz produces quite slow code # - system libraries such as OpenGL are included in the JS but shouldn't be # - we need EMSCRIPTEN_KEEPALIVE annotations on exports to run meta-dce (-s MAIN_MODULE=2) - # - -fexceptions is a slow JS blob, remove when more runtimes support the WASM exceptions spec # From https://emscripten.org/docs/compiling/WebAssembly.html#backends: # > The simple and safe thing is to pass all -s flags at both compile and link time. - set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -s DISABLE_EXCEPTION_CATCHING=0 -s MAIN_MODULE=1 -fexceptions") + set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -fwasm-exceptions -pthread -flto") + string(APPEND LEANC_EXTRA_FLAGS " -pthread") string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_EMSCRIPTEN ${EMSCRIPTEN_SETTINGS}") string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${EMSCRIPTEN_SETTINGS}") endif() -if (CMAKE_CROSSCOMPILING_EMULATOR) - # emscripten likes to quote "node" - string(REPLACE "\"" "" CMAKE_CROSSCOMPILING_EMULATOR ${CMAKE_CROSSCOMPILING_EMULATOR}) - # HACK(WN): lazy compilation makes Node.js startup time a bad but tolerable ~4s - string(APPEND CMAKE_CROSSCOMPILING_EMULATOR " --wasm-lazy-compilation") -else() - set(CMAKE_CROSSCOMPILING_EMULATOR) -endif() # Added for CTest include(CTest) @@ -339,7 +334,7 @@ endif() # get rid of unused parts of C++ stdlib if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,-dead_strip") -else() +elseif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,--gc-sections") endif() @@ -355,18 +350,28 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec") string(APPEND LEANC_EXTRA_FLAGS " -fPIC") string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN") - string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean") elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") string(APPEND CMAKE_CXX_FLAGS " -ftls-model=initial-exec") string(APPEND LEANSHARED_LINKER_FLAGS " -install_name @rpath/libleanshared.dylib") - string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") + string(APPEND CMAKE_CXX_FLAGS " -fPIC") + string(APPEND LEANC_EXTRA_FLAGS " -fPIC") + # We do not use dynamic linking via leanshared for Emscripten to keep things + # simple. (And we are not interested in `Lake` anyway.) To use dynamic + # linking, we would probably have to set MAIN_MODULE=2 on `leanshared`, + # SIDE_MODULE=2 on `lean`, and set CMAKE_SHARED_LIBRARY_SUFFIX to ".js". + string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,--whole-archive -lInit -lLean -lleancpp -lleanrt ${EMSCRIPTEN_SETTINGS} -lnodefs.js -s EXIT_RUNTIME=1 -s MAIN_MODULE=1 -s LINKABLE=1 -s EXPORT_ALL=1") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared") endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") string(APPEND LEAN_EXTRA_LINKER_FLAGS " -ldl") endif() -if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows")) +if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows") AND NOT(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")) # export symbols for the interpreter (done via `LEAN_EXPORT` for Windows) string(APPEND LEAN_DYN_EXE_LINKER_FLAGS " -rdynamic") string(APPEND CMAKE_EXE_LINKER_FLAGS " -rdynamic") diff --git a/stage0/src/library/module.cpp b/stage0/src/library/module.cpp index bb41bbe318d6..7d93ca857c4f 100644 --- a/stage0/src/library/module.cpp +++ b/stage0/src/library/module.cpp @@ -155,7 +155,9 @@ extern "C" LEAN_EXPORT object * lean_read_module_data(object * fname, object *) if (fd == -1) { return io_result_mk_error((sstream() << "failed to open '" << olean_fn << "': " << strerror(errno)).str()); } +#ifdef LEAN_MMAP buffer = static_cast(mmap(base_addr, size, PROT_READ, MAP_PRIVATE, fd, 0)); +#endif close(fd); free_data = [=]() { if (buffer != MAP_FAILED) { @@ -163,11 +165,13 @@ extern "C" LEAN_EXPORT object * lean_read_module_data(object * fname, object *) } }; #endif - if (buffer == base_addr) { + if (buffer && buffer == base_addr) { buffer += header_size; is_mmap = true; } else { +#ifdef LEAN_MMAP free_data(); +#endif buffer = static_cast(malloc(size - header_size)); free_data = [=]() { free(buffer); diff --git a/stage0/src/shell/CMakeLists.txt b/stage0/src/shell/CMakeLists.txt index 389bfca006d4..bda271ca3d4f 100644 --- a/stage0/src/shell/CMakeLists.txt +++ b/stage0/src/shell/CMakeLists.txt @@ -46,8 +46,14 @@ add_test(lean_ghash2 "${CMAKE_BINARY_DIR}/bin/lean" --githash) add_test(lean_unknown_option bash "${LEAN_SOURCE_DIR}/cmake/check_failure.sh" "${CMAKE_BINARY_DIR}/bin/lean" "-z") add_test(lean_unknown_file1 bash "${LEAN_SOURCE_DIR}/cmake/check_failure.sh" "${CMAKE_BINARY_DIR}/bin/lean" "boofoo.lean") -# LEANC_OPTS is necessary for macOS c++ to find its headers -set(TEST_VARS "PATH=${LEAN_BIN}:$PATH ${LEAN_TEST_VARS} CXX='${CMAKE_CXX_COMPILER} ${LEANC_OPTS}'") +if(${EMSCRIPTEN}) + set(LEAN_EXE "node --stack-size=8192 ${CMAKE_BINARY_DIR}/bin/lean") +else() + set(LEAN_EXE "lean") +endif() + +# LEANC_OPTS in CXX is necessary for macOS c++ to find its headers +set(TEST_VARS "PATH=${LEAN_BIN}:$PATH ${LEAN_TEST_VARS} CXX='${CMAKE_CXX_COMPILER} ${LEANC_OPTS}' LEANC_OPTS='${LEANC_OPTS}' LEAN_EXE='${LEAN_EXE}'") # LEAN TESTS file(GLOB LEANTESTS "${LEAN_SOURCE_DIR}/../tests/lean/*.lean") diff --git a/stage0/src/stdlib.make.in b/stage0/src/stdlib.make.in index e8c876b8ad94..5d192f9ec6c0 100644 --- a/stage0/src/stdlib.make.in +++ b/stage0/src/stdlib.make.in @@ -12,7 +12,7 @@ export LEAN_ABORT_ON_PANIC=1 # LEAN_OPTS: don't use native code (except for primitives) since it is from the previous stage # MORE_DEPS: rebuild the stdlib whenever the compiler has changed LEANMAKE_OPTS=\ - LEAN="${CMAKE_CROSSCOMPILING_EMULATOR} ${PREV_STAGE}/bin/lean${CMAKE_EXECUTABLE_SUFFIX}"\ + LEAN="${PREV_STAGE}/bin/lean${PREV_STAGE_CMAKE_EXECUTABLE_SUFFIX}"\ LEANC="${CMAKE_BINARY_DIR}/leanc.sh"\ OUT="${LIB}"\ LIB_OUT="${LIB}/lean"\ @@ -21,7 +21,7 @@ LEANMAKE_OPTS=\ LEAN_OPTS+="${LEAN_EXTRA_MAKE_OPTS} -DwarningAsError=true"\ LEANC_OPTS+="${LEANC_OPTS}"\ LEAN_AR="${CMAKE_AR}"\ - MORE_DEPS+="${PREV_STAGE}/bin/lean${CMAKE_EXECUTABLE_SUFFIX}"\ + MORE_DEPS+="${PREV_STAGE}/bin/lean${PREV_STAGE_CMAKE_EXECUTABLE_SUFFIX}"\ ${EXTRA_LEANMAKE_OPTS}\ CMAKE_LIKE_OUTPUT=1 @@ -52,15 +52,15 @@ leanshared: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libleanshared${CMAKE_SHARED_LIBRAR Lake: # lake is in its own subdirectory, so must adjust relative paths... - +"${LEAN_BIN}/leanmake" -C lake bin lib PKG=Lake BIN_NAME=lake${CMAKE_EXECUTABLE_SUFFIX} $(LEANMAKE_OPTS) LINK_OPTS='-lleanshared ${CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE}' OUT="../${LIB}" LIB_OUT="../${LIB}/lean" OLEAN_OUT="../${LIB}/lean" + +"${LEAN_BIN}/leanmake" -C lake bin lib PKG=Lake BIN_NAME=lake${CMAKE_EXECUTABLE_SUFFIX} $(LEANMAKE_OPTS) LINK_OPTS='${CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE}' OUT="../${LIB}" LIB_OUT="../${LIB}/lean" OLEAN_OUT="../${LIB}/lean" ${CMAKE_BINARY_DIR}/bin/lean${CMAKE_EXECUTABLE_SUFFIX}: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libleanshared${CMAKE_SHARED_LIBRARY_SUFFIX} $(LEAN_SHELL) @echo "[ ] Building $@" # on Windows, must remove file before writing a new one (since the old one may be in use) @rm -f $@ - "${CMAKE_BINARY_DIR}/leanc.sh" $(LEAN_SHELL) -lleanshared ${CMAKE_EXE_LINKER_FLAGS_MAKE} ${LEAN_EXE_LINKER_FLAGS} ${LEANC_OPTS} -o $@ + "${CMAKE_BINARY_DIR}/leanc.sh" $(LEAN_SHELL) ${CMAKE_EXE_LINKER_FLAGS_MAKE} ${LEAN_EXE_LINKER_FLAGS} ${LEANC_OPTS} -o $@ lean: ${CMAKE_BINARY_DIR}/bin/lean${CMAKE_EXECUTABLE_SUFFIX} Leanc: - +"${LEAN_BIN}/leanmake" bin PKG=Leanc BIN_NAME=leanc${CMAKE_EXECUTABLE_SUFFIX} $(LEANMAKE_OPTS) LINK_OPTS='-lleanshared ${CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE}' OUT="${CMAKE_BINARY_DIR}" OLEAN_OUT="${CMAKE_BINARY_DIR}" + +"${LEAN_BIN}/leanmake" bin PKG=Leanc BIN_NAME=leanc${CMAKE_EXECUTABLE_SUFFIX} $(LEANMAKE_OPTS) LINK_OPTS='${CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE}' OUT="${CMAKE_BINARY_DIR}" OLEAN_OUT="${CMAKE_BINARY_DIR}" diff --git a/tests/common.sh b/tests/common.sh index c9fc2fdee9d5..a64e1a39a3f8 100644 --- a/tests/common.sh +++ b/tests/common.sh @@ -26,7 +26,7 @@ function lean_has_llvm_support { function compile_lean_c_backend { lean --c="$f.c" "$f" || fail "Failed to compile $f into C file" - leanc -O3 -DNDEBUG -o "$f.out" "$@" "$f.c" || fail "Failed to compile C file $f.c" + leanc ${LEANC_OPTS-} -O3 -DNDEBUG -o "$f.out" "$@" "$f.c" || fail "Failed to compile C file $f.c" } function compile_lean_llvm_backend { @@ -35,7 +35,7 @@ function compile_lean_llvm_backend { rm "*.bc" || true # remove bitcode files rm "*.o" || true # remove object files lean --bc="$f.linked.bc" "$f" || fail "Failed to compile $f into bitcode file" - leanc -o "$f.out" "$@" "$f.linked.bc.o" || fail "Failed to link object file '$f.linked.bc.o'" + leanc ${LEANC_OPTS-} -o "$f.out" "$@" "$f.linked.bc.o" || fail "Failed to link object file '$f.linked.bc.o'" set +o xtrace } From 89b65c8f1d6fa7700d73f1bc12db0b140c728e32 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Wed, 4 Oct 2023 13:02:54 +0200 Subject: [PATCH 18/71] feat: make `Environment.mk` private (#2604) * feat: make `Environment.mk` private --------- --- src/Lean/Environment.lean | 5 ++++- tests/lean/prvCtor.lean | 8 +++++++- tests/lean/prvCtor.lean.expected.out | 10 ++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Lean/Environment.lean b/src/Lean/Environment.lean index a4a9ad16f7bd..59d0bbbf6509 100644 --- a/src/Lean/Environment.lean +++ b/src/Lean/Environment.lean @@ -117,6 +117,9 @@ declared by users are stored in an environment extension. Users can declare new using meta-programming. -/ structure Environment where + /-- The constructor of `Environment` is private to protect against modification + that bypasses the kernel. -/ + private mk :: /-- Mapping from constant name to module (index) where constant has been declared. Recall that a Lean file has a header where previously compiled modules can be imported. @@ -149,7 +152,7 @@ structure Environment where namespace Environment -def addAux (env : Environment) (cinfo : ConstantInfo) : Environment := +private def addAux (env : Environment) (cinfo : ConstantInfo) : Environment := { env with constants := env.constants.insert cinfo.name cinfo } /-- diff --git a/tests/lean/prvCtor.lean b/tests/lean/prvCtor.lean index 18a978732c4d..28c1bcb2a0f8 100644 --- a/tests/lean/prvCtor.lean +++ b/tests/lean/prvCtor.lean @@ -16,7 +16,13 @@ def n2 : Name "hello" := ⟨"hello"⟩ def n3 : Name "hello" := Name.mk "hello" open Lean in -#eval id (α := CoreM Unit) do modifyEnv fun env => { env with header.mainModule := `foo } -- change module name to test `private` +#eval id (α := CoreM Unit) do + modifyEnv fun env => env.setMainModule `foo -- change module name to test `private` + +open Lean in +#eval id (α := CoreM Unit) do + -- this implementation is no longer allowed because of a private constructor + modifyEnv fun env => { env with header.mainModule := `foo } #check a -- Error diff --git a/tests/lean/prvCtor.lean.expected.out b/tests/lean/prvCtor.lean.expected.out index 76f48d818330..f175e7d2fdfe 100644 --- a/tests/lean/prvCtor.lean.expected.out +++ b/tests/lean/prvCtor.lean.expected.out @@ -1,10 +1,12 @@ a : Nat -prvCtor.lean:21:7-21:8: error: unknown identifier 'a' -prvCtor.lean:23:25-23:27: error: overloaded, errors +prvCtor.lean:25:23-25:61: error: invalid {...} notation, constructor for `Lean.Environment` is marked as private +prvCtor.lean:23:0-25:61: error: cannot evaluate code because '_eval._lambda_1' uses 'sorry' and/or contains errors +prvCtor.lean:27:7-27:8: error: unknown identifier 'a' +prvCtor.lean:29:25-29:27: error: overloaded, errors failed to synthesize instance EmptyCollection (Name "hello") invalid {...} notation, constructor for `Name` is marked as private -prvCtor.lean:25:25-25:34: error: invalid ⟨...⟩ notation, constructor for `Name` is marked as private -prvCtor.lean:27:25-27:40: error: unknown constant 'Name.mk' +prvCtor.lean:31:25-31:34: error: invalid ⟨...⟩ notation, constructor for `Name` is marked as private +prvCtor.lean:33:25-33:40: error: unknown constant 'Name.mk' From dceed634a05e1d62588f89b9f1d7b7b4cf79f676 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Wed, 4 Oct 2023 17:49:50 +0200 Subject: [PATCH 19/71] doc: fix typo in quickstart.md --- doc/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/quickstart.md b/doc/quickstart.md index ffdbaaad04cb..091829a03717 100644 --- a/doc/quickstart.md +++ b/doc/quickstart.md @@ -39,7 +39,7 @@ You are set up! ## Create a Lean Project -*If your goal is to contribute to [mathlib4](https://github.com/leanprover-community/mathlib4) or use it as a depdency, please see its readme for specific instructions on how to do that.* +*If your goal is to contribute to [mathlib4](https://github.com/leanprover-community/mathlib4) or use it as a dependency, please see its readme for specific instructions on how to do that.* You can now create a Lean project in a new folder. Run `lake init foo` from "View > Terminal" to create a package, followed by `lake build` to get an executable version of your Lean program. On Linux/macOS, you first have to follow the instructions printed by the Lean installation or log out and in again for the Lean executables to be available in you terminal. From 42cb59efdd9099cb6e1891fa58b21dfcc5eef702 Mon Sep 17 00:00:00 2001 From: Denis Gorbachev <829578+DenisGorbachev@users.noreply.github.com> Date: Thu, 5 Oct 2023 08:02:55 +0700 Subject: [PATCH 20/71] doc: fix the link to contribution guidelines (#2623) --- doc/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/faq.md b/doc/faq.md index af8b4bfe0275..9ae981375502 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -47,7 +47,7 @@ We expect similar independent checkers will be built for Lean 4. We use [GitHub](https://github.com/leanprover/lean4/issues) to track bugs and new features. Bug reports are always welcome, but nitpicking issues are not (e.g., the error message is confusing). -See also our [contribution guidelines](../CONTRIBUTING.md). +See also our [contribution guidelines](https://github.com/leanprover/lean4/blob/master/CONTRIBUTING.md). ### Is it Lean, LEAN, or L∃∀N? From 734ce1ef2f62f6aaba440690686bf76b614c1186 Mon Sep 17 00:00:00 2001 From: Siddharth Date: Thu, 5 Oct 2023 04:38:59 +0100 Subject: [PATCH 21/71] feat: show path of failed import (#2616) --- RELEASES.md | 1 + src/lake/Lake/Build/Module.lean | 14 +++++++++++++- src/lake/Lake/Util/Cycle.lean | 5 +++++ src/lake/Lake/Util/List.lean | 19 +++++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/lake/Lake/Util/List.lean diff --git a/RELEASES.md b/RELEASES.md index 7aa09c12e0fb..688b6876ed25 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -11,6 +11,7 @@ v4.3.0 (development in progress) --------- * The derive handler for `DecidableEq` [now handles](https://github.com/leanprover/lean4/pull/2591) mutual inductive types. +* [Show path of failed import in Lake](https://github.com/leanprover/lean4/pull/2616). * [Fix linker warnings on macOS](https://github.com/leanprover/lean4/pull/2598). v4.2.0 diff --git a/src/lake/Lake/Build/Module.lean b/src/lake/Lake/Build/Module.lean index 97246db7293e..ee4444b9bc9a 100644 --- a/src/lake/Lake/Build/Module.lean +++ b/src/lake/Lake/Build/Module.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sebastian Ullrich, Mac Malone -/ import Lake.Util.OrdHashSet +import Lake.Util.List import Lean.Elab.ParseImportsFast import Lake.Build.Common @@ -58,7 +59,18 @@ Recursively parse the Lean files of a module and its imports building an `Array` product of its direct local imports. -/ def Module.recParseImports (mod : Module) : IndexBuildM (Array Module) := do - let contents ← IO.FS.readFile mod.leanFile + let callstack : CallStack BuildKey ← EquipT.lift <| CycleT.readCallStack + let contents ← liftM <| tryCatch (IO.FS.readFile mod.leanFile) (fun err => + -- filter out only modules from build key, and remove adjacent duplicates (squeeze), + -- since Lake visits multiple nested facets of the same module. + let callstack := callstack.filterMap (fun bk => + match bk with + | .moduleFacet mod .. => .some s!"'{mod.toString}'" + | _ => .none + ) |> List.squeeze + let breadcrumb := String.intercalate " ▸ " callstack.reverse + throw <| IO.userError s!"({breadcrumb}): {err}" + ) let imports ← Lean.parseImports' contents mod.leanFile.toString let mods ← imports.foldlM (init := OrdModuleSet.empty) fun set imp => findModule? imp.module <&> fun | some mod => set.insert mod | none => set diff --git a/src/lake/Lake/Util/Cycle.lean b/src/lake/Lake/Util/Cycle.lean index 523bd0f16e36..d2608c8a73b2 100644 --- a/src/lake/Lake/Util/Cycle.lean +++ b/src/lake/Lake/Util/Cycle.lean @@ -15,6 +15,11 @@ abbrev Cycle κ := CallStack κ /-- A transformer that equips a monad with a `CallStack` to detect cycles. -/ abbrev CycleT κ m := ReaderT (CallStack κ) <| ExceptT (Cycle κ) m +/-- Read the call stack from a CycleT. + this specialized version exists to be used in e.g. `BuildM`. -/ +def CycleT.readCallStack [Pure m] : CycleT κ m (CallStack κ) := + fun callStack => ExceptT.mk <| pure (Except.ok callStack) + /-- Add `key` to the monad's `CallStack` before invoking `act`. If adding `key` produces a cycle, the cyclic call stack is thrown. diff --git a/src/lake/Lake/Util/List.lean b/src/lake/Lake/Util/List.lean new file mode 100644 index 000000000000..807082562819 --- /dev/null +++ b/src/lake/Lake/Util/List.lean @@ -0,0 +1,19 @@ +/- +Copyright (c) 2023 Siddharth Bhat. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Siddharth Bhat +-/ + +open Lean + +namespace Lake + +/-- Remove adjacent duplicates. -/ +def List.squeeze [BEq α] : List α → List α +| [] => [] +| x :: xs => + match List.squeeze xs with + | [] => [x] + | x' :: xs' => if x == x' then x' :: xs' else x :: x' :: xs' + +end Lake From b3ff006eb8c4d954f55142c3ab947749bc060fb9 Mon Sep 17 00:00:00 2001 From: David Thrane Christiansen Date: Fri, 6 Oct 2023 09:57:04 +0200 Subject: [PATCH 22/71] doc: add missing character in testing.md The testing docs omit the `s` in the `tests` directory at one point. The incorrect directory name threw me off - it will probably throw others off. --- doc/dev/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/testing.md b/doc/dev/testing.md index 888c2631d77e..8f427a641776 100644 --- a/doc/dev/testing.md +++ b/doc/dev/testing.md @@ -111,7 +111,7 @@ First, we must install [meld](http://meldmerge.org/). On Ubuntu, we can do it by sudo apt-get install meld ``` -Now, suppose `bad_class.lean` test is broken. We can see the problem by going to `test/lean` directory and +Now, suppose `bad_class.lean` test is broken. We can see the problem by going to `tests/lean` directory and executing ``` From 4c6d2b399869148d3ef80bcd0fe55858c6c89e8c Mon Sep 17 00:00:00 2001 From: David Christiansen Date: Thu, 5 Oct 2023 15:05:07 +0200 Subject: [PATCH 23/71] doc: fix typo in comment Fix a misspelled/mistyped word in a comment. --- src/Lean/Message.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Lean/Message.lean b/src/Lean/Message.lean index 2f6aa8286d1b..d2dc1b043485 100644 --- a/src/Lean/Message.lean +++ b/src/Lean/Message.lean @@ -185,7 +185,7 @@ def bracket (l : String) (f : MessageData) (r : String) : MessageData := group ( def paren (f : MessageData) : MessageData := bracket "(" f ")" /-- Wrap the given message in square brackets `[]`. -/ def sbracket (f : MessageData) : MessageData := bracket "[" f "]" -/-- Append the given list of messages with the given separarator. -/ +/-- Append the given list of messages with the given separator. -/ def joinSep : List MessageData → MessageData → MessageData | [], _ => Format.nil | [a], _ => a From b0b922bae499e6380ed3e48ad8efb25c963d5aaf Mon Sep 17 00:00:00 2001 From: David Christiansen Date: Thu, 5 Oct 2023 21:25:18 +0200 Subject: [PATCH 24/71] feat: list the valid case tags when the user writes an invalid one Before, Lean would simply emit the message "tag not found". With this change, it also tells the user what they could have written that would be accepted. --- src/Lean/Elab/Tactic/BuiltinTactic.lean | 30 ++++++++++++- tests/lean/caseSuggestions.lean | 45 ++++++++++++++++++++ tests/lean/caseSuggestions.lean.expected.out | 42 ++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 tests/lean/caseSuggestions.lean create mode 100644 tests/lean/caseSuggestions.lean.expected.out diff --git a/src/Lean/Elab/Tactic/BuiltinTactic.lean b/src/Lean/Elab/Tactic/BuiltinTactic.lean index ea220167091d..e7fb5b0a0d5b 100644 --- a/src/Lean/Elab/Tactic/BuiltinTactic.lean +++ b/src/Lean/Elab/Tactic/BuiltinTactic.lean @@ -369,12 +369,40 @@ private def getCaseGoals (tag : TSyntax ``binderIdent) : TacticM (MVarId × List let gs ← getUnsolvedGoals let g ← if let `(binderIdent| $tag:ident) := tag then let tag := tag.getId - let some g ← findTag? gs tag | throwError "tag not found" + let some g ← findTag? gs tag | notFound gs tag pure g else getMainGoal return (g, gs.erase g) +where + -- When the case tag is not found, construct a message that tells + -- the user what they could have written + notFound (available : List MVarId) (tag : Name) := do + let firstLine := m!"Case tag {showTagName tag} not found." + -- We must filter out the anonymous name because there may be an + -- anonymous goal, but users shouldn't be mistakenly encouraged + -- to write `case anonymous` + match (← available.mapM getUserName).filter (· ≠ Name.anonymous) with + | [] => + throwError "{firstLine}\n\nThere are no cases to select." + | [availableName] => + throwError "{firstLine}\n\nThe only available case tag is {showTagName availableName}." + | availableNames => + throwError "Case tag {showTagName tag} not found.\n\nAvailable tags:{commaList <| availableNames.map showTagName}" + + getUserName (mv : MVarId) := do return (← mv.getDecl).userName + + showTagName (tagName : Name) : MessageData := m!"'{tagName}'" + + -- Construct a comma-separated list that renders one per line, + -- indented, if it's too long + commaList (items : List MessageData) : MessageData := + let sep := MessageData.ofFormat "," ++ Format.line + .group <| .nest 2 <| + .ofFormat .line ++ .joinSep items sep + + @[builtin_tactic «case»] def evalCase : Tactic | stx@`(tactic| case $[$tag $hs*]|* =>%$arr $tac:tacticSeq) => for tag in tag, hs in hs do diff --git a/tests/lean/caseSuggestions.lean b/tests/lean/caseSuggestions.lean new file mode 100644 index 000000000000..5b212658cc5a --- /dev/null +++ b/tests/lean/caseSuggestions.lean @@ -0,0 +1,45 @@ +/-! + + # Provide case alternatives in "nonexistent tag" message + + Test that the available case tags are suggested when a nonexistent + tag is requested. -/ + +/-! + This example tests what happens when no cases are available. -/ +theorem noCases : Nat := by + case nonexistent => + skip + +/-! + This example tests what happens when just one case is available, but + it wasn't picked. -/ + +theorem oneCase : Nat := by + cases () + case nonexistent => + skip + +/-! + Check varying numbers of cases to make sure the pretty-print setup for + the list is correct. -/ + +theorem twoCases : Nat := by + cases true + case nonexistent => + skip + +theorem fourCases : Nat := by + cases true <;> cases true + case nonexistent => + skip + +theorem eightCases : Nat := by + cases true <;> cases true <;> cases true + case nonexistent => + skip + +theorem sixteenCases : Nat := by + cases true <;> cases true <;> cases true <;> cases true + case nonexistent => + skip diff --git a/tests/lean/caseSuggestions.lean.expected.out b/tests/lean/caseSuggestions.lean.expected.out new file mode 100644 index 000000000000..eb7b2cb2ccae --- /dev/null +++ b/tests/lean/caseSuggestions.lean.expected.out @@ -0,0 +1,42 @@ +caseSuggestions.lean:11:2-12:8: error: Case tag 'nonexistent' not found. + +There are no cases to select. +caseSuggestions.lean:20:2-21:8: error: Case tag 'nonexistent' not found. + +The only available case tag is 'unit'. +caseSuggestions.lean:29:2-30:8: error: Case tag 'nonexistent' not found. + +Available tags: 'false', 'true' +caseSuggestions.lean:34:2-35:8: error: Case tag 'nonexistent' not found. + +Available tags: 'false.false', 'false.true', 'true.false', 'true.true' +caseSuggestions.lean:39:2-40:8: error: Case tag 'nonexistent' not found. + +Available tags: + 'false.false.false', + 'false.false.true', + 'false.true.false', + 'false.true.true', + 'true.false.false', + 'true.false.true', + 'true.true.false', + 'true.true.true' +caseSuggestions.lean:44:2-45:8: error: Case tag 'nonexistent' not found. + +Available tags: + 'false.false.false.false', + 'false.false.false.true', + 'false.false.true.false', + 'false.false.true.true', + 'false.true.false.false', + 'false.true.false.true', + 'false.true.true.false', + 'false.true.true.true', + 'true.false.false.false', + 'true.false.false.true', + 'true.false.true.false', + 'true.false.true.true', + 'true.true.false.false', + 'true.true.false.true', + 'true.true.true.false', + 'true.true.true.true' From 184318fd8b3e46000b45c54046274f27159f041f Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Sat, 7 Oct 2023 11:10:41 +0200 Subject: [PATCH 25/71] fix: eliminate widestring uses --- src/runtime/io.cpp | 9 ++++----- src/util/path.cpp | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/runtime/io.cpp b/src/runtime/io.cpp index 86c206024e69..93b67c0f85a6 100644 --- a/src/runtime/io.cpp +++ b/src/runtime/io.cpp @@ -690,11 +690,10 @@ extern "C" LEAN_EXPORT obj_res lean_io_remove_file(b_obj_arg fname, obj_arg) { extern "C" LEAN_EXPORT obj_res lean_io_app_path(obj_arg) { #if defined(LEAN_WINDOWS) - HMODULE hModule = GetModuleHandleW(NULL); - WCHAR path[MAX_PATH]; - GetModuleFileNameW(hModule, path, MAX_PATH); - std::wstring pathwstr(path); - std::string pathstr(pathwstr.begin(), pathwstr.end()); + HMODULE hModule = GetModuleHandle(NULL); + char path[MAX_PATH]; + GetModuleFileName(hModule, path, MAX_PATH); + std::string pathstr(path); // Hack for making sure disk is lower case // TODO(Leo): more robust solution if (pathstr.size() >= 2 && pathstr[1] == ':') { diff --git a/src/util/path.cpp b/src/util/path.cpp index 0bfe6d963180..c61acee262a1 100644 --- a/src/util/path.cpp +++ b/src/util/path.cpp @@ -42,11 +42,10 @@ static char g_path_sep = ';'; static constexpr char g_sep = '\\'; static char g_bad_sep = '/'; std::string get_exe_location() { - HMODULE hModule = GetModuleHandleW(NULL); - WCHAR path[MAX_PATH]; - GetModuleFileNameW(hModule, path, MAX_PATH); - std::wstring pathstr(path); - return std::string(pathstr.begin(), pathstr.end()); + HMODULE hModule = GetModuleHandle(NULL); + char path[MAX_PATH]; + GetModuleFileName(hModule, path, MAX_PATH); + return std::string(path); } bool is_path_sep(char c) { return c == g_path_sep; } #elif defined(__APPLE__) From 8d7520b36f00ab6e85b50e3673485dd07e90e1a4 Mon Sep 17 00:00:00 2001 From: int-y1 Date: Sat, 7 Oct 2023 21:32:59 -0700 Subject: [PATCH 26/71] chore: fix typos in comments --- src/Lean/Compiler/IR/EmitLLVM.lean | 2 +- src/Lean/Compiler/IR/ExpandResetReuse.lean | 4 ++-- src/Lean/Compiler/IR/ResetReuse.lean | 2 +- src/Lean/Compiler/LCNF/Basic.lean | 4 ++-- src/Lean/Compiler/LCNF/Closure.lean | 2 +- src/Lean/Compiler/LCNF/ElimDeadBranches.lean | 4 ++-- src/Lean/Compiler/LCNF/FloatLetIn.lean | 6 ++--- src/Lean/Compiler/LCNF/JoinPoints.lean | 2 +- src/Lean/Compiler/LCNF/Level.lean | 2 +- src/Lean/Compiler/LCNF/ReduceArity.lean | 2 +- src/Lean/Compiler/LCNF/Simp/JpCases.lean | 4 ++-- src/Lean/Compiler/LCNF/Simp/SimpM.lean | 2 +- src/Lean/Compiler/LCNF/SpecInfo.lean | 2 +- src/Lean/Data/Json/Basic.lean | 2 +- src/Lean/Data/Lsp/CodeActions.lean | 2 +- src/Lean/Data/Name.lean | 2 +- src/Lean/Elab/Binders.lean | 4 ++-- src/Lean/Elab/BuiltinCommand.lean | 2 +- src/Lean/Elab/BuiltinNotation.lean | 2 +- src/Lean/Elab/Calc.lean | 2 +- src/Lean/Elab/DeclarationRange.lean | 2 +- src/Lean/Elab/Do.lean | 2 +- src/Lean/Elab/Inductive.lean | 6 ++--- src/Lean/Elab/InfoTree/Main.lean | 2 +- src/Lean/Elab/Match.lean | 6 ++--- src/Lean/Elab/MutualDef.lean | 2 +- src/Lean/Elab/PreDefinition/Eqns.lean | 2 +- .../Elab/PreDefinition/Structural/Basic.lean | 2 +- src/Lean/Elab/StructInst.lean | 2 +- src/Lean/Elab/Structure.lean | 2 +- src/Lean/Elab/SyntheticMVars.lean | 6 ++--- src/Lean/Elab/Tactic/ElabTerm.lean | 2 +- src/Lean/Elab/Tactic/Induction.lean | 2 +- src/Lean/Expr.lean | 14 +++++------ src/Lean/Hygiene.lean | 2 +- src/Lean/Level.lean | 2 +- src/Lean/Meta/ACLt.lean | 4 ++-- src/Lean/Meta/AbstractNestedProofs.lean | 2 +- src/Lean/Meta/AppBuilder.lean | 4 ++-- src/Lean/Meta/Basic.lean | 24 +++++++++---------- src/Lean/Meta/CollectMVars.lean | 4 ++-- src/Lean/Meta/DiscrTree.lean | 4 ++-- src/Lean/Meta/ExprDefEq.lean | 20 ++++++++-------- src/Lean/Meta/IndPredBelow.lean | 4 ++-- src/Lean/Meta/Instances.lean | 2 +- src/Lean/Meta/KExprMap.lean | 2 +- src/Lean/Meta/Match/Basic.lean | 2 +- src/Lean/Meta/Match/CaseValues.lean | 2 +- src/Lean/Meta/Match/Match.lean | 6 ++--- src/Lean/Meta/Match/MatchEqs.lean | 4 ++-- src/Lean/Meta/Match/Value.lean | 2 +- src/Lean/Meta/Offset.lean | 2 +- src/Lean/Meta/PPGoal.lean | 2 +- src/Lean/Meta/SynthInstance.lean | 4 ++-- src/Lean/Meta/Tactic/Cases.lean | 2 +- src/Lean/Meta/Tactic/Revert.lean | 2 +- src/Lean/Meta/Tactic/Simp/Main.lean | 2 +- .../Meta/Tactic/Simp/SimpCongrTheorems.lean | 2 +- src/Lean/Meta/Tactic/Simp/SimpTheorems.lean | 2 +- src/Lean/Meta/Tactic/Split.lean | 2 +- src/Lean/Meta/Tactic/UnifyEq.lean | 6 ++--- src/Lean/Meta/WHNF.lean | 2 +- src/Lean/MetavarContext.lean | 2 +- src/Lean/Parser/Basic.lean | 6 ++--- src/Lean/ResolveName.lean | 6 ++--- src/Lean/Server/AsyncList.lean | 2 +- src/Lean/Server/FileWorker.lean | 10 ++++---- src/Lean/Server/InfoUtils.lean | 2 +- src/Lean/Server/Watchdog.lean | 2 +- src/Lean/Util/OccursCheck.lean | 2 +- tests/lean/docStr.lean.expected.out | 2 +- 71 files changed, 129 insertions(+), 129 deletions(-) diff --git a/src/Lean/Compiler/IR/EmitLLVM.lean b/src/Lean/Compiler/IR/EmitLLVM.lean index 350dd4925702..fb9a6b6fa386 100644 --- a/src/Lean/Compiler/IR/EmitLLVM.lean +++ b/src/Lean/Compiler/IR/EmitLLVM.lean @@ -1044,7 +1044,7 @@ mutual partial def emitCase (builder : LLVM.Builder llvmctx) (x : VarId) (xType : IRType) (alts : Array Alt) : M llvmctx Unit := do let oldBB ← LLVM.getInsertBlock builder - -- NOTE: In this context, 'Zext' versus 'Sext' have a meaninful semantic difference. + -- NOTE: In this context, 'Zext' versus 'Sext' have a meaningful semantic difference. -- We perform a zero extend so that one-bit tags of `0/-1` actually extend to `0/1` -- in 64-bit space. let tag ← emitTag builder x xType diff --git a/src/Lean/Compiler/IR/ExpandResetReuse.lean b/src/Lean/Compiler/IR/ExpandResetReuse.lean index aab8af752ca8..7352601f6e5c 100644 --- a/src/Lean/Compiler/IR/ExpandResetReuse.lean +++ b/src/Lean/Compiler/IR/ExpandResetReuse.lean @@ -86,7 +86,7 @@ partial def eraseProjIncForAux (y : VarId) (bs : Array FnBody) (mask : Mask) (ke def eraseProjIncFor (n : Nat) (y : VarId) (bs : Array FnBody) : Array FnBody × Mask := eraseProjIncForAux y bs (mkArray n none) #[] -/-- Replace `reuse x ctor ...` with `ctor ...`, and remoce `dec x` -/ +/-- Replace `reuse x ctor ...` with `ctor ...`, and remove `dec x` -/ partial def reuseToCtor (x : VarId) : FnBody → FnBody | FnBody.dec y n c p b => if x == y then b -- n must be 1 since `x := reset ...` @@ -236,7 +236,7 @@ def mkFastPath (x y : VarId) (mask : Mask) (b : FnBody) : M FnBody := do partial def expand (mainFn : FnBody → Array FnBody → M FnBody) (bs : Array FnBody) (x : VarId) (n : Nat) (y : VarId) (b : FnBody) : M FnBody := do let (bs, mask) := eraseProjIncFor n y bs - /- Remark: we may be duplicting variable/JP indices. That is, `bSlow` and `bFast` may + /- Remark: we may be duplicating variable/JP indices. That is, `bSlow` and `bFast` may have duplicate indices. We run `normalizeIds` to fix the ids after we have expand them. -/ let bSlow := mkSlowPath x y mask b let bFast ← mkFastPath x y mask b diff --git a/src/Lean/Compiler/IR/ResetReuse.lean b/src/Lean/Compiler/IR/ResetReuse.lean index 9566eb5758dc..a358f3afcc5e 100644 --- a/src/Lean/Compiler/IR/ResetReuse.lean +++ b/src/Lean/Compiler/IR/ResetReuse.lean @@ -9,7 +9,7 @@ import Lean.Compiler.IR.Format namespace Lean.IR.ResetReuse /-! Remark: the insertResetReuse transformation is applied before we have - inserted `inc/dec` instructions, and perfomed lower level optimizations + inserted `inc/dec` instructions, and performed lower level optimizations that introduce the instructions `release` and `set`. -/ /-! Remark: the functions `S`, `D` and `R` defined here implement the diff --git a/src/Lean/Compiler/LCNF/Basic.lean b/src/Lean/Compiler/LCNF/Basic.lean index 009ffc7ae78e..a0c6a21224c2 100644 --- a/src/Lean/Compiler/LCNF/Basic.lean +++ b/src/Lean/Compiler/LCNF/Basic.lean @@ -471,7 +471,7 @@ structure Decl where of this kind. See `DefinitionSafety`. `partial` and `unsafe` functions may not be terminating, but Lean functions terminate, and some static analyzers exploit this - fact. So, we use the following semantics. Suppose whe hav a (large) natural + fact. So, we use the following semantics. Suppose we have a (large) natural number `C`. We consider a nondeterministic model for computation of Lean expressions as follows: Each call to a partial/unsafe function uses up one "recursion token". @@ -490,7 +490,7 @@ structure Decl where safe : Bool := true /-- We store the inline attribute at LCNF declarations to make sure we can set them for - auxliary declarations created during compilation. + auxiliary declarations created during compilation. -/ inlineAttr? : Option InlineAttributeKind deriving Inhabited, BEq diff --git a/src/Lean/Compiler/LCNF/Closure.lean b/src/Lean/Compiler/LCNF/Closure.lean index 788e99f61b6e..450e4ef1820e 100644 --- a/src/Lean/Compiler/LCNF/Closure.lean +++ b/src/Lean/Compiler/LCNF/Closure.lean @@ -24,7 +24,7 @@ structure Context where inScope : FVarId → Bool /-- If `abstract x` returns `true`, we convert `x` into a closure parameter. Otherwise, - we collect the dependecies in the `let`/`fun`-declaration too, and include the declaration in the closure. + we collect the dependencies in the `let`/`fun`-declaration too, and include the declaration in the closure. Remark: the lambda lifting pass abstracts all `let`/`fun`-declarations. -/ abstract : FVarId → Bool diff --git a/src/Lean/Compiler/LCNF/ElimDeadBranches.lean b/src/Lean/Compiler/LCNF/ElimDeadBranches.lean index 160a574c7775..fc15d5935250 100644 --- a/src/Lean/Compiler/LCNF/ElimDeadBranches.lean +++ b/src/Lean/Compiler/LCNF/ElimDeadBranches.lean @@ -26,7 +26,7 @@ inductive Value where -/ | top /-- - A certian consructor with a certain sets of parameters is possible. + A certain constructor with a certain sets of parameters is possible. -/ | ctor (i : Name) (vs : Array Value) /-- @@ -531,7 +531,7 @@ partial def inferMain : InterpM Unit := do return () /-- -Use the information produced by the abstract interpeter to: +Use the information produced by the abstract interpreter to: - Eliminate branches that we know cannot be hit - Eliminate values that we know have to be constants. -/ diff --git a/src/Lean/Compiler/LCNF/FloatLetIn.lean b/src/Lean/Compiler/LCNF/FloatLetIn.lean index 9849a20c8155..174a9d47762c 100644 --- a/src/Lean/Compiler/LCNF/FloatLetIn.lean +++ b/src/Lean/Compiler/LCNF/FloatLetIn.lean @@ -187,7 +187,7 @@ Will: | n => x * y | m => z ``` - If we are at `y` `x` is alreayd marked to be floated into `n` as well. + If we are at `y` `x` is already marked to be floated into `n` as well. - if there hasn't be a decision yet, that is they are marked with `.unknown` we float them into the same arm as the current value: ``` @@ -211,7 +211,7 @@ Will: When we visit `a` `x` is now marked as getting moved into `n` but since it also occurs in `a` which wants to be moved somewhere else we will instead decide to not move `x` at all. - - if they are meant to be floated somewhere else decide that they wont get floated: + - if they are meant to be floated somewhere else decide that they won't get floated: ``` let x := ... let y := x + z @@ -234,7 +234,7 @@ where modify fun s => { s with decision := s.decision.insert fvar arm } /-- -Iterate throgh `decl`, pushing local declarations that are only used in one +Iterate through `decl`, pushing local declarations that are only used in one control flow arm into said arm in order to avoid useless computations. -/ partial def floatLetIn (decl : Decl) : CompilerM Decl := do diff --git a/src/Lean/Compiler/LCNF/JoinPoints.lean b/src/Lean/Compiler/LCNF/JoinPoints.lean index 6acbb730affd..09dfdf2341eb 100644 --- a/src/Lean/Compiler/LCNF/JoinPoints.lean +++ b/src/Lean/Compiler/LCNF/JoinPoints.lean @@ -342,7 +342,7 @@ def mergeJpContextIfNecessary (jp : FVarId) : ExtendM Unit := do /-- We call this whenever we enter a new local function. It clears both the -current join point and the list of candidates since we cant lift join +current join point and the list of candidates since we can't lift join points outside of functions as explained in `mergeJpContextIfNecessary`. -/ def withNewFunScope (decl : FunDecl) (x : ExtendM α): ExtendM α := do diff --git a/src/Lean/Compiler/LCNF/Level.lean b/src/Lean/Compiler/LCNF/Level.lean index cd4984d80e4e..4275ce9af04a 100644 --- a/src/Lean/Compiler/LCNF/Level.lean +++ b/src/Lean/Compiler/LCNF/Level.lean @@ -33,7 +33,7 @@ structure State where /-- Parameters that have been normalized. -/ paramNames : Array Name := #[] -/-- Monad for the universe leve normalizer -/ +/-- Monad for the universe level normalizer -/ abbrev M := StateM State /-- diff --git a/src/Lean/Compiler/LCNF/ReduceArity.lean b/src/Lean/Compiler/LCNF/ReduceArity.lean index 9b862b81e5f5..4518494b9699 100644 --- a/src/Lean/Compiler/LCNF/ReduceArity.lean +++ b/src/Lean/Compiler/LCNF/ReduceArity.lean @@ -13,7 +13,7 @@ namespace Lean.Compiler.LCNF # Function arity reduction This module finds "used" parameters in a declaration, and then -create an auxliary declaration that contains only used parameters. +create an auxiliary declaration that contains only used parameters. For example: ``` def f (x y : Nat) : Nat := diff --git a/src/Lean/Compiler/LCNF/Simp/JpCases.lean b/src/Lean/Compiler/LCNF/Simp/JpCases.lean index a012e1842f8f..962fb2fc3690 100644 --- a/src/Lean/Compiler/LCNF/Simp/JpCases.lean +++ b/src/Lean/Compiler/LCNF/Simp/JpCases.lean @@ -105,7 +105,7 @@ abbrev Ctor2JpCasesAlt := FVarIdMap (NameMap JpCasesAlt) open Internalize in /-- -Construct an auxiliary join point for a particular alternative in a join-point that satifies `isJpCases?`. +Construct an auxiliary join point for a particular alternative in a join-point that satisfies `isJpCases?`. - `decls` is the prefix (before the `cases`). See `isJpCases?`. - `params` are the parameters of the main join point that satisfies `isJpCases?`. - `targetParamIdx` is the index of the parameter that we are expanding to `fields` @@ -149,7 +149,7 @@ private def mkJmpArgsAtJp (params : Array Param) (targetParamIdx : Nat) (fields /-- Try to optimize `jpCases` join points. -We say a join point is a `jpCases` when it satifies the predicate `isJpCases`. +We say a join point is a `jpCases` when it satisfies the predicate `isJpCases`. If we have a jump to `jpCases` with a constructor, then we can optimize the code by creating an new join point for the constructor. Example: suppose we have diff --git a/src/Lean/Compiler/LCNF/Simp/SimpM.lean b/src/Lean/Compiler/LCNF/Simp/SimpM.lean index 59ae4baa69cc..4deab43c23fe 100644 --- a/src/Lean/Compiler/LCNF/Simp/SimpM.lean +++ b/src/Lean/Compiler/LCNF/Simp/SimpM.lean @@ -139,7 +139,7 @@ where return numOccs /-- -Similar to the default `Lean.withIncRecDepth`, but include the `inlineStack` in the error messsage. +Similar to the default `Lean.withIncRecDepth`, but include the `inlineStack` in the error message. -/ @[inline] def withIncRecDepth (x : SimpM α) : SimpM α := do let curr ← MonadRecDepth.getRecDepth diff --git a/src/Lean/Compiler/LCNF/SpecInfo.lean b/src/Lean/Compiler/LCNF/SpecInfo.lean index d0553efe669e..fa6d6e4b03a7 100644 --- a/src/Lean/Compiler/LCNF/SpecInfo.lean +++ b/src/Lean/Compiler/LCNF/SpecInfo.lean @@ -103,7 +103,7 @@ private def isNoSpecType (env : Environment) (type : Expr) : Bool := *Note*: `fixedNeutral` must have forward dependencies. The code specializer consider a `fixedNeutral` parameter during code specialization -only if it contains forward dependecies that are tagged as `.user`, `.fixedHO`, or `.fixedInst`. +only if it contains forward dependencies that are tagged as `.user`, `.fixedHO`, or `.fixedInst`. The motivation is to minimize the number of code specializations that have little or no impact on performance. For example, let's consider the function. ``` diff --git a/src/Lean/Data/Json/Basic.lean b/src/Lean/Data/Json/Basic.lean index 46bdb5062174..263755ee6284 100644 --- a/src/Lean/Data/Json/Basic.lean +++ b/src/Lean/Data/Json/Basic.lean @@ -114,7 +114,7 @@ protected def toString : JsonNumber → String protected def shiftl : JsonNumber → Nat → JsonNumber -- if s ≤ e, then 10 ^ (s - e) = 1, and hence the mantissa remains unchanged. -- otherwise, the expression pads the mantissa with zeroes - -- to accomodate for the remaining places to shift. + -- to accommodate for the remaining places to shift. | ⟨m, e⟩, s => ⟨m * (10 ^ (s - e) : Nat), e - s⟩ -- shift a JsonNumber by a specified amount of places to the right diff --git a/src/Lean/Data/Lsp/CodeActions.lean b/src/Lean/Data/Lsp/CodeActions.lean index dcaa16c74f4e..6b4c97e6854d 100644 --- a/src/Lean/Data/Lsp/CodeActions.lean +++ b/src/Lean/Data/Lsp/CodeActions.lean @@ -83,7 +83,7 @@ structure CodeActionParams extends WorkDoneProgressParams, PartialResultParams w context : CodeActionContext := {} deriving FromJson, ToJson -/-- If the code action is disabled, this type gives the reson why. -/ +/-- If the code action is disabled, this type gives the reason why. -/ structure CodeActionDisabled where reason : String deriving FromJson, ToJson diff --git a/src/Lean/Data/Name.lean b/src/Lean/Data/Name.lean index b97a95996958..5ea21e385f75 100644 --- a/src/Lean/Data/Name.lean +++ b/src/Lean/Data/Name.lean @@ -133,7 +133,7 @@ def isNum : Name → Bool | _ => false /-- -Return `true` if `n` contains a string part `s` that satifies `f`. +Return `true` if `n` contains a string part `s` that satisfies `f`. Examples: ``` diff --git a/src/Lean/Elab/Binders.lean b/src/Lean/Elab/Binders.lean index 6f5ab35c6d98..39218390659b 100644 --- a/src/Lean/Elab/Binders.lean +++ b/src/Lean/Elab/Binders.lean @@ -132,7 +132,7 @@ private def getBinderIds (ids : Syntax) : TermElabM (Array Syntax) := /-- Convert `stx` into an array of `BinderView`s. -`stx` must be an indentifier, `_`, `explicitBinder`, `implicitBinder`, `strictImplicitBinder`, or `instBinder`. +`stx` must be an identifier, `_`, `explicitBinder`, `implicitBinder`, `strictImplicitBinder`, or `instBinder`. -/ private def toBinderViews (stx : Syntax) : TermElabM (Array BinderView) := do let k := stx.getKind @@ -233,7 +233,7 @@ def elabBindersEx (binders : Array Syntax) (k : Array (Syntax × Expr) → TermE /-- Elaborate the given binders (i.e., `Syntax` objects for `bracketedBinder`), - update the local context, set of local instances, reset instance chache (if needed), and then + update the local context, set of local instances, reset instance cache (if needed), and then execute `k` with the updated context. The local context will only be included inside `k`. diff --git a/src/Lean/Elab/BuiltinCommand.lean b/src/Lean/Elab/BuiltinCommand.lean index 482a45bec8fa..9d5cfddfcbc2 100644 --- a/src/Lean/Elab/BuiltinCommand.lean +++ b/src/Lean/Elab/BuiltinCommand.lean @@ -158,7 +158,7 @@ private def containsId (ids : Array (TSyntax [`ident, ``Parser.Term.hole])) (id /-- Auxiliary method for processing binder annotation update commands: `variable (α)` and `variable {α}`. The argument `binder` is the binder of the `variable` command. - The method retuns an array containing the "residue", that is, variables that do not correspond to updates. + The method returns an array containing the "residue", that is, variables that do not correspond to updates. Recall that a `bracketedBinder` can be of the form `(x y)`. ``` variable {α β : Type} diff --git a/src/Lean/Elab/BuiltinNotation.lean b/src/Lean/Elab/BuiltinNotation.lean index e2ff3e907da6..9b9473157a32 100644 --- a/src/Lean/Elab/BuiltinNotation.lean +++ b/src/Lean/Elab/BuiltinNotation.lean @@ -82,7 +82,7 @@ open Meta let type ← withSynthesize (mayPostpone := true) do let type ← elabType type if let some expectedType := expectedType? then - -- Recall that a similiar approach is used when elaborating applications + -- Recall that a similar approach is used when elaborating applications discard <| isDefEq expectedType type return type /- diff --git a/src/Lean/Elab/Calc.lean b/src/Lean/Elab/Calc.lean index 6240c45eaba9..0a33a18cb890 100644 --- a/src/Lean/Elab/Calc.lean +++ b/src/Lean/Elab/Calc.lean @@ -46,7 +46,7 @@ def mkCalcTrans (result resultType step stepType : Expr) : MetaM (Expr × Expr) /-- Adds a type annotation to a hole that occurs immediately at the beginning of the term. This is so that coercions can trigger when elaborating the term. -See https://github.com/leanprover/lean4/issues/2040 for futher rationale. +See https://github.com/leanprover/lean4/issues/2040 for further rationale. - `_ < 3` is annotated - `(_) < 3` is not, because it occurs after an atom diff --git a/src/Lean/Elab/DeclarationRange.lean b/src/Lean/Elab/DeclarationRange.lean index 9c403828ee29..792879cc55a0 100644 --- a/src/Lean/Elab/DeclarationRange.lean +++ b/src/Lean/Elab/DeclarationRange.lean @@ -48,7 +48,7 @@ def getDeclarationSelectionRef (stx : Syntax) : Syntax := /-- - Store the `range` and `selectionRange` for `declName` where `stx` is the whole syntax object decribing `declName`. + Store the `range` and `selectionRange` for `declName` where `stx` is the whole syntax object describing `declName`. This method is for the builtin declarations only. User-defined commands should use `Lean.addDeclarationRanges` to store this information for their commands. -/ def addDeclarationRanges [Monad m] [MonadEnv m] [MonadFileMap m] (declName : Name) (stx : Syntax) : m Unit := do diff --git a/src/Lean/Elab/Do.lean b/src/Lean/Elab/Do.lean index 847791bc12f5..386522349890 100644 --- a/src/Lean/Elab/Do.lean +++ b/src/Lean/Elab/Do.lean @@ -501,7 +501,7 @@ def homogenize (c₁ c₂ : CodeBlock) : TermElabM (CodeBlock × CodeBlock) := d /-- Extending code blocks with variable declarations: `let x : t := v` and `let x : t ← v`. -We remove `x` from the collection of updated varibles. +We remove `x` from the collection of updated variables. Remark: `stx` is the syntax for the declaration (e.g., `letDecl`), and `xs` are the variables declared by it. It is an array because we have let-declarations that declare multiple variables. Example: `let (x, y) := t` diff --git a/src/Lean/Elab/Inductive.lean b/src/Lean/Elab/Inductive.lean index f3d98d0587b2..a2f38eebc61e 100644 --- a/src/Lean/Elab/Inductive.lean +++ b/src/Lean/Elab/Inductive.lean @@ -228,7 +228,7 @@ where type /-- - Reorder contructor arguments to improve the effectiveness of the `fixedIndicesToParams` method. + Reorder constructor arguments to improve the effectiveness of the `fixedIndicesToParams` method. The idea is quite simple. Given a constructor type of the form ``` @@ -267,7 +267,7 @@ private def reorderCtorArgs (ctorType : Expr) : MetaM Expr := do let r ← mkForallFVars (bsPrefix ++ as) type /- `r` already contains the resulting type. To be able to produce more better error messages, we copy the first `bsPrefix.size` binder names from `C` to `r`. - This is important when some of contructor parameters were inferred using the auto-bound implicit feature. + This is important when some of constructor parameters were inferred using the auto-bound implicit feature. For example, in the following declaration. ``` inductive Member : α → List α → Type u @@ -549,7 +549,7 @@ private def checkResultingUniverses (views : Array InductiveView) (numParams : N /- Special case: The constructor parameter `v` is at unverse level `?v+k` and the resulting inductive universe level is `u'+k`, where `u'` is a parameter (or zero). - Thus, `?v := u'` is the only choice for satisfying the universe contraint `?v+k <= u'+k`. + Thus, `?v := u'` is the only choice for satisfying the universe constraint `?v+k <= u'+k`. Note that, we still generate an error for cases where there is more than one of satisfying the constraint. Examples: ----------------------------------------------------------- diff --git a/src/Lean/Elab/InfoTree/Main.lean b/src/Lean/Elab/InfoTree/Main.lean index 7dc2dc55302c..10ee3eb13b4f 100644 --- a/src/Lean/Elab/InfoTree/Main.lean +++ b/src/Lean/Elab/InfoTree/Main.lean @@ -52,7 +52,7 @@ partial def InfoTree.findInfo? (p : Info → Bool) (t : InfoTree) : Option Info | _ => none /-- Instantiate the holes on the given `tree` with the assignment table. -(analoguous to instantiating the metavariables in an expression) -/ +(analogous to instantiating the metavariables in an expression) -/ partial def InfoTree.substitute (tree : InfoTree) (assignment : PersistentHashMap MVarId InfoTree) : InfoTree := match tree with | node i c => node i <| c.map (substitute · assignment) diff --git a/src/Lean/Elab/Match.lean b/src/Lean/Elab/Match.lean index 22e5dd297c92..1b183f9134e0 100644 --- a/src/Lean/Elab/Match.lean +++ b/src/Lean/Elab/Match.lean @@ -121,7 +121,7 @@ where This transformation was added to address issue #1155, and avoid an unnecessary dependency. In issue #1155, `discrType` was of the form `let _discr := OfNat.ofNat ... 0 ?m; ...`, and not removing the unnecessary `let-expr` was introducing an artificial dependency to `?m`. - TODO: make sure that even when this kind of artificial dependecy occurs we catch it before sending + TODO: make sure that even when this kind of artificial dependency occurs we catch it before sending the term to the kernel. -/ let discrType ← transform (usedLetOnly := true) (← instantiateMVars (← inferType discr)) @@ -593,7 +593,7 @@ abbrev TopSortM := StateRefT TopSort.State TermElabM /-- Topological sort. We need it because inaccessible patterns may contain pattern variables that are declared later. That is, processing patterns from left to right to do not guarantee that the pattern variables are collected in the - "right" order. "Right" here means pattern `x` must occur befor pattern `y` if `y`s type depends on `x`. + "right" order. "Right" here means pattern `x` must occur before pattern `y` if `y`s type depends on `x`. -/ private partial def topSort (patternVars : Array Expr) : TermElabM (Array Expr) := do let (_, s) ← patternVars.mapM visit |>.run {} @@ -1037,7 +1037,7 @@ private def elabMatchAux (generalizing? : Option Bool) (discrStxs : Array Syntax | _ => pure () ``` If `synthesizeSyntheticMVarsNoPostponing`, the example above fails at `x.fst` because - the type of `x` is only available after we proces the last argument of `List.forM`. + the type of `x` is only available after we process the last argument of `List.forM`. We apply pending default types to make sure we can process examples such as ``` diff --git a/src/Lean/Elab/MutualDef.lean b/src/Lean/Elab/MutualDef.lean index e37eb7d206ef..5d9bdd5d443d 100644 --- a/src/Lean/Elab/MutualDef.lean +++ b/src/Lean/Elab/MutualDef.lean @@ -32,7 +32,7 @@ structure DefViewElabHeader where declName : Name /-- Universe level parameter names explicitly provided by the user. -/ levelNames : List Name - /-- Syntax objects for the binders occurring befor `:`, we use them to populate the `InfoTree` when elaborating `valueStx`. -/ + /-- Syntax objects for the binders occurring before `:`, we use them to populate the `InfoTree` when elaborating `valueStx`. -/ binderIds : Array Syntax /-- Number of parameters before `:`, it also includes auto-implicit parameters automatically added by Lean. -/ numParams : Nat diff --git a/src/Lean/Elab/PreDefinition/Eqns.lean b/src/Lean/Elab/PreDefinition/Eqns.lean index ce6d9e2fbb8d..670143db6908 100644 --- a/src/Lean/Elab/PreDefinition/Eqns.lean +++ b/src/Lean/Elab/PreDefinition/Eqns.lean @@ -319,7 +319,7 @@ builtin_initialize unfoldEqnExt : EnvExtension UnfoldEqnExtState ← ``` declName x_1 ... x_n = body[x_1, ..., x_n] ``` - The proof is constracted using the automatically generated equational theorems. + The proof is constructed using the automatically generated equational theorems. We basically keep splitting the `match` and `if-then-else` expressions in the right hand side until one of the equational theorems is applicable. -/ diff --git a/src/Lean/Elab/PreDefinition/Structural/Basic.lean b/src/Lean/Elab/PreDefinition/Structural/Basic.lean index c3f392129ecb..4c99253e0b3e 100644 --- a/src/Lean/Elab/PreDefinition/Structural/Basic.lean +++ b/src/Lean/Elab/PreDefinition/Structural/Basic.lean @@ -54,7 +54,7 @@ def run (x : M α) (s : State := {}) : MetaM (α × State) := the argument we are trying to recurse on, and it contains loose bound variables. We use this test to decide whether we should process a matcher-application as a regular - applicaton or not. That is, whether we should push the `below` argument should be affected by the matcher or not. + application or not. That is, whether we should push the `below` argument should be affected by the matcher or not. If `e` does not contain an application of the form `recFnName .. t ..`, then we know the recursion doesn't depend on any pattern variable in this matcher. -/ diff --git a/src/Lean/Elab/StructInst.lean b/src/Lean/Elab/StructInst.lean index 51cc3c1cc9ee..6a2cb23260e4 100644 --- a/src/Lean/Elab/StructInst.lean +++ b/src/Lean/Elab/StructInst.lean @@ -647,7 +647,7 @@ private partial def elabStruct (s : Struct) (expectedType? : Option Expr) : Term namespace DefaultFields structure Context where - -- We must search for default values overriden in derived structures + -- We must search for default values overridden in derived structures structs : Array Struct := #[] allStructNames : Array Name := #[] /-- diff --git a/src/Lean/Elab/Structure.lean b/src/Lean/Elab/Structure.lean index f776f61f4a4f..1040c0e7159e 100644 --- a/src/Lean/Elab/Structure.lean +++ b/src/Lean/Elab/Structure.lean @@ -321,7 +321,7 @@ private def toVisibility (fieldInfo : StructureFieldInfo) : CoreM Visibility := abbrev FieldMap := NameMap Expr -- Map from field name to expression representing the field -/-- Reduce projetions of the structures in `structNames` -/ +/-- Reduce projections of the structures in `structNames` -/ private def reduceProjs (e : Expr) (structNames : NameSet) : MetaM Expr := let reduce (e : Expr) : MetaM TransformStep := do match (← reduceProjOf? e structNames.contains) with diff --git a/src/Lean/Elab/SyntheticMVars.lean b/src/Lean/Elab/SyntheticMVars.lean index d0bb07faef3a..9ed56cc650d3 100644 --- a/src/Lean/Elab/SyntheticMVars.lean +++ b/src/Lean/Elab/SyntheticMVars.lean @@ -274,7 +274,7 @@ private def throwStuckAtUniverseCnstr : TermElabM Unit := do ``` Another benefit of using `withoutPostponingUniverseConstraints` is better error messages. Instead of getting a mysterious type mismatch constraint, we get a list of - universe contraints the system is stuck at. + universe constraints the system is stuck at. -/ private def processPostponedUniverseContraints : TermElabM Unit := do unless (← processPostponed (mayPostpone := false) (exceptionOnFailure := true)) do @@ -304,7 +304,7 @@ mutual `?m2` (for `by tac`). When `A` is resumed, it creates a new metavariable `?m3` for the nested `by ...` term in `A`. `?m3` is after `?m2` in the to-do list. Then, we execute `by tac` for synthesizing `?m2`, but its type depends on `?m3`. We have considered putting `?m3` at `?m2` place in the to-do list, but this is not super robust. - The ideal solution is to make sure a tactic "resolves" all pending metavariables nested in their local contex and target type + The ideal solution is to make sure a tactic "resolves" all pending metavariables nested in their local context and target type before starting tactic execution. The procedure would be a generalization of `runPendingTacticsAt`. We can try to combine it with `instantiateMVarDeclMVars` to make sure we do not perform two traversals. Regarding issue #1380, we addressed the issue by avoiding the elaboration postponement step. However, the same issue can happen @@ -415,7 +415,7 @@ mutual Recall that we postponed `x` at `Prod.fst x` because its type it is not known. We the type of `x` may learn later its type and it may contain implicit and/or auto arguments. By disabling postponement, we are essentially giving up the opportunity of learning `x`s type - and assume it does not have implict and/or auto arguments. -/ + and assume it does not have implicit and/or auto arguments. -/ if ← withoutPostponing <| synthesizeSyntheticMVarsStep (postponeOnError := true) (runTactics := false) then loop () else if ← synthesizeUsingDefault then diff --git a/src/Lean/Elab/Tactic/ElabTerm.lean b/src/Lean/Elab/Tactic/ElabTerm.lean index 4e51e416f62b..53032df0340b 100644 --- a/src/Lean/Elab/Tactic/ElabTerm.lean +++ b/src/Lean/Elab/Tactic/ElabTerm.lean @@ -261,7 +261,7 @@ def elabTermForApply (stx : Syntax) (mayPostpone := true) : TacticM Expr := do More complex solution: - We do not disable "error to sorry" - We elaborate term and check whether errors were produced - - If there are other tactic braches and there are errors, we remove the errors from the log, and throw a new error to force the tactic to backtrack. + - If there are other tactic branches and there are errors, we remove the errors from the log, and throw a new error to force the tactic to backtrack. -/ withoutRecover <| elabTerm stx none mayPostpone diff --git a/src/Lean/Elab/Tactic/Induction.lean b/src/Lean/Elab/Tactic/Induction.lean index bbdcdb84fa0d..1e1a0fcbd119 100644 --- a/src/Lean/Elab/Tactic/Induction.lean +++ b/src/Lean/Elab/Tactic/Induction.lean @@ -395,7 +395,7 @@ private def generalizeVars (mvarId : MVarId) (stx : Syntax) (targets : Array Exp return (fvarIds.size, mvarId') /-- -Given `inductionAlts` of the fom +Given `inductionAlts` of the form ``` syntax inductionAlts := "with " (tactic)? withPosition( (colGe inductionAlt)+) ``` diff --git a/src/Lean/Expr.lean b/src/Lean/Expr.lean index 18074aac9371..44e1f7deb2cf 100644 --- a/src/Lean/Expr.lean +++ b/src/Lean/Expr.lean @@ -46,7 +46,7 @@ This can be set to - `implicit` -- `{x : α}` - `strict_implicit` -- `⦃x : α⦄` - `inst_implicit` -- `[x : α]`. -- `aux_decl` -- Auxillary definitions are helper methods that +- `aux_decl` -- Auxiliary definitions are helper methods that Lean generates. `aux_decl` is used for `_match`, `_fun_match`, `_let_match` and the self reference that appears in recursive pattern matching. @@ -67,7 +67,7 @@ inductive BinderInfo where | default /-- Implicit binder annotation, e.g., `{x : α}` -/ | implicit - /-- Strict implict binder annotation, e.g., `{{ x : α }}` -/ + /-- Strict implicit binder annotation, e.g., `{{ x : α }}` -/ | strictImplicit /-- Local instance binder annotataion, e.g., `[Decidable α]` -/ | instImplicit @@ -321,7 +321,7 @@ inductive Expr where /-- The `fvar` constructor represent free variables. These /free/ variable occurrences are not bound by an earlier `lam`, `forallE`, or `letE` - contructor and its binder exists in a local context only. + constructor and its binder exists in a local context only. Note that Lean uses the /locally nameless approach/. See [here](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.365.2479&rep=rep1&type=pdf) for additional details. @@ -1441,7 +1441,7 @@ partial def cleanupAnnotations (e : Expr) : Expr := let e' := e.consumeMData.consumeTypeAnnotations if e' == e then e else cleanupAnnotations e' -/-- Return true iff `e` contains a free variable which statisfies `p`. -/ +/-- Return true iff `e` contains a free variable which satisfies `p`. -/ @[inline] def hasAnyFVar (e : Expr) (p : FVarId → Bool) : Bool := let rec @[specialize] visit (e : Expr) := if !e.hasFVar then false else match e with @@ -1754,21 +1754,21 @@ def isLHSGoal? (e : Expr) : Option Expr := /-- Polymorphic operation for generating unique/fresh free variable identifiers. -It is available in any monad `m` that implements the inferface `MonadNameGenerator`. +It is available in any monad `m` that implements the interface `MonadNameGenerator`. -/ def mkFreshFVarId [Monad m] [MonadNameGenerator m] : m FVarId := return { name := (← mkFreshId) } /-- Polymorphic operation for generating unique/fresh metavariable identifiers. -It is available in any monad `m` that implements the inferface `MonadNameGenerator`. +It is available in any monad `m` that implements the interface `MonadNameGenerator`. -/ def mkFreshMVarId [Monad m] [MonadNameGenerator m] : m MVarId := return { name := (← mkFreshId) } /-- Polymorphic operation for generating unique/fresh universe metavariable identifiers. -It is available in any monad `m` that implements the inferface `MonadNameGenerator`. +It is available in any monad `m` that implements the interface `MonadNameGenerator`. -/ def mkFreshLMVarId [Monad m] [MonadNameGenerator m] : m LMVarId := return { name := (← mkFreshId) } diff --git a/src/Lean/Hygiene.lean b/src/Lean/Hygiene.lean index 167177f5a999..b47e4eaa0fee 100644 --- a/src/Lean/Hygiene.lean +++ b/src/Lean/Hygiene.lean @@ -22,7 +22,7 @@ antiquotations, and if references to globals are prefixed with `_root_.` (which is not allowed to refer to a local variable) `Unhygienic` can also be seen as a model implementation of `MonadQuotation` (since it is completely hygienic as long as it is "run" only once and can -assume that there are no other implentations in use, as is the case for the +assume that there are no other implementations in use, as is the case for the elaboration monads that carry their macro scope state through the entire processing of a file). It uses the state monad to query and allocate the next macro scope, and uses the reader monad to store the stack of scopes diff --git a/src/Lean/Level.lean b/src/Lean/Level.lean index 74868ff82767..83fc26db55ed 100644 --- a/src/Lean/Level.lean +++ b/src/Lean/Level.lean @@ -191,7 +191,7 @@ def mvarId! : Level → LMVarId | mvar mvarId => mvarId | _ => panic! "metavariable expected" -/-- If result is true, then forall assignments `A` which assigns all parameters and metavariables occuring +/-- If result is true, then forall assignments `A` which assigns all parameters and metavariables occurring in `l`, `l[A] != zero` -/ def isNeverZero : Level → Bool | zero => false diff --git a/src/Lean/Meta/ACLt.lean b/src/Lean/Meta/ACLt.lean index 122f1718d2bf..b5cd69d69917 100644 --- a/src/Lean/Meta/ACLt.lean +++ b/src/Lean/Meta/ACLt.lean @@ -38,7 +38,7 @@ mutual Recall that an AC-compatible ordering if it is monotonic, well-founded, and total. Both KBO and LPO are AC-compatible. KBO is faster, but we do not cache the weight of - each expression in Lean 4. Even if we did, we would need to have a weight where implicit instace arguments are ignored. + each expression in Lean 4. Even if we did, we would need to have a weight where implicit instance arguments are ignored. So, we use a LPO-like term ordering. Remark: this method is used to implement ordered rewriting. We ignore implicit instance @@ -120,7 +120,7 @@ where | .fvar id .. => return Name.lt id.name b.fvarId!.name | .mvar id .. => return Name.lt id.name b.mvarId!.name | .sort u .. => return Level.normLt u b.sortLevel! - | .const n .. => return Name.lt n b.constName! -- We igore the levels + | .const n .. => return Name.lt n b.constName! -- We ignore the levels | .lit v .. => return Literal.lt v b.litValue! -- Composite | .proj _ i e .. => if i != b.projIdx! then return i < b.projIdx! else lt e b.projExpr! diff --git a/src/Lean/Meta/AbstractNestedProofs.lean b/src/Lean/Meta/AbstractNestedProofs.lean index b76e65db6247..da83060f82e0 100644 --- a/src/Lean/Meta/AbstractNestedProofs.lean +++ b/src/Lean/Meta/AbstractNestedProofs.lean @@ -36,7 +36,7 @@ private def mkAuxLemma (e : Expr) : M Expr := do let lemmaName ← mkAuxName (ctx.baseName ++ `proof) s.nextIdx modify fun s => { s with nextIdx := s.nextIdx + 1 } /- We turn on zeta-expansion to make sure we don't need to perform an expensive `check` step to - identify which let-decls can be abstracted. If we design a more efficient test, we can avoid the eager zeta expasion step. + identify which let-decls can be abstracted. If we design a more efficient test, we can avoid the eager zeta expansion step. It a benchmark created by @selsam, The extra `check` step was a bottleneck. -/ mkAuxTheoremFor lemmaName e (zeta := true) diff --git a/src/Lean/Meta/AppBuilder.lean b/src/Lean/Meta/AppBuilder.lean index 8309452256ea..39b0f4a408c2 100644 --- a/src/Lean/Meta/AppBuilder.lean +++ b/src/Lean/Meta/AppBuilder.lean @@ -553,7 +553,7 @@ def mkNumeral (type : Expr) (n : Nat) : MetaM Expr := do /-- Return `a op b`, where `op` has name `opName` and is implemented using the typeclass `className`. This method assumes `a` and `b` have the same type, and typeclass `className` is heterogeneous. - Examples of supported clases: `HAdd`, `HSub`, `HMul`. + Examples of supported classes: `HAdd`, `HSub`, `HMul`. We use heterogeneous operators to ensure we have a uniform representation. -/ private def mkBinaryOp (className : Name) (opName : Name) (a b : Expr) : MetaM Expr := do @@ -574,7 +574,7 @@ def mkMul (a b : Expr) : MetaM Expr := mkBinaryOp ``HMul ``HMul.hMul a b /-- Return `a r b`, where `r` has name `rName` and is implemented using the typeclass `className`. This method assumes `a` and `b` have the same type. - Examples of supported clases: `LE` and `LT`. + Examples of supported classes: `LE` and `LT`. We use heterogeneous operators to ensure we have a uniform representation. -/ private def mkBinaryRel (className : Name) (rName : Name) (a b : Expr) : MetaM Expr := do diff --git a/src/Lean/Meta/Basic.lean b/src/Lean/Meta/Basic.lean index 2ed7c55f2de6..bfcce6d207a3 100644 --- a/src/Lean/Meta/Basic.lean +++ b/src/Lean/Meta/Basic.lean @@ -71,11 +71,11 @@ structure Config where constApprox : Bool := false /-- When the following flag is set, - `isDefEq` throws the exeption `Exeption.isDefEqStuck` + `isDefEq` throws the exception `Exeption.isDefEqStuck` whenever it encounters a constraint `?m ... =?= t` where `?m` is read only. This feature is useful for type class resolution where - we may want to notify the caller that the TC problem may be solveable + we may want to notify the caller that the TC problem may be solvable later after it assigns `?m`. -/ isDefEqStuckEx : Bool := false /-- @@ -185,7 +185,7 @@ structure InfoCacheKey where /-- `nargs? = some n` if the cached information was computed assuming the function has arity `n`. If `nargs? = none`, then the cache information consumed the arrow type as much as possible - unsing the current transparency setting. + using the current transparency setting. X-/ nargs? : Option Nat deriving Inhabited, BEq @@ -517,7 +517,7 @@ def findMVarDecl? (mvarId : MVarId) : MetaM (Option MetavarDecl) := /-- Return `mvarId` declaration in the current metavariable context. -Throw an exception if `mvarId` is not declarated in the current metavariable context. +Throw an exception if `mvarId` is not declared in the current metavariable context. -/ def _root_.Lean.MVarId.getDecl (mvarId : MVarId) : MetaM MetavarDecl := do match (← mvarId.findDecl?) with @@ -529,7 +529,7 @@ def getMVarDecl (mvarId : MVarId) : MetaM MetavarDecl := do mvarId.getDecl /-- -Return `mvarId` kind. Throw an exception if `mvarId` is not declarated in the current metavariable context. +Return `mvarId` kind. Throw an exception if `mvarId` is not declared in the current metavariable context. -/ def _root_.Lean.MVarId.getKind (mvarId : MVarId) : MetaM MetavarKind := return (← mvarId.getDecl).kind @@ -538,7 +538,7 @@ def _root_.Lean.MVarId.getKind (mvarId : MVarId) : MetaM MetavarKind := def getMVarDeclKind (mvarId : MVarId) : MetaM MetavarKind := mvarId.getKind -/-- Reture `true` if `e` is a synthetic (or synthetic opaque) metavariable -/ +/-- Return `true` if `e` is a synthetic (or synthetic opaque) metavariable -/ def isSyntheticMVar (e : Expr) : MetaM Bool := do if e.isMVar then return (← e.mvarId!.getKind) matches .synthetic | .syntheticOpaque @@ -778,16 +778,16 @@ def elimMVarDeps (xs : Array Expr) (e : Expr) (preserveOrder : Bool := false) : @[inline] def withTransparency (mode : TransparencyMode) : n α → n α := mapMetaM <| withConfig (fun config => { config with transparency := mode }) -/-- `withDefault x` excutes `x` using the default transparency setting. -/ +/-- `withDefault x` executes `x` using the default transparency setting. -/ @[inline] def withDefault (x : n α) : n α := withTransparency TransparencyMode.default x -/-- `withReducible x` excutes `x` using the reducible transparency setting. In this setting only definitions tagged as `[reducible]` are unfolded. -/ +/-- `withReducible x` executes `x` using the reducible transparency setting. In this setting only definitions tagged as `[reducible]` are unfolded. -/ @[inline] def withReducible (x : n α) : n α := withTransparency TransparencyMode.reducible x /-- -`withReducibleAndInstances x` excutes `x` using the `.instances` transparency setting. In this setting only definitions tagged as `[reducible]` +`withReducibleAndInstances x` executes `x` using the `.instances` transparency setting. In this setting only definitions tagged as `[reducible]` or type class instances are unfolded. -/ @[inline] def withReducibleAndInstances (x : n α) : n α := @@ -924,7 +924,7 @@ mutual dangling bound variables in the range `[j, fvars.size)` - if `reducing? == true` and `type` is not `forallE`, we use `whnf`. - when `type` is not a `forallE` nor it can't be reduced to one, we - excute the continuation `k`. + execute the continuation `k`. Here is an example that demonstrates the `reducing?`. Suppose we have @@ -1048,7 +1048,7 @@ private def forallTelescopeReducingImp (type : Expr) (k : Array Expr → Expr /-- Similar to `forallTelescope`, but given `type` of the form `forall xs, A`, - it reduces `A` and continues bulding the telescope if it is a `forall`. -/ + it reduces `A` and continues building the telescope if it is a `forall`. -/ def forallTelescopeReducing (type : Expr) (k : Array Expr → Expr → n α) : n α := map2MetaM (fun k => forallTelescopeReducingImp type k) k @@ -1599,7 +1599,7 @@ partial def processPostponed (mayPostpone : Bool := true) (exceptionOnFailure := but it was not effective. It is more important to cache aggressively inside of a single `isDefEq` call because some of the heuristics create many similar subproblems. See issue #1102 for an example that triggers an exponential blowup if we don't use this more - aggresive form of caching. + aggressive form of caching. -/ modifyDefEqCache fun _ => {} let postponed ← getResetPostponed diff --git a/src/Lean/Meta/CollectMVars.lean b/src/Lean/Meta/CollectMVars.lean index adc6c5c7c528..728deccccdf0 100644 --- a/src/Lean/Meta/CollectMVars.lean +++ b/src/Lean/Meta/CollectMVars.lean @@ -9,7 +9,7 @@ import Lean.Meta.Basic namespace Lean.Meta /-- - Collect unassigned metavariables occuring in the given expression. + Collect unassigned metavariables occurring in the given expression. Remark: if `e` contains `?m` and there is a `t` assigned to `?m`, we collect unassigned metavariables occurring in `t`. @@ -28,7 +28,7 @@ partial def collectMVars (e : Expr) : StateRefT CollectMVars.State MetaM Unit := | none => pure () | some d => collectMVars (mkMVar d.mvarIdPending) -/-- Return metavariables in occuring the given expression. See `collectMVars` -/ +/-- Return metavariables in occurring the given expression. See `collectMVars` -/ def getMVars (e : Expr) : MetaM (Array MVarId) := do let (_, s) ← (collectMVars e).run {} pure s.result diff --git a/src/Lean/Meta/DiscrTree.lean b/src/Lean/Meta/DiscrTree.lean index 8609250cfd0b..6fb8ccf0818b 100644 --- a/src/Lean/Meta/DiscrTree.lean +++ b/src/Lean/Meta/DiscrTree.lean @@ -131,7 +131,7 @@ instance : Inhabited (DiscrTree α s) where ``` Decidable -> Eq -> * -> * -> * -> [Nat.decEq] ``` - to the discrimination tree IF we ignored the implict `Nat` argument. + to the discrimination tree IF we ignored the implicit `Nat` argument. This would be BAD since **ALL** decidable equality instances would be in the same path. So, we index implicit arguments if they are types. This setting seems sensible for simplification theorems such as: @@ -503,7 +503,7 @@ private def getKeyArgs (e : Expr) (isMatch root : Bool) : MetaM (Key s × Array we want `isDefEq` to throw an exception whenever it tries to assign a read-only metavariable. This feature is useful for type class resolution where - we may want to notify the caller that the TC problem may be solveable + we may want to notify the caller that the TC problem may be solvable later after it assigns `?m`. The method `DiscrTree.getUnify e` returns candidates `c` that may "unify" with `e`. That is, `isDefEq c e` may return true. Now, consider `DiscrTree.getUnify d (Add ?m)` diff --git a/src/Lean/Meta/ExprDefEq.lean b/src/Lean/Meta/ExprDefEq.lean index 0a860850761e..e1224b5d9e43 100644 --- a/src/Lean/Meta/ExprDefEq.lean +++ b/src/Lean/Meta/ExprDefEq.lean @@ -183,7 +183,7 @@ inductive DefEqArgsFirstPassResult where Succeeded. The array `postponedImplicit` contains the position of the implicit arguments for which def-eq has been postponed. `postponedHO` contains the higher order output parameters, and parameters - that depend on them. They should be processed after the implict ones. + that depend on them. They should be processed after the implicit ones. `postponedHO` is used to handle applications involving functions that contain higher order output parameters. Example: ```lean @@ -192,7 +192,7 @@ inductive DefEqArgsFirstPassResult where {dom : cont → idx → Prop} → [self : GetElem cont idx elem dom] → (xs : cont) → (i : idx) → (h : dom xs i) → elem ``` - The argumengs `dom` and `h` must be processed after all implicit arguments + The arguments `dom` and `h` must be processed after all implicit arguments otherwise higher-order unification problems are generated. See issue #1299, when trying to solve ``` @@ -629,7 +629,7 @@ where let f (x : _) := pure "hello"; f () ``` with expected type `IO String`. - In this example, the following unification contraint is generated. + In this example, the following unification constraint is generated. ``` ?m () String =?= IO String ``` @@ -649,7 +649,7 @@ where a **potential** dependency on `x`. By using constant approximation here, we are just saying the type of `f` does **not** depend on `x`. We claim this is a reasonable approximation in practice. Moreover, it is expected by any functional programmer used to non-dependently type languages (e.g., Haskell). - We distinguish the two cases above by using the field `numScopeArgs` at `MetavarDecl`. This fiels tracks + We distinguish the two cases above by using the field `numScopeArgs` at `MetavarDecl`. This field tracks how many metavariable arguments are representing dependencies. -/ @@ -735,7 +735,7 @@ mutual throwCheckAssignmentFailure -- It is not a pattern, then we fail and fall back to FO unification else if mvarDecl.lctx.isSubPrefixOf ctx.mvarDecl.lctx ctx.fvars then /- The local context of `mvar` - free variables being abstracted is a subprefix of the metavariable being assigned. - We "substract" variables being abstracted because we use `elimMVarDeps` -/ + We "subtract" variables being abstracted because we use `elimMVarDeps` -/ pure mvar else if mvarDecl.depth != (← getMCtx).depth || mvarDecl.kind.isSyntheticOpaque then traceM `Meta.isDefEq.assign.readOnlyMVarWithBiggerLCtx <| addAssignmentInfo (mkMVar mvarId) @@ -1034,7 +1034,7 @@ private def assignConst (mvar : Expr) (numArgs : Nat) (v : Expr) : MetaM Bool := ``` ?m := fun y₁ ... y‌ⱼ => (fun y_{j+1} ... yₙ x₁ ... xᵢ => v)[a₁/y₁, .., aⱼ/yⱼ] ``` - That is, after the longest prefix is found, we solve the contraint as the lhs was a pattern. See the definition of "pattern" above. + That is, after the longest prefix is found, we solve the constraint as the lhs was a pattern. See the definition of "pattern" above. -/ private partial def processConstApprox (mvar : Expr) (args : Array Expr) (patternVarPrefix : Nat) (v : Expr) : MetaM Bool := do trace[Meta.isDefEq.constApprox] "{mvar} {args} := {v}" @@ -1397,7 +1397,7 @@ private def expandDelayedAssigned? (t : Expr) : MetaM (Option Expr) := do if tNew != t then return some tNew /- If `assignSyntheticOpaque` is true, we must follow the delayed assignment. - Recall a delayed assignment `mvarId [xs] := mvarIdPending` is morally an assingment + Recall a delayed assignment `mvarId [xs] := mvarIdPending` is morally an assignment `mvarId := fun xs => mvarIdPending` where `xs` are free variables in the scope of `mvarIdPending`, but not in the scope of `mvarId`. We can only perform the abstraction when `mvarIdPending` has been fully synthesized. That is, `instantiateMVars (mkMVar mvarIdPending)` does not contain any expression metavariables. @@ -1411,7 +1411,7 @@ private def expandDelayedAssigned? (t : Expr) : MetaM (Option Expr) := do We also have the delayed assignment `?m [xs] := ?n`, where `xs` are variables in the scope of `?n`, and this delayed assignment is morally `?m := fun xs => ?n`. Thus, we can reduce `?m as =?= s[as]` to `?n =?= s[as/xs]`, and solve it using `?n`'s local context. - This is more precise than simplying droping the arguments `as`. + This is more precise than simply dropping the arguments `as`. -/ unless (← getConfig).assignSyntheticOpaque do return none let tArgs := t.getAppArgs @@ -1688,7 +1688,7 @@ private def isDefEqProj : Expr → Expr → MetaM Bool | v, Expr.proj structName 0 s => isDefEqSingleton structName s v | _, _ => pure false where - /-- If `structName` is a structure with a single field and `(?m ...).1 =?= v`, then solve contraint as `?m ... =?= ⟨v⟩` -/ + /-- If `structName` is a structure with a single field and `(?m ...).1 =?= v`, then solve constraint as `?m ... =?= ⟨v⟩` -/ isDefEqSingleton (structName : Name) (s : Expr) (v : Expr) : MetaM Bool := do if isClass (← getEnv) structName then /- @@ -1802,7 +1802,7 @@ private def getCachedResult (key : Expr × Expr) : MetaM LBool := do private def cacheResult (key : Expr × Expr) (result : Bool) : MetaM Unit := do /- - We must ensure that all assigned metavariables in the key are replaced by their current assingments. + We must ensure that all assigned metavariables in the key are replaced by their current assignments. Otherwise, the key is invalid after the assignment is "backtracked". See issue #1870 for an example. -/ diff --git a/src/Lean/Meta/IndPredBelow.lean b/src/Lean/Meta/IndPredBelow.lean index 7118a320582c..71e23507e014 100644 --- a/src/Lean/Meta/IndPredBelow.lean +++ b/src/Lean/Meta/IndPredBelow.lean @@ -456,14 +456,14 @@ where /-- this function changes the type of the pattern from the original type to the `below` version thereof. Most of the cases don't apply. In order to change the type and the pattern to be type correct, we don't - simply recursively change all occurrences, but rather, we recursively change occurences of the constructor. + simply recursively change all occurrences, but rather, we recursively change occurrences of the constructor. As such there are only a few cases: - the pattern is a constructor from the original type. Here we need to: - replace the constructor - copy original recursive patterns and convert them to below and reintroduce them in the correct position - turn original recursive patterns inaccessible - introduce free variables as needed. - - it is an `as` pattern. Here the contstructor could be hidden inside of it. + - it is an `as` pattern. Here the constructor could be hidden inside of it. - it is a variable. Here you we need to introduce a fresh variable of a different type. -/ convertToBelow (indName : Name) diff --git a/src/Lean/Meta/Instances.lean b/src/Lean/Meta/Instances.lean index d3b784f965d6..f39ceef9590a 100644 --- a/src/Lean/Meta/Instances.lean +++ b/src/Lean/Meta/Instances.lean @@ -16,7 +16,7 @@ register_builtin_option synthInstance.checkSynthOrder : Bool := { } /- -Note: we want to use iota reduction when indexing instaces. Otherwise, +Note: we want to use iota reduction when indexing instances. Otherwise, we cannot elaborate examples such as ``` inductive Ty where diff --git a/src/Lean/Meta/KExprMap.lean b/src/Lean/Meta/KExprMap.lean index d57b33df7ddd..55c61e9133af 100644 --- a/src/Lean/Meta/KExprMap.lean +++ b/src/Lean/Meta/KExprMap.lean @@ -9,7 +9,7 @@ import Lean.Meta.Basic namespace Lean.Meta /-- - A mapping that indentifies definitionally equal expressions. + A mapping that identifies definitionally equal expressions. We implement it as a mapping from `HeadIndex` to `AssocList Expr α`. Remark: this map may be quite inefficient if there are many `HeadIndex` collisions. diff --git a/src/Lean/Meta/Match/Basic.lean b/src/Lean/Meta/Match/Basic.lean index 16dd830117d7..c674067babd5 100644 --- a/src/Lean/Meta/Match/Basic.lean +++ b/src/Lean/Meta/Match/Basic.lean @@ -136,7 +136,7 @@ structure Alt where /-- `Syntax` object for providing position information -/ ref : Syntax /-- - Orginal alternative index. Alternatives can be split, this index is the original + Original alternative index. Alternatives can be split, this index is the original position of the alternative that generated this one. -/ idx : Nat diff --git a/src/Lean/Meta/Match/CaseValues.lean b/src/Lean/Meta/Match/CaseValues.lean index 2d0d6ecb0245..aac439af6ce4 100644 --- a/src/Lean/Meta/Match/CaseValues.lean +++ b/src/Lean/Meta/Match/CaseValues.lean @@ -75,7 +75,7 @@ structure CaseValuesSubgoal where The type of `x` must have decidable equality. Remark: the last subgoal is for the "else" catchall case, and its `subst` is `{}`. - Remark: the fiels `newHs` has size 1 forall but the last subgoal. + Remark: the field `newHs` has size 1 forall but the last subgoal. If `substNewEqs = true`, then the new `h_i` equality hypotheses are substituted in the first `n` cases. -/ diff --git a/src/Lean/Meta/Match/Match.lean b/src/Lean/Meta/Match/Match.lean index 53af4b8688e1..b4ce22790431 100644 --- a/src/Lean/Meta/Match/Match.lean +++ b/src/Lean/Meta/Match/Match.lean @@ -151,7 +151,7 @@ private def processSkipInaccessible (p : Problem) : Problem := Id.run do { p with alts := alts, vars := xs } /-- -If contraint is of the form `e ≋ x` where `x` is a free variable, reorient it +If constraint is of the form `e ≋ x` where `x` is a free variable, reorient it as `x ≋ e` If - `x` is an `alt`-local declaration - `e` is not a free variable. @@ -254,7 +254,7 @@ private def processAsPattern (p : Problem) : MetaM Problem := withGoalOf p do match alt.patterns with | .as fvarId p h :: ps => /- We used to use `checkAndReplaceFVarId` here, but `x` and `fvarId` may have different types - when dependent types are beind used. Let's consider the repro for issue #471 + when dependent types are being used. Let's consider the repro for issue #471 ``` inductive vec : Nat → Type | nil : vec 0 @@ -413,7 +413,7 @@ private def processConstructor (p : Problem) : MetaM (Array Problem) := do p.mvarId.cases x.fvarId! catch ex => if p.alts.isEmpty then - /- If we have no alternatives and dependent pattern matching fails, then a "missing cases" error is bettern than a "stuck" error message. -/ + /- If we have no alternatives and dependent pattern matching fails, then a "missing cases" error is better than a "stuck" error message. -/ return none else throwCasesException p ex diff --git a/src/Lean/Meta/Match/MatchEqs.lean b/src/Lean/Meta/Match/MatchEqs.lean index 3e2b76b97242..909edfe87c81 100644 --- a/src/Lean/Meta/Match/MatchEqs.lean +++ b/src/Lean/Meta/Match/MatchEqs.lean @@ -146,7 +146,7 @@ structure State where mvarId : MVarId -- Goal representing the hypothesis xs : List FVarId -- Pattern variables for a previous case eqs : List FVarId -- Equations to be processed - eqsNew : List FVarId := [] -- Simplied (already processed) equations + eqsNew : List FVarId := [] -- Simplified (already processed) equations abbrev M := StateRefT State MetaM @@ -371,7 +371,7 @@ private abbrev ConvertM := ReaderT (FVarIdMap (Expr × Nat × Array Bool)) $ Sta Construct a proof for the splitter generated by `mkEquationsfor`. The proof uses the definition of the `match`-declaration as a template (argument `template`). - `alts` are free variables corresponding to alternatives of the `match` auxiliary declaration being processed. - - `altNews` are the new free variables which contains aditional hypotheses that ensure they are only used + - `altNews` are the new free variables which contains additional hypotheses that ensure they are only used when the previous overlapping alternatives are not applicable. -/ private partial def mkSplitterProof (matchDeclName : Name) (template : Expr) (alts altsNew : Array Expr) (altsNewNumParams : Array Nat) diff --git a/src/Lean/Meta/Match/Value.lean b/src/Lean/Meta/Match/Value.lean index 39667cd59b77..ba6e35927ba0 100644 --- a/src/Lean/Meta/Match/Value.lean +++ b/src/Lean/Meta/Match/Value.lean @@ -31,7 +31,7 @@ def isUIntPatLit (v : Expr) : Bool := isUIntPatLit? v |>.isSome /-- - The frontend expands uint numerals occurring in patterns into `UInt*.mk ..` contructor applications. + The frontend expands uint numerals occurring in patterns into `UInt*.mk ..` constructor applications. This method convert them back into `UInt*.ofNat ..` applications. -/ def foldPatValue (v : Expr) : Expr := diff --git a/src/Lean/Meta/Offset.lean b/src/Lean/Meta/Offset.lean index 21ade50c12ec..3d87c7f97129 100644 --- a/src/Lean/Meta/Offset.lean +++ b/src/Lean/Meta/Offset.lean @@ -113,7 +113,7 @@ private def mkOffset (e : Expr) (offset : Nat) : MetaM Expr := do def isDefEqOffset (s t : Expr) : MetaM LBool := do let ifNatExpr (x : MetaM LBool) : MetaM LBool := do let type ← inferType s - -- Remark: we use `withNewMCtxDepth` to make sure we don't assing metavariables when performing the `isDefEq` test + -- Remark: we use `withNewMCtxDepth` to make sure we don't assign metavariables when performing the `isDefEq` test if (← withNewMCtxDepth <| Meta.isExprDefEqAux type (mkConst ``Nat)) then x else diff --git a/src/Lean/Meta/PPGoal.lean b/src/Lean/Meta/PPGoal.lean index d19e4673b0fe..23ac5268bbcb 100644 --- a/src/Lean/Meta/PPGoal.lean +++ b/src/Lean/Meta/PPGoal.lean @@ -52,7 +52,7 @@ def ppGoal (mvarId : MVarId) : MetaM Format := do let lctx := mvarDecl.lctx let lctx := lctx.sanitizeNames.run' { options := (← getOptions) } withLCtx lctx mvarDecl.localInstances do - -- The followint two `let rec`s are being used to control the generated code size. + -- The following two `let rec`s are being used to control the generated code size. -- Then should be remove after we rewrite the compiler in Lean let rec pushPending (ids : List Name) (type? : Option Expr) (fmt : Format) : MetaM Format := do if ids.isEmpty then diff --git a/src/Lean/Meta/SynthInstance.lean b/src/Lean/Meta/SynthInstance.lean index ea502244b864..15f2bcc61acb 100644 --- a/src/Lean/Meta/SynthInstance.lean +++ b/src/Lean/Meta/SynthInstance.lean @@ -601,7 +601,7 @@ it contains a regular parameter X that depends on an `out` parameter Y. Then, we execute type class resolution as usual. If it succeeds, and metavariables ?m_i have been assigned, we try to unify -the original type `C a_1 ... a_n` witht the normalized one. +the original type `C a_1 ... a_n` with the normalized one. -/ private def preprocess (type : Expr) : MetaM Expr := @@ -697,7 +697,7 @@ def synthInstance? (type : Expr) (maxResultSize? : Option Nat := none) : MetaM ( trace[Meta.synthInstance] "result {result}" if (← assignOutParams result) then let result ← instantiateMVars result - /- We use `check` to propogate universe constraints implied by the `result`. + /- We use `check` to propagate universe constraints implied by the `result`. Recall that we use `allowLevelAssignments := true` which allows universe metavariables in the current depth to be assigned, but these assignments are discarded by `withNewMCtxDepth`. diff --git a/src/Lean/Meta/Tactic/Cases.lean b/src/Lean/Meta/Tactic/Cases.lean index 418a77e2eb5c..3fd14009f4d5 100644 --- a/src/Lean/Meta/Tactic/Cases.lean +++ b/src/Lean/Meta/Tactic/Cases.lean @@ -168,7 +168,7 @@ private def hasIndepIndices (ctx : Context) : MetaM Bool := do /- One of the indices is not a free variable. -/ return false else if ctx.majorTypeIndices.size.any fun i => i.any fun j => ctx.majorTypeIndices[i]! == ctx.majorTypeIndices[j]! then - /- An index ocurrs more than once -/ + /- An index occurs more than once -/ return false else (← getLCtx).allM fun decl => diff --git a/src/Lean/Meta/Tactic/Revert.lean b/src/Lean/Meta/Tactic/Revert.lean index 1c4da42e33f2..c38195b6822a 100644 --- a/src/Lean/Meta/Tactic/Revert.lean +++ b/src/Lean/Meta/Tactic/Revert.lean @@ -32,7 +32,7 @@ def _root_.Lean.MVarId.revert (mvarId : MVarId) (fvarIds : Array FVarId) (preser toRevertNew := toRevertNew.push x let tag ← mvarId.getTag -- TODO: the following code can be optimized because `MetavarContext.revert` will compute `collectDeps` again. - -- We should factor out the relevat part + -- We should factor out the relevant part -- Set metavariable kind to natural to make sure `revert` will assign it. mvarId.setKind .natural diff --git a/src/Lean/Meta/Tactic/Simp/Main.lean b/src/Lean/Meta/Tactic/Simp/Main.lean index 5a5d621d8bc6..4fca5307a049 100644 --- a/src/Lean/Meta/Tactic/Simp/Main.lean +++ b/src/Lean/Meta/Tactic/Simp/Main.lean @@ -66,7 +66,7 @@ private def mkImpCongr (src : Expr) (r₁ r₂ : Result) : MetaM Result := do let e := src.updateForallE! r₁.expr r₂.expr match r₁.proof?, r₂.proof? with | none, none => return { expr := e, proof? := none } - | _, _ => return { expr := e, proof? := (← Meta.mkImpCongr (← r₁.getProof) (← r₂.getProof)) } -- TODO specialize if bootleneck + | _, _ => return { expr := e, proof? := (← Meta.mkImpCongr (← r₁.getProof) (← r₂.getProof)) } -- TODO specialize if bottleneck /-- Return true if `e` is of the form `ofNat n` where `n` is a kernel Nat literal -/ def isOfNatNatLit (e : Expr) : Bool := diff --git a/src/Lean/Meta/Tactic/Simp/SimpCongrTheorems.lean b/src/Lean/Meta/Tactic/Simp/SimpCongrTheorems.lean index 17868a869d2d..48404047de48 100644 --- a/src/Lean/Meta/Tactic/Simp/SimpCongrTheorems.lean +++ b/src/Lean/Meta/Tactic/Simp/SimpCongrTheorems.lean @@ -13,7 +13,7 @@ namespace Lean.Meta /-- Data for user-defined theorems marked with the `congr` attribute. - This type should be confused with `CongrTheorem` which reprents different kinds of automatically + This type should be confused with `CongrTheorem` which represents different kinds of automatically generated congruence theorems. The `simp` tactic also uses some of them. -/ structure SimpCongrTheorem where diff --git a/src/Lean/Meta/Tactic/Simp/SimpTheorems.lean b/src/Lean/Meta/Tactic/Simp/SimpTheorems.lean index 87cea99d203c..7921193c44e1 100644 --- a/src/Lean/Meta/Tactic/Simp/SimpTheorems.lean +++ b/src/Lean/Meta/Tactic/Simp/SimpTheorems.lean @@ -51,7 +51,7 @@ instance : BEq Origin := ⟨(·.key == ·.key)⟩ instance : Hashable Origin := ⟨(hash ·.key)⟩ /- -Note: we want to use iota reduction when indexing instaces. Otherwise, +Note: we want to use iota reduction when indexing instances. Otherwise, we cannot use simp theorems such as ``` @[simp] theorem liftOn_mk (a : α) (f : α → γ) (h : ∀ a₁ a₂, r a₁ a₂ → f a₁ = f a₂) : diff --git a/src/Lean/Meta/Tactic/Split.lean b/src/Lean/Meta/Tactic/Split.lean index 847029153fec..a76a15c772f7 100644 --- a/src/Lean/Meta/Tactic/Split.lean +++ b/src/Lean/Meta/Tactic/Split.lean @@ -164,7 +164,7 @@ where - `altEqs` are free variables of the form `h_altEq : discr = pattern`. `altEqs.size = numDiscrEqs ≤ discrs.size` This method executes `k altEqsNew subst` where - `altEqsNew` are fresh free variables of the form `h_altEqNew : discrVar = pattern` - - `subst` are terms of the form `h_eq.trans h_altEqNew : discr = pattern`. We use `subst` later to replace occurences of `h_altEq` with `h_eq.trans h_altEqNew`. + - `subst` are terms of the form `h_eq.trans h_altEqNew : discr = pattern`. We use `subst` later to replace occurrences of `h_altEq` with `h_eq.trans h_altEqNew`. -/ withNewAltEqs (matcherInfo : MatcherInfo) (eqs : Array Expr) (altEqs : Array Expr) (k : Array Expr → Array Expr → MetaM Expr) : MetaM Expr := do let eqs' := (eqs.zip matcherInfo.discrInfos).filterMap fun (eq, info) => if info.hName?.isNone then none else some eq diff --git a/src/Lean/Meta/Tactic/UnifyEq.lean b/src/Lean/Meta/Tactic/UnifyEq.lean index 7bcf83f690a4..ee63627e67b7 100644 --- a/src/Lean/Meta/Tactic/UnifyEq.lean +++ b/src/Lean/Meta/Tactic/UnifyEq.lean @@ -7,9 +7,9 @@ import Lean.Meta.Tactic.Injection namespace Lean.Meta -/-- Convert heterogeneous equality into a homegeneous one -/ +/-- Convert heterogeneous equality into a homogeneous one -/ private def heqToEq' (mvarId : MVarId) (eqDecl : LocalDecl) : MetaM MVarId := do - /- Convert heterogeneous equality into a homegeneous one -/ + /- Convert heterogeneous equality into a homogeneous one -/ let prf ← mkEqOfHEq (mkFVar eqDecl.fvarId) let aEqb ← whnf (← inferType prf) let mvarId ← mvarId.assert eqDecl.userName aEqb prf @@ -30,7 +30,7 @@ structure UnifyEqResult where - Normalize `a` and `b` using the current reducibility setting. - If `a` (`b`) is a free variable not occurring in `b` (`a`), replace it everywhere. - If `a` and `b` are distinct constructors, return `none` to indicate that the goal has been closed. - - If `a` and `b` are the same contructor, apply `injection`, the result contains the number of new equalities introduced in the goal. + - If `a` and `b` are the same constructor, apply `injection`, the result contains the number of new equalities introduced in the goal. - It also tries to apply the given `acyclic` method to try to close the goal. Remark: It is a parameter because `simp` uses `unifyEq?`, and `acyclic` depends on `simp`. -/ diff --git a/src/Lean/Meta/WHNF.lean b/src/Lean/Meta/WHNF.lean index d4cfa085d938..4759521b743f 100644 --- a/src/Lean/Meta/WHNF.lean +++ b/src/Lean/Meta/WHNF.lean @@ -416,7 +416,7 @@ private def whnfMatcher (e : Expr) : MetaM Expr := do /- When reducing `match` expressions, if the reducibility setting is at `TransparencyMode.reducible`, we increase it to `TransparencyMode.instances`. We use the `TransparencyMode.reducible` in many places (e.g., `simp`), and this setting prevents us from reducing `match` expressions where the discriminants are terms such as `OfNat.ofNat α n inst`. - For example, `simp [Int.div]` will not unfold the application `Int.div 2 1` occuring in the target. + For example, `simp [Int.div]` will not unfold the application `Int.div 2 1` occurring in the target. TODO: consider other solutions; investigate whether the solution above produces counterintuitive behavior. -/ let mut transparency ← getTransparency diff --git a/src/Lean/MetavarContext.lean b/src/Lean/MetavarContext.lean index 9b1733936af9..db4374cf3e07 100644 --- a/src/Lean/MetavarContext.lean +++ b/src/Lean/MetavarContext.lean @@ -564,7 +564,7 @@ partial def instantiateExprMVars [Monad m] [MonadMCtx m] [STWorld ω m] [MonadLi Example: suppose we have `?m t1 t2 t3` That is, `f := ?m` and `args := #[t1, t2, t3]` - Morever, `?m` is delayed assigned + Moreover, `?m` is delayed assigned `?m #[x, y] := f x y` where, `fvars := #[x, y]` and `newVal := f x y`. After abstracting `newVal`, we have `f (Expr.bvar 0) (Expr.bvar 1)`. diff --git a/src/Lean/Parser/Basic.lean b/src/Lean/Parser/Basic.lean index 02c950885c74..d34063e0557f 100644 --- a/src/Lean/Parser/Basic.lean +++ b/src/Lean/Parser/Basic.lean @@ -1183,7 +1183,7 @@ def runLongestMatchParser (left? : Option Syntax) (startLhsPrec : Nat) (p : Pars -- error with an unexpected number of nodes. s.shrinkStack startSize |>.pushSyntax Syntax.missing else - -- parser succeded with incorrect number of nodes + -- parser succeeded with incorrect number of nodes invalidLongestMatchParser s def longestMatchStep (left? : Option Syntax) (startSize startLhsPrec : Nat) (startPos : String.Pos) (prevPrio : Nat) (prio : Nat) (p : ParserFn) @@ -1715,8 +1715,8 @@ partial def trailingLoop (tables : PrattParsingTables) (c : ParserContext) (s : After processing the leading parser, we chain with parsers from `trailingTable`/`trailingParsers` that have precedence at least `c.prec` where `c` is the `ParsingContext`. Recall that `c.prec` is set by `categoryParser`. - Note that in the original Pratt's algorith, precedences are only checked before calling trailing parsers. In our - implementation, leading *and* trailing parsers check the precendece. We claim our algorithm is more flexible, + Note that in the original Pratt's algorithm, precedences are only checked before calling trailing parsers. In our + implementation, leading *and* trailing parsers check the precedence. We claim our algorithm is more flexible, modular and easier to understand. `antiquotParser` should be a `mkAntiquot` parser (or always fail) and is tried before all other parsers. diff --git a/src/Lean/ResolveName.lean b/src/Lean/ResolveName.lean index 00fb6c747a86..b5ae3360ab76 100644 --- a/src/Lean/ResolveName.lean +++ b/src/Lean/ResolveName.lean @@ -55,7 +55,7 @@ def getRevAliases (env : Environment) (e : Name) : List Name := /-! # Global name resolution -/ namespace ResolveName -/-- Check whether `ns ++ id` is a valid namepace name and/or there are aliases names `ns ++ id`. -/ +/-- Check whether `ns ++ id` is a valid namespace name and/or there are aliases names `ns ++ id`. -/ private def resolveQualifiedName (env : Environment) (ns : Name) (id : Name) : List Name := let resolvedId := ns ++ id -- We ignore protected aliases if `id` is atomic. @@ -160,7 +160,7 @@ Given a name `id` try to find namespaces it may refer to. The resolution procedu then we include `s_1 . ... . s_i ++ n` in the result if it is the name of an existing namespace. We search "backwards", and include at most one of the in the list of resulting namespaces. -2- If `id` is the extact name of an existing namespace, then include `id` +2- If `id` is the exact name of an existing namespace, then include `id` 3- Finally, for each command `open N`, include in the result `N ++ n` if it is the name of an existing namespace. We only consider simple `open` commands. -/ @@ -253,7 +253,7 @@ def resolveGlobalConstNoOverloadCore [Monad m] [MonadResolveName m] [MonadEnv m] | _ => throwError s!"ambiguous identifier '{mkConst n}', possible interpretations: {cs.map mkConst}" /-- Interpret the syntax `n` as an identifier for a global constant, and return a list of resolved -constant names that it could be refering to based on the currently open namespaces. +constant names that it could be referring to based on the currently open namespaces. This should be used instead of `resolveGlobalConstCore` for identifiers taken from syntax because `Syntax` objects may have names that have already been resolved. diff --git a/src/Lean/Server/AsyncList.lean b/src/Lean/Server/AsyncList.lean index ef64d7322d2b..5da2648899e2 100644 --- a/src/Lean/Server/AsyncList.lean +++ b/src/Lean/Server/AsyncList.lean @@ -83,7 +83,7 @@ partial def waitUntil (p : α → Bool) : AsyncList ε α → Task (List α × O def waitAll : AsyncList ε α → Task (List α × Option ε) := waitUntil (fun _ => false) -/-- Spawns a `Task` acting like `List.find?` but which will wait for tail evalution +/-- Spawns a `Task` acting like `List.find?` but which will wait for tail evaluation when necessary to traverse the list. If the tail terminates before a matching element is found, the task throws the terminating value. -/ partial def waitFind? (p : α → Bool) : AsyncList ε α → Task (Except ε (Option α)) diff --git a/src/Lean/Server/FileWorker.lean b/src/Lean/Server/FileWorker.lean index 4c3ef01d8312..99815d87da7d 100644 --- a/src/Lean/Server/FileWorker.lean +++ b/src/Lean/Server/FileWorker.lean @@ -38,13 +38,13 @@ File processing and requests+notifications against a file should be concurrent f To achieve these goals, elaboration is executed in a chain of tasks, where each task corresponds to the elaboration of one command. When the elaboration of one command is done, the next task is spawned. -On didChange notifications, we search for the task in which the change occured. If we stumble across +On didChange notifications, we search for the task in which the change occurred. If we stumble across a task that has not yet finished before finding the task we're looking for, we terminate it -and start the elaboration there, otherwise we start the elaboration at the task where the change occured. +and start the elaboration there, otherwise we start the elaboration at the task where the change occurred. Requests iterate over tasks until they find the command that they need to answer the request. In order to not block the main thread, this is done in a request task. -If a task that the request task waits for is terminated, a change occured somewhere before the +If a task that the request task waits for is terminated, a change occurred somewhere before the command that the request is looking for and the request sends a "content changed" error. -/ @@ -104,7 +104,7 @@ section Elab -- TODO(MH): check for interrupt with increased precision cancelTk.check /- NOTE(MH): This relies on the client discarding old diagnostics upon receiving new ones - while prefering newer versions over old ones. The former is necessary because we do + while preferring newer versions over old ones. The former is necessary because we do not explicitly clear older diagnostics, while the latter is necessary because we do not guarantee that diagnostics are emitted in order. Specifically, it may happen that we interrupted this elaboration task right at this point and a newer elaboration task @@ -112,7 +112,7 @@ section Elab the interrupt. Explicitly clearing diagnostics is difficult for a similar reason, because we cannot guarantee that no further diagnostics are emitted after clearing them. -/ - -- NOTE(WN): this is *not* redundent even if there are no new diagnostics in this snapshot + -- NOTE(WN): this is *not* redundant even if there are no new diagnostics in this snapshot -- because empty diagnostics clear existing error/information squiggles. Therefore we always -- want to publish in case there was previously a message at this position. publishDiagnostics m snap.diagnostics.toArray ctx.hOut diff --git a/src/Lean/Server/InfoUtils.lean b/src/Lean/Server/InfoUtils.lean index a9f52e24729b..bd0196f2bdbd 100644 --- a/src/Lean/Server/InfoUtils.lean +++ b/src/Lean/Server/InfoUtils.lean @@ -24,7 +24,7 @@ functionality is purpose-specific to showing the contents of infoview popups. For use in standard LSP go-to-definition (see `Lean.Server.FileWorker.locationLinksOfInfo`), all the elaborator information we need for similar tasks is already fully recoverable via the `InfoTree` structure (see `Lean.Elab.InfoTree.visitM`). -There we use this as a convienience wrapper for queried nodes (e.g. the return value of +There we use this as a convenience wrapper for queried nodes (e.g. the return value of `Lean.Elab.InfoTree.hoverableInfoAt?`). It also includes the children info nodes as additional context (this is unused in the RPC case, as delaboration has no notion of child nodes). diff --git a/src/Lean/Server/Watchdog.lean b/src/Lean/Server/Watchdog.lean index b67bb04ddbd4..4c4707d0338c 100644 --- a/src/Lean/Server/Watchdog.lean +++ b/src/Lean/Server/Watchdog.lean @@ -105,7 +105,7 @@ section FileWorker -- This should not be mutated outside of namespace FileWorker, as it is used as shared mutable state /-- The pending requests map contains all requests that have been received from the LSP client, but were not answered yet. - We need them for forwaring cancellation requests to the correct worker as well as cleanly aborting + We need them for forwarding cancellation requests to the correct worker as well as cleanly aborting requests on worker crashes. -/ pendingRequestsRef : IO.Ref PendingRequestMap diff --git a/src/Lean/Util/OccursCheck.lean b/src/Lean/Util/OccursCheck.lean index d6b33264843e..90f982d0439d 100644 --- a/src/Lean/Util/OccursCheck.lean +++ b/src/Lean/Util/OccursCheck.lean @@ -9,7 +9,7 @@ namespace Lean /-- Return true if `e` does **not** contain `mvarId` directly or indirectly - This function considers assigments and delayed assignments. -/ + This function considers assignments and delayed assignments. -/ partial def occursCheck [Monad m] [MonadMCtx m] (mvarId : MVarId) (e : Expr) : m Bool := do if !e.hasExprMVar then return true diff --git a/tests/lean/docStr.lean.expected.out b/tests/lean/docStr.lean.expected.out index 2a3987f5fc01..c6094eae6f50 100644 --- a/tests/lean/docStr.lean.expected.out +++ b/tests/lean/docStr.lean.expected.out @@ -17,7 +17,7 @@ doc string for 'g' is not available "let rec documentation at g " "Gadget for optional parameter support.\n\nA binder like `(x : α := default)` in a declaration is syntax sugar for\n`x : optParam α default`, and triggers the elaborator to attempt to use\n`default` to supply the argument if it is not supplied.\n" "Auxiliary declaration used to implement named patterns like `x@h:p`. " -"Similar to `forallTelescope`, but given `type` of the form `forall xs, A`,\nit reduces `A` and continues bulding the telescope if it is a `forall`. " +"Similar to `forallTelescope`, but given `type` of the form `forall xs, A`,\nit reduces `A` and continues building the telescope if it is a `forall`. " Foo := { range := { pos := { line := 4, column := 0 }, charUtf16 := 0, From ce4ae37c1973d7afe3874f8e990e5790a1816c35 Mon Sep 17 00:00:00 2001 From: int-y1 Date: Sun, 8 Oct 2023 13:11:41 -0700 Subject: [PATCH 27/71] chore: fix more typos in comments --- RELEASES.md | 8 ++++---- doc/examples/bintree.lean | 12 ++++++------ doc/examples/deBruijn.lean | 2 +- doc/examples/interp.lean | 4 ++-- doc/examples/phoas.lean | 2 +- doc/examples/tc.lean | 2 +- doc/latex/lstlean.tex | 4 ++-- doc/monads/readers.lean | 2 +- script/gen_constants_cpp.py | 2 +- script/gen_tokens_cpp.py | 2 +- src/CMakeLists.txt | 4 ++-- src/Init/Data/Fin/Basic.lean | 2 +- src/Init/Data/Format/Basic.lean | 2 +- src/Init/Data/String/Basic.lean | 2 +- src/Init/Meta.lean | 2 +- src/Init/Notation.lean | 8 ++++---- src/Init/System/Uri.lean | 4 ++-- src/Init/Tactics.lean | 10 +++++----- src/include/lean/lean.h | 2 +- src/initialize/init.cpp | 2 +- src/kernel/inductive.cpp | 2 +- src/kernel/level.h | 4 ++-- src/kernel/type_checker.cpp | 2 +- src/lake/Lake/Util/Async.lean | 2 +- src/lake/tests/buildArgs/test.sh | 4 ++-- src/lake/tests/rebuild/test.sh | 2 +- src/library/annotation.h | 2 +- src/library/compiler/cse.cpp | 2 +- src/library/compiler/csimp.cpp | 4 ++-- src/library/compiler/specialize.cpp | 4 ++-- src/library/print.h | 2 +- src/runtime/alloc.cpp | 2 +- src/runtime/interrupt.h | 4 ++-- src/runtime/io.cpp | 2 +- src/runtime/object.cpp | 2 +- src/runtime/utf8.h | 2 +- src/util/name.cpp | 2 +- src/version.h.in | 2 +- tests/bench/cross.yaml | 6 +++--- tests/bench/speedcenter.yaml | 4 ++-- .../elabissues/invalid_field_notation_error_msg.lean | 2 +- tests/elabissues/leaky_tmp_metavars.lean | 2 +- .../elabissues/typeclasses_with_umetavariables.lean | 2 +- tests/elabissues/vars.lean | 2 +- tests/lean/rewrite.lean | 2 +- tests/lean/run/909.lean | 2 +- tests/lean/run/meta.lean | 2 +- tests/lean/run/newfrontend5.lean | 2 +- 48 files changed, 75 insertions(+), 75 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 688b6876ed25..a4287e9d6d26 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -54,7 +54,7 @@ v4.0.0 * [`dsimp` / `simp` / `simp_all` now fail by default if they make no progress](https://github.com/leanprover/lean4/pull/2336). - This can be overriden with the `(config := { failIfUnchanged := false })` option. + This can be overridden with the `(config := { failIfUnchanged := false })` option. This change was made to ease manual use of `simp` (with complicated goals it can be hard to tell if it was effective) and to allow easier flow control in tactics internally using `simp`. See the [summary discussion](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/simp.20fails.20if.20no.20progress/near/380153295) @@ -153,7 +153,7 @@ v4.0.0 * New [code generator](https://github.com/leanprover/lean4/tree/master/src/Lean/Compiler/LCNF) project has started. -* Remove description argument frome `register_simp_attr`. [PR #1566](https://github.com/leanprover/lean4/pull/1566). +* Remove description argument from `register_simp_attr`. [PR #1566](https://github.com/leanprover/lean4/pull/1566). * [Additional concurrency primitives](https://github.com/leanprover/lean4/pull/1555). @@ -673,7 +673,7 @@ v4.0.0-m5 (07 August 2022) `Foo : {Foo : Type u} → List Foo → Type`. -* Fix syntax hightlighting for recursive declarations. Example +* Fix syntax highlighting for recursive declarations. Example ```lean inductive List (α : Type u) where | nil : List α -- `List` is not highlighted as a variable anymore @@ -982,7 +982,7 @@ For example, given `f : Nat → Nat` and `g : Nat → Nat`, `f.comp g` is now no * Various improvements to go-to-definition & find-all-references accuracy. -* Auto generated congruence lemmas with support for casts on proofs and `Decidable` instances (see [whishlist](https://github.com/leanprover/lean4/issues/988)). +* Auto generated congruence lemmas with support for casts on proofs and `Decidable` instances (see [wishlist](https://github.com/leanprover/lean4/issues/988)). * Rename option `autoBoundImplicitLocal` => `autoImplicit`. diff --git a/doc/examples/bintree.lean b/doc/examples/bintree.lean index bb4fb73d1d95..6f775d8b5d2c 100644 --- a/doc/examples/bintree.lean +++ b/doc/examples/bintree.lean @@ -5,7 +5,7 @@ If the type of keys can be totally ordered -- that is, it supports a well-behave then maps can be implemented with binary search trees (BSTs). Insert and lookup operations on BSTs take time proportional to the height of the tree. If the tree is balanced, the operations therefore take logarithmic time. -This example is based on a similar example found in the ["Sofware Foundations"](https://softwarefoundations.cis.upenn.edu/vfa-current/SearchTree.html) +This example is based on a similar example found in the ["Software Foundations"](https://softwarefoundations.cis.upenn.edu/vfa-current/SearchTree.html) book (volume 3). -/ @@ -81,9 +81,9 @@ def Tree.toList (t : Tree β) : List (Nat × β) := |>.toList /-! -The implemention of `Tree.toList` is inefficient because of how it uses the `++` operator. +The implementation of `Tree.toList` is inefficient because of how it uses the `++` operator. On a balanced tree its running time is linearithmic, because it does a linear number of -concatentations at each level of the tree. On an unbalanced tree it's quadratic time. +concatenations at each level of the tree. On an unbalanced tree it's quadratic time. Here's a tail-recursive implementation than runs in linear time, regardless of whether the tree is balanced: -/ def Tree.toListTR (t : Tree β) : List (Nat × β) := @@ -114,9 +114,9 @@ concatenating all goals produced by `tac'`. In this theorem, we use it to apply The `simp` parameters `toListTR.go` and `toList` instruct the simplifier to try to reduce and/or apply auto generated equation theorems for these two functions. -The parameter `*` intructs the simplifier to use any equation in a goal as rewriting rules. +The parameter `*` instructs the simplifier to use any equation in a goal as rewriting rules. In this particular case, `simp` uses the induction hypotheses as rewriting rules. -Finally, the parameter `List.append_assoc` intructs the simplifier to use the +Finally, the parameter `List.append_assoc` instructs the simplifier to use the `List.append_assoc` theorem as a rewriting rule. -/ theorem Tree.toList_eq_toListTR (t : Tree β) @@ -186,7 +186,7 @@ local macro "have_eq " lhs:term:max rhs:term:max : tactic => The `by_cases' e` is just the regular `by_cases` followed by `simp` using all hypotheses in the current goal as rewriting rules. Recall that the `by_cases` tactic creates two goals. One where we have `h : e` and -another one containing `h : ¬ e`. The simplier uses the `h` to rewrite `e` to `True` +another one containing `h : ¬ e`. The simplifier uses the `h` to rewrite `e` to `True` in the first subgoal, and `e` to `False` in the second. This is particularly useful if `e` is the condition of an `if`-statement. -/ diff --git a/doc/examples/deBruijn.lean b/doc/examples/deBruijn.lean index fa83799db247..4d6822073ce4 100644 --- a/doc/examples/deBruijn.lean +++ b/doc/examples/deBruijn.lean @@ -152,7 +152,7 @@ We prove all cases but the one for `plus` using `simp [*]`. This tactic instruct use hypotheses such as `a = b` as rewriting/simplications rules. We use the `split` to break the nested `match` expression in the `plus` case into two cases. The local variables `iha` and `ihb` are the induction hypotheses for `a` and `b`. -The modifier `←` in a term simplifier argument instructs the term simplier to use the equation as a rewriting rule in +The modifier `←` in a term simplifier argument instructs the term simplifier to use the equation as a rewriting rule in the "reverse direction". That is, given `h : a = b`, `← h` instructs the term simplifier to rewrite `b` subterms to `a`. -/ theorem Term.constFold_sound (e : Term ctx ty) : e.constFold.denote env = e.denote env := by diff --git a/doc/examples/interp.lean b/doc/examples/interp.lean index c87c27ef9281..b1202e9c3fc8 100644 --- a/doc/examples/interp.lean +++ b/doc/examples/interp.lean @@ -83,7 +83,7 @@ In practice, this means we use `stop` to refer to the most recently defined vari A value `Expr.val` carries a concrete representation of an integer. -A lambda `Expr.lam` creates a function. In the scope of a function ot type `Ty.fn a ty`, there is a +A lambda `Expr.lam` creates a function. In the scope of a function of type `Ty.fn a ty`, there is a new local variable of type `a`. A function application `Expr.app` produces a value of type `ty` given a function from `a` to `ty` and a value of type `a`. @@ -139,7 +139,7 @@ def add : Expr ctx (Ty.fn Ty.int (Ty.fn Ty.int Ty.int)) := More interestingly, a factorial function fact (e.g. `fun x => if (x == 0) then 1 else (fact (x-1) * x)`), can be written as. Note that this is a recursive (non-terminating) definition. For every input value, the interpreter terminates, but the definition itself is non-terminating. We use two tricks to make sure Lean accepts it. First, we use the auxiliary constructor -`Expr.delay` to delay its unfolding. Second, we add the annotation `decreasing_by sorry` which can be viwed as +`Expr.delay` to delay its unfolding. Second, we add the annotation `decreasing_by sorry` which can be viewed as "trust me, this recursive definition makes sense". Recall that `sorry` is an unsound axiom in Lean. -/ diff --git a/doc/examples/phoas.lean b/doc/examples/phoas.lean index c4bb8ac76ceb..49aa3a7d54e4 100644 --- a/doc/examples/phoas.lean +++ b/doc/examples/phoas.lean @@ -228,7 +228,7 @@ We prove all cases but the one for `plus` using `simp [*]`. This tactic instruct use hypotheses such as `a = b` as rewriting/simplications rules. We use the `split` to break the nested `match` expression in the `plus` case into two cases. The local variables `iha` and `ihb` are the induction hypotheses for `a` and `b`. -The modifier `←` in a term simplifier argument instructs the term simplier to use the equation as a rewriting rule in +The modifier `←` in a term simplifier argument instructs the term simplifier to use the equation as a rewriting rule in the "reverse direction. That is, given `h : a = b`, `← h` instructs the term simplifier to rewrite `b` subterms to `a`. -/ theorem constFold_sound (e : Term' Ty.denote ty) : denote (constFold e) = denote e := by diff --git a/doc/examples/tc.lean b/doc/examples/tc.lean index ef0c30913baf..56bc18cf4ff1 100644 --- a/doc/examples/tc.lean +++ b/doc/examples/tc.lean @@ -38,7 +38,7 @@ theorem HasType.det (h₁ : HasType e t₁) (h₂ : HasType e t₂) : t₁ = t cases h₁ <;> cases h₂ <;> rfl /-! -The inductive type `Maybe p` has two contructors: `found a h` and `unknown`. +The inductive type `Maybe p` has two constructors: `found a h` and `unknown`. The former contains an element `a : α` and a proof that `a` satisfies the predicate `p`. The constructor `unknown` is used to encode "failure". -/ diff --git a/doc/latex/lstlean.tex b/doc/latex/lstlean.tex index 36c8f7599f65..c6c02e572051 100644 --- a/doc/latex/lstlean.tex +++ b/doc/latex/lstlean.tex @@ -4,7 +4,7 @@ \lstdefinelanguage{lean} { -% Anything betweeen $ becomes LaTeX math mode +% Anything between $ becomes LaTeX math mode mathescape=false, % Comments may or not include Latex commands texcl=false, @@ -265,7 +265,7 @@ % Style for (listings') identifiers identifierstyle={\ttfamily\color{black}}, % Note : highlighting of Coq identifiers is done through a new -% delimiter definition through an lstset at the begining of the +% delimiter definition through an lstset at the beginning of the % document. Don't know how to do better. % Style for declaration keywords diff --git a/doc/monads/readers.lean b/doc/monads/readers.lean index 256beb2ec0d7..b3b4d6f923d6 100644 --- a/doc/monads/readers.lean +++ b/doc/monads/readers.lean @@ -113,7 +113,7 @@ the monadic container type. to write `(readerFunc3 args).run env` and this is a bit ugly, so Lean provides an infix operator `|>` that eliminates those parentheses so you can write `readerFunc3 args |>.run env` and then you can chain multiple monadic actions like this `m1 args1 |>.run args2 |>.run args3` and this is the -recommended style. You will see this patten used heavily in Lean code. +recommended style. You will see this pattern used heavily in Lean code. The `let env ← read` expression in `readerFunc1` unwraps the environment from the `ReaderM` so we can use it. Each type of monad might provide one or more extra functions like this, functions that diff --git a/script/gen_constants_cpp.py b/script/gen_constants_cpp.py index b7ddfffdecff..a6b2c6203d87 100755 --- a/script/gen_constants_cpp.py +++ b/script/gen_constants_cpp.py @@ -7,7 +7,7 @@ # Author: Leonardo de Moura # # Given a text file containing constants defined in the Lean libraries, -# this script generates .h and .cpp files for initialing/finalizing theses constants +# this script generates .h and .cpp files for initialing/finalizing these constants # as C++ name objects. # # This script is used to generate src/library/constants.cpp and src/library/constants.h diff --git a/script/gen_tokens_cpp.py b/script/gen_tokens_cpp.py index 73dfd41d2d6e..16e411772114 100755 --- a/script/gen_tokens_cpp.py +++ b/script/gen_tokens_cpp.py @@ -7,7 +7,7 @@ # Author: Leonardo de Moura # # Given a text file containing id and token strings, -# this script generates .h and .cpp files for initialing/finalizing theses tokens +# this script generates .h and .cpp files for initialing/finalizing these tokens # as C++ name objects. # # This script is used to generate src/frontends/lean/tokens.cpp and src/frontends/lean/tokens.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b40444ee2227..b84826c7378c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -318,7 +318,7 @@ if(LLVM AND ${STAGE} GREATER 0) # - Recall that the host's copy of LLVM binaries and libraries is at # `llvm-host`, and the target's copy of LLVM binaries and libraries is at # `llvm`. - # - In an ideal world, we would run the target's `llvm/bin/llvm-config` and get the corrct link options for the target + # - In an ideal world, we would run the target's `llvm/bin/llvm-config` and get the correct link options for the target # (e.g. `-Lllvm/lib/libLLVM`.) # - However, the target's `llvm/bin/llvm-config` has a different target # triple from the host, and thus cannot be run on the host. @@ -513,7 +513,7 @@ else() endif() endif() -# Build the compiler using the bootstraped C sources for stage0, and use +# Build the compiler using the bootstrapped C sources for stage0, and use # the LLVM build for stage1 and further. if (LLVM AND ${STAGE} GREATER 0) set(EXTRA_LEANMAKE_OPTS "LLVM=1") diff --git a/src/Init/Data/Fin/Basic.lean b/src/Init/Data/Fin/Basic.lean index 5f75b8062f3d..18b1a24f9074 100644 --- a/src/Init/Data/Fin/Basic.lean +++ b/src/Init/Data/Fin/Basic.lean @@ -47,7 +47,7 @@ protected def sub : Fin n → Fin n → Fin n /-! Remark: mod/div/modn/land/lor can be defined without using (% n), but we are trying to minimize the number of Nat theorems -needed to boostrap Lean. +needed to bootstrap Lean. -/ protected def mod : Fin n → Fin n → Fin n diff --git a/src/Init/Data/Format/Basic.lean b/src/Init/Data/Format/Basic.lean index 94d32beb80b0..b86537bd3e48 100644 --- a/src/Init/Data/Format/Basic.lean +++ b/src/Init/Data/Format/Basic.lean @@ -315,7 +315,7 @@ class ToFormat (α : Type u) where export ToFormat (format) --- note: must take precendence over the above instance to avoid premature formatting +-- note: must take precedence over the above instance to avoid premature formatting instance : ToFormat Format where format f := f diff --git a/src/Init/Data/String/Basic.lean b/src/Init/Data/String/Basic.lean index 12363c31117f..0446969012c4 100644 --- a/src/Init/Data/String/Basic.lean +++ b/src/Init/Data/String/Basic.lean @@ -566,7 +566,7 @@ def prevn : Substring → Nat → String.Pos → String.Pos @[inline] def front (s : Substring) : Char := s.get 0 -/-- Return the offset into `s` of the first occurence of `c` in `s`, +/-- Return the offset into `s` of the first occurrence of `c` in `s`, or `s.bsize` if `c` doesn't occur. -/ @[inline] def posOf (s : Substring) (c : Char) : String.Pos := match s with diff --git a/src/Init/Meta.lean b/src/Init/Meta.lean index bf42bdddfd07..86f9335dea81 100644 --- a/src/Init/Meta.lean +++ b/src/Init/Meta.lean @@ -480,7 +480,7 @@ structure Module where 1- A proper extensible tactic feature that does not rely on the macro system. 2- Typed macros that know the syntax categories they're working in. Then, we would be able to select which - syntatic categories are expanded by `expandMacros`. + syntactic categories are expanded by `expandMacros`. -/ partial def expandMacros (stx : Syntax) (p : SyntaxNodeKind → Bool := fun k => k != `Lean.Parser.Term.byTactic) : MacroM Syntax := withRef stx do diff --git a/src/Init/Notation.lean b/src/Init/Notation.lean index 267044413356..fa1d400ff240 100644 --- a/src/Init/Notation.lean +++ b/src/Init/Notation.lean @@ -86,14 +86,14 @@ namespace Parser.Syntax /-! DSL for specifying parser precedences and priorities -/ -/-- Addition of precedences. This is normally used only for offseting, e.g. `max + 1`. -/ +/-- Addition of precedences. This is normally used only for offsetting, e.g. `max + 1`. -/ syntax:65 (name := addPrec) prec " + " prec:66 : prec -/-- Subtraction of precedences. This is normally used only for offseting, e.g. `max - 1`. -/ +/-- Subtraction of precedences. This is normally used only for offsetting, e.g. `max - 1`. -/ syntax:65 (name := subPrec) prec " - " prec:66 : prec -/-- Addition of priorities. This is normally used only for offseting, e.g. `default + 1`. -/ +/-- Addition of priorities. This is normally used only for offsetting, e.g. `default + 1`. -/ syntax:65 (name := addPrio) prio " + " prio:66 : prio -/-- Subtraction of priorities. This is normally used only for offseting, e.g. `default - 1`. -/ +/-- Subtraction of priorities. This is normally used only for offsetting, e.g. `default - 1`. -/ syntax:65 (name := subPrio) prio " - " prio:66 : prio end Parser.Syntax diff --git a/src/Init/System/Uri.lean b/src/Init/System/Uri.lean index 696342eaf0bf..a3bfbdf905b5 100644 --- a/src/Init/System/Uri.lean +++ b/src/Init/System/Uri.lean @@ -20,7 +20,7 @@ namespace UriEscape @[inline] def letterF : UInt8 := 'F'.toNat.toUInt8 /-- Decode %HH escapings in the given string. Note that sometimes a consecutive -sequence of multiple escapings can represet a utf-8 encoded sequence for +sequence of multiple escapings can represent a utf-8 encoded sequence for a single unicode code point and these will also be decoded correctly. -/ def decodeUri (uri : String) : String := Id.run do let mut decoded : ByteArray := ByteArray.empty @@ -78,7 +78,7 @@ def escapeUri (uri: String) : String := /-- Replaces all %HH Uri escapings in the given string with their corresponding unicode code points. Note that sometimes a consecutive -sequence of multiple escapings can represet a utf-8 encoded sequence for +sequence of multiple escapings can represent a utf-8 encoded sequence for a single unicode code point and these will also be decoded correctly. -/ def unescapeUri (s: String) : String := UriEscape.decodeUri s diff --git a/src/Init/Tactics.lean b/src/Init/Tactics.lean index 246756a972a3..cc4272d20373 100644 --- a/src/Init/Tactics.lean +++ b/src/Init/Tactics.lean @@ -202,19 +202,19 @@ can be either separated by newlines or `;`. syntax (name := paren) "(" withoutPosition(tacticSeq) ")" : tactic /-- -`with_reducible tacs` excutes `tacs` using the reducible transparency setting. +`with_reducible tacs` executes `tacs` using the reducible transparency setting. In this setting only definitions tagged as `[reducible]` are unfolded. -/ syntax (name := withReducible) "with_reducible " tacticSeq : tactic /-- -`with_reducible_and_instances tacs` excutes `tacs` using the `.instances` transparency setting. +`with_reducible_and_instances tacs` executes `tacs` using the `.instances` transparency setting. In this setting only definitions tagged as `[reducible]` or type class instances are unfolded. -/ syntax (name := withReducibleAndInstances) "with_reducible_and_instances " tacticSeq : tactic /-- -`with_unfolding_all tacs` excutes `tacs` using the `.all` transparency setting. +`with_unfolding_all tacs` executes `tacs` using the `.all` transparency setting. In this setting all definitions that are not opaque are unfolded. -/ syntax (name := withUnfoldingAll) "with_unfolding_all " tacticSeq : tactic @@ -438,7 +438,7 @@ syntax (name := simp) "simp" (config)? (discharger)? (&" only")? (" [" withoutPosition((simpStar <|> simpErase <|> simpLemma),*) "]")? (location)? : tactic /-- `simp_all` is a stronger version of `simp [*] at *` where the hypotheses and target -are simplified multiple times until no simplication is applicable. +are simplified multiple times until no simplification is applicable. Only non-dependent propositional hypotheses are considered. -/ syntax (name := simpAll) "simp_all" (config)? (discharger)? (&" only")? @@ -527,7 +527,7 @@ macro "let' " d:letDecl : tactic => `(tactic| refine_lift' let $d:letDecl; ?_) /-- The left hand side of an induction arm, `| foo a b c` or `| @foo a b c` where `foo` is a constructor of the inductive type and `a b c` are the arguments -to the contstructor. +to the constructor. -/ syntax inductionAltLHS := "| " (("@"? ident) <|> hole) (ident <|> hole)* /-- diff --git a/src/include/lean/lean.h b/src/include/lean/lean.h index d7fc1ee5796b..b5d47d3355dc 100644 --- a/src/include/lean/lean.h +++ b/src/include/lean/lean.h @@ -126,7 +126,7 @@ x When this calling convention is used for an argument `x`, then it is safe to perform destructive updates to `x` if its RC is 1. -2- "borrowed" calling convention if it doesn't consume/decrement the RC, and it is the responsability of the caller +2- "borrowed" calling convention if it doesn't consume/decrement the RC, and it is the responsibility of the caller to decrement the RC. This is roughly equivalent to `S const & a` in C++, where `S` is a smart pointer, and `a` is the argument. diff --git a/src/initialize/init.cpp b/src/initialize/init.cpp index a9362e0c5725..9299c59fa713 100644 --- a/src/initialize/init.cpp +++ b/src/initialize/init.cpp @@ -21,7 +21,7 @@ extern "C" object* initialize_Init(uint8_t, object* w); extern "C" object* initialize_Lean(uint8_t, object* w); /* Initializes the Lean runtime. Before executing any code which uses the Lean package, -you must first call this function, and then `lean::io_mark_end_initialization`. Inbetween +you must first call this function, and then `lean::io_mark_end_initialization`. In between these two calls, you may also have to run additional initializers for your own modules. */ extern "C" LEAN_EXPORT void lean_initialize() { save_stack_info(); diff --git a/src/kernel/inductive.cpp b/src/kernel/inductive.cpp index 1bf7ba7789da..2238b24a256c 100644 --- a/src/kernel/inductive.cpp +++ b/src/kernel/inductive.cpp @@ -1091,7 +1091,7 @@ static pair> mk_aux_rec_name_map(environment const & aux_e /* This function is only called if we have created auxiliary inductive types when eliminating the nested inductives. */ lean_assert(length(all_names) > ntypes); - /* Remark: we use the `main_name` to declarate the auxiliary recursors as: .rec_1, .rec_2, ... + /* Remark: we use the `main_name` to declare the auxiliary recursors as: .rec_1, .rec_2, ... This is a little bit asymmetrical if `d` is a mutual declaration, but it makes sure we have simple names. */ buffer old_rec_names; name_map rec_map; diff --git a/src/kernel/level.h b/src/kernel/level.h index 7f26ed11ff08..b01240747ec9 100644 --- a/src/kernel/level.h +++ b/src/kernel/level.h @@ -140,7 +140,7 @@ bool is_equivalent(level const & lhs, level const & rhs); /** \brief Return the given level expression normal form */ level normalize(level const & l); -/** \brief If the result is true, then forall assignments \c A that assigns all parameters and metavariables occuring +/** \brief If the result is true, then forall assignments \c A that assigns all parameters and metavariables occurring in \c l1 and \l2, we have that the universe level l1[A] is bigger or equal to l2[A]. \remark This function assumes l1 and l2 are normalized */ @@ -191,7 +191,7 @@ level instantiate(level const & l, names const & ps, levels const & ls); /** \brief Printer for debugging purposes */ std::ostream & operator<<(std::ostream & out, level const & l); -/** \brief If the result is true, then forall assignments \c A that assigns all parameters and metavariables occuring +/** \brief If the result is true, then forall assignments \c A that assigns all parameters and metavariables occurring in \c l, l[A] != zero. */ bool is_not_zero(level const & l); diff --git a/src/kernel/type_checker.cpp b/src/kernel/type_checker.cpp index ded2680ef1c0..1527ee2e4bc2 100644 --- a/src/kernel/type_checker.cpp +++ b/src/kernel/type_checker.cpp @@ -862,7 +862,7 @@ auto type_checker::lazy_delta_reduction_step(expr & t_n, expr & s_n) -> reductio return reduction_status::DefUnknown; } else if (d_t && !d_s) { /* If `s_n` is a projection application, we try to unfold it instead. - We added this extra test to address a perfomance issue at defeq tests such as + We added this extra test to address a performance issue at defeq tests such as ```lean expensive_term =?= instFoo.1 a ``` diff --git a/src/lake/Lake/Util/Async.lean b/src/lake/Lake/Util/Async.lean index f52ddb143ed8..f7103a515a1f 100644 --- a/src/lake/Lake/Util/Async.lean +++ b/src/lake/Lake/Util/Async.lean @@ -112,7 +112,7 @@ class BindAsync (n : Type u → Type v) (k : Type u → Type u) where export BindAsync (bindAsync) class SeqAsync (n : outParam $ Type u → Type v) (k : Type u → Type u) where - /-- Combine two (a)synchronous tasks, applying the result of the second one ot the first one. -/ + /-- Combine two (a)synchronous tasks, applying the result of the second one to the first one. -/ seqAsync {α β : Type u} : k (α → β) → k α → n (k β) export SeqAsync (seqAsync) diff --git a/src/lake/tests/buildArgs/test.sh b/src/lake/tests/buildArgs/test.sh index b7ba40faf5d6..fb44a535ffda 100755 --- a/src/lake/tests/buildArgs/test.sh +++ b/src/lake/tests/buildArgs/test.sh @@ -26,7 +26,7 @@ ${LAKE} build +Hello -R -KweakLeanArgs=-DwarningAsError=true | tee -a produced.o ${LAKE} build +Hello:o -R echo "# compile args" >> produced.out -# Use `head -n1` to avoid extranous warnings on Windows with current Lean (8/1/23) +# Use `head -n1` to avoid extraneous warnings on Windows with current Lean (8/1/23) ${LAKE} build +Hello:o -R -KleancArgs=-DBAR | head -n1 | tee -a produced.out ${LAKE} build +Hello:o -R @@ -35,7 +35,7 @@ ${LAKE} build +Hello:o -R -KweakLeancArgs=-DBAR | tee -a produced.out ${LAKE} build +Hello:dynlib Hello:shared hello -R echo "# link args" >> produced.out -# Use `head -n1` to avoid extranous warnings on MacOS with current Lean (6/8/23) +# Use `head -n1` to avoid extraneous warnings on MacOS with current Lean (6/8/23) ${LAKE} build +Hello:dynlib -R -KlinkArgs=-Lbuild/lib | head -n1 | tee -a produced.out ${LAKE} build Hello:shared -R -KlinkArgs=-Lbuild/lib | head -n1 | tee -a produced.out ${LAKE} build hello -R -KlinkArgs=-Lbuild/lib | head -n1 | tee -a produced.out diff --git a/src/lake/tests/rebuild/test.sh b/src/lake/tests/rebuild/test.sh index 50cbab1d3b12..5e69a6ad6e62 100755 --- a/src/lake/tests/rebuild/test.sh +++ b/src/lake/tests/rebuild/test.sh @@ -5,7 +5,7 @@ LAKE=${LAKE:-../../build/bin/lake} ./clean.sh -# Tests that Lake rebulds C files and relinks executables on changes +# Tests that Lake rebuilds C files and relinks executables on changes # See https://github.com/leanprover/lake/issues/75 # The exact issue is no longer applicable as Lake now always rebuilds C files diff --git a/src/library/annotation.h b/src/library/annotation.h index b3783fab8085..8f6fa5465596 100644 --- a/src/library/annotation.h +++ b/src/library/annotation.h @@ -10,7 +10,7 @@ Author: Leonardo de Moura namespace lean { /** \brief Declare a new kind of annotation. It must only be invoked at startup time - Use helper obect #register_annotation_fn. */ + Use helper object #register_annotation_fn. */ void register_annotation(name const & n); /** \brief Create an annotated expression with tag \c kind based on \c e. diff --git a/src/library/compiler/cse.cpp b/src/library/compiler/cse.cpp index d2fd28946d69..057b30356796 100644 --- a/src/library/compiler/cse.cpp +++ b/src/library/compiler/cse.cpp @@ -255,7 +255,7 @@ class cce_fn { expr const & fvar = m_fvars[k]; if (get_fvar_idx(fvar) > max_idx) { m_fvars.insert(k, new_fvar); - /* We need to save the pairs to replace the `target` on let-declarations that occurr after k */ + /* We need to save the pairs to replace the `target` on let-declarations that occur after k */ target_jmp_pairs.emplace_back(target, jmp); break; } diff --git a/src/library/compiler/csimp.cpp b/src/library/compiler/csimp.cpp index 252d87807ac4..34d5e51ade13 100644 --- a/src/library/compiler/csimp.cpp +++ b/src/library/compiler/csimp.cpp @@ -825,7 +825,7 @@ class csimp_fn { For example, consider the following scenario. When starting a `float_cases_on` operation, we determine that the already processed entries `[_j_1._join, _x_1]` do not depend on the operation. Moreover, `_j_1._join` is a new join-point that depends on `_x_1`. Recall that entries are in reverse - dependecy order, and this is why `_j_1._join` occurs before `_x_1`. + dependency order, and this is why `_j_1._join` occurs before `_x_1`. Then, during the actual execution of the `float_cases_on` operation, we create a new joint point `_j_2._join` that depends on `_j_1._join`, and is consequently attached to `_x_1`, that is, `m_fvar2jps[_x_1]` contains `_j_2._join`. After executing this procedure, `entries` will contain `[_j_1._join, _j_2._join, _x_1]` which is incorrect @@ -1798,7 +1798,7 @@ class csimp_fn { if (!is_app(r)) return r; fn = get_app_fn(r); /* If `r` is an application of the form `g ...` where - `g` is an interal name and `g` prefix of the main function, we unfold this + `g` is an internal name and `g` prefix of the main function, we unfold this application too. */ if (!is_constant(fn) || !is_internal_name(const_name(fn)) || const_name(fn).get_prefix() != main) diff --git a/src/library/compiler/specialize.cpp b/src/library/compiler/specialize.cpp index 6298383dcda9..c58012f5b859 100644 --- a/src/library/compiler/specialize.cpp +++ b/src/library/compiler/specialize.cpp @@ -546,7 +546,7 @@ class specialize_fn { /* Recall that `m_ctx.m_vars` contains all variables (lambda and let) the specialization depends on, and `m_ctx.m_params` contains the ones that should be lambda abstracted. */ m_ctx.m_vars.push_back(x); - /* Thus, a variable occuring outside of a binder is only lambda abstracted if it is not + /* Thus, a variable occurring outside of a binder is only lambda abstracted if it is not a let-variable. */ if (!v) m_ctx.m_params.push_back(x); } @@ -959,7 +959,7 @@ class specialize_fn { types, and it will fail to infer the type of `n`-applications if we do not have an entry in the environment. - Remark: we mark the axiom as `meta` to make sure it does not polute the environment + Remark: we mark the axiom as `meta` to make sure it does not pollute the environment regular definitions. We also considered the following cleaner solution: modify `csimp` to use a custom diff --git a/src/library/print.h b/src/library/print.h index 98b8892d5225..40e696a493c8 100644 --- a/src/library/print.h +++ b/src/library/print.h @@ -14,7 +14,7 @@ bool is_used_name(expr const & t, name const & n); name pick_unused_name(expr const & t, name const & s); /** \brief Return the body of the binding \c b, where variable #0 is replaced by a local constant with a "fresh" name. - The name is considered fresh if it is not used by a constant or local constant occuring in the body of \c b. + The name is considered fresh if it is not used by a constant or local constant occurring in the body of \c b. The fresh constant is also returned (second return value). \remark If preserve_type is false, then the local constant will not use binding_domain. diff --git a/src/runtime/alloc.cpp b/src/runtime/alloc.cpp index 958afa4d1b63..ea0a438311f4 100644 --- a/src/runtime/alloc.cpp +++ b/src/runtime/alloc.cpp @@ -467,7 +467,7 @@ void finalize_alloc() { LEAN_THREAD_VALUE(uint64_t, g_heartbeat, 0); #endif -/* Helper function for increasing hearbeat even when LEAN_SMALL_ALLOCATOR is not defined */ +/* Helper function for increasing heartbeat even when LEAN_SMALL_ALLOCATOR is not defined */ extern "C" LEAN_EXPORT void lean_inc_heartbeat() { #ifdef LEAN_SMALL_ALLOCATOR if (g_heap) diff --git a/src/runtime/interrupt.h b/src/runtime/interrupt.h index 662951341064..a01a5394048c 100644 --- a/src/runtime/interrupt.h +++ b/src/runtime/interrupt.h @@ -24,7 +24,7 @@ class scope_heartbeat : flet { scope_heartbeat(size_t curr); }; -/** \brief Threshold on the number of hearbeats. check_system will throw +/** \brief Threshold on the number of heartbeats. check_system will throw an exception if a thread exceeds the limit. The default is unlimited. The limit is checked in the check_system API. @@ -52,7 +52,7 @@ struct scoped_interrupt_flag : flet { void check_interrupted(); /** - \brief Check system resources: stack, memory, hearbeat, interrupt flag. + \brief Check system resources: stack, memory, heartbeat, interrupt flag. */ void check_system(char const * component_name); diff --git a/src/runtime/io.cpp b/src/runtime/io.cpp index 93b67c0f85a6..75741e6b64fc 100644 --- a/src/runtime/io.cpp +++ b/src/runtime/io.cpp @@ -623,7 +623,7 @@ extern "C" LEAN_EXPORT obj_res lean_io_metadata(b_obj_arg fname, obj_arg) { cnstr_set(mdata, 0, timespec_to_obj(st.st_atimespec)); cnstr_set(mdata, 1, timespec_to_obj(st.st_mtimespec)); #elif defined(LEAN_WINDOWS) - // TOOD: sub-second precision on Windows + // TODO: sub-second precision on Windows cnstr_set(mdata, 0, timespec_to_obj(timespec { st.st_atime, 0 })); cnstr_set(mdata, 1, timespec_to_obj(timespec { st.st_mtime, 0 })); #else diff --git a/src/runtime/object.cpp b/src/runtime/object.cpp index aece5ff2d0b1..1e1276568674 100644 --- a/src/runtime/object.cpp +++ b/src/runtime/object.cpp @@ -725,7 +725,7 @@ class task_manager { mark_mt(v); t->m_value = v; /* After the task has been finished and we propagated - dependecies, we can release `m_imp` and keep just the value */ + dependencies, we can release `m_imp` and keep just the value */ free_task_imp(t->m_imp); t->m_imp = nullptr; m_task_finished_cv.notify_all(); diff --git a/src/runtime/utf8.h b/src/runtime/utf8.h index 50e8d6b7e381..fdbcbff52005 100644 --- a/src/runtime/utf8.h +++ b/src/runtime/utf8.h @@ -47,7 +47,7 @@ void utf8_decode(std::string const & str, std::vector & out); /* Push a unicode scalar value into a utf-8 encoded string */ void push_unicode_scalar(std::string & s, unsigned code); -/* Store unicode scalar value at `d`, `d` must point to memory with enough space to stroe `c`. +/* Store unicode scalar value at `d`, `d` must point to memory with enough space to store `c`. Return the number of bytes consumed. */ unsigned push_unicode_scalar(char * d, unsigned code); } diff --git a/src/util/name.cpp b/src/util/name.cpp index c1960195165f..9813bdfc84d3 100644 --- a/src/util/name.cpp +++ b/src/util/name.cpp @@ -41,7 +41,7 @@ bool is_letter_like_unicode(unsigned u) { } bool is_sub_script_alnum_unicode(unsigned u) { return - (0x207f <= u && u <= 0x2089) || // n superscript and numberic subscripts + (0x207f <= u && u <= 0x2089) || // n superscript and numeric subscripts (0x2090 <= u && u <= 0x209c) || // letter-like subscripts (0x1d62 <= u && u <= 0x1d6a); // letter-like subscripts } diff --git a/src/version.h.in b/src/version.h.in index 65ea409c0c69..3128fad3119c 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -7,6 +7,6 @@ // Additional version description like "nightly-2018-03-11" #define LEAN_SPECIAL_VERSION_DESC "@LEAN_SPECIAL_VERSION_DESC@" -// When git_sha1 is not avilable, lean reads bin/version file and +// When git_sha1 is not available, lean reads bin/version file and // assign its contents to LEAN_PACKAGE_VERSION #define LEAN_PACKAGE_VERSION "@LEAN_PACKAGE_VERSION@" diff --git a/tests/bench/cross.yaml b/tests/bench/cross.yaml index 2b1c841cf0a6..aee572034909 100644 --- a/tests/bench/cross.yaml +++ b/tests/bench/cross.yaml @@ -258,7 +258,7 @@ run: # Implements a simple run driver that just executes one of the passed run_cmds # in each benchmarking run. - # It meausures the time using the perf stat tool (runner=perf_stat). + # It measures the time using the perf stat tool (runner=perf_stat). # # The constructor calls the ``setup`` method. exec_misc: @@ -297,7 +297,7 @@ run: # Enable: Disables swapping on the system before the benchmarking and enables it after. disable_swap_active: null - # Enable: Drop page cache, directoy entries and inodes before every benchmarking run. + # Enable: Drop page cache, directory entries and inodes before every benchmarking run. drop_fs_caches_active: null # Enable: Adds random environment variables. @@ -355,7 +355,7 @@ run: # Disables swapping on the system before the benchmarking and enables it after. disable_swap_misc: !!map {} - # Drop page cache, directoy entries and inodes before every benchmarking run. + # Drop page cache, directory entries and inodes before every benchmarking run. drop_fs_caches_misc: # Free dentries and inodes diff --git a/tests/bench/speedcenter.yaml b/tests/bench/speedcenter.yaml index 91a6570c1f67..ca5ec6cec921 100644 --- a/tests/bench/speedcenter.yaml +++ b/tests/bench/speedcenter.yaml @@ -348,7 +348,7 @@ run: # Enable: Disables swapping on the system before the benchmarking and enables it after. disable_swap_active: null - # Enable: Drop page cache, directoy entries and inodes before every benchmarking run. + # Enable: Drop page cache, directory entries and inodes before every benchmarking run. drop_fs_caches_active: null # Enable: Adds random environment variables. @@ -409,7 +409,7 @@ run: # Disables swapping on the system before the benchmarking and enables it after. disable_swap_misc: !!map {} - # Drop page cache, directoy entries and inodes before every benchmarking run. + # Drop page cache, directory entries and inodes before every benchmarking run. drop_fs_caches_misc: # Free dentries and inodes diff --git a/tests/elabissues/invalid_field_notation_error_msg.lean b/tests/elabissues/invalid_field_notation_error_msg.lean index fa3293593ad3..889c60853865 100644 --- a/tests/elabissues/invalid_field_notation_error_msg.lean +++ b/tests/elabissues/invalid_field_notation_error_msg.lean @@ -6,7 +6,7 @@ An exact line number would help, but even so it would be great to report the fie [Leo]: the bad line number is due to the transition from Lean3 to Lean4. The new frontend reports the exact position. It still fails to elaborate since the types of `f`, `g` and `h` are unknown, and there is no `Foo.f6`. -I decided to no report the field, users have all information they neeed when the correct position is reported. +I decided to not report the field, users have all information they need when the correct position is reported. -/ structure Foo := (n : Nat) def Foo.f1 (f : Foo) : Nat := f.n diff --git a/tests/elabissues/leaky_tmp_metavars.lean b/tests/elabissues/leaky_tmp_metavars.lean index e9c30be21e98..b32ddf80f178 100644 --- a/tests/elabissues/leaky_tmp_metavars.lean +++ b/tests/elabissues/leaky_tmp_metavars.lean @@ -18,7 +18,7 @@ class Top : Type := (x : Unit) instance AllFoo (α : Type) : Foo α := {x:=()} /- -When the subgoal `[@HasParam α (@FooToBar α (AllFoo α))]` is triggerred, `α` is not known. +When the subgoal `[@HasParam α (@FooToBar α (AllFoo α))]` is triggered, `α` is not known. This happens for two reasons: diff --git a/tests/elabissues/typeclasses_with_umetavariables.lean b/tests/elabissues/typeclasses_with_umetavariables.lean index e61d4d44cb9c..08a4868a4aa5 100644 --- a/tests/elabissues/typeclasses_with_umetavariables.lean +++ b/tests/elabissues/typeclasses_with_umetavariables.lean @@ -1,5 +1,5 @@ /- -In constrast to expression metavariables (see: typeclasses_with_emetavariables.lean), +In contrast to expression metavariables (see: typeclasses_with_emetavariables.lean), typeclass resolution is not stalled due to the presence of universe metavariables. In the current C++ implementation, some (but not all) universe metavariables appearing diff --git a/tests/elabissues/vars.lean b/tests/elabissues/vars.lean index 3ee28097f872..e4e65bb40cc2 100644 --- a/tests/elabissues/vars.lean +++ b/tests/elabissues/vars.lean @@ -18,7 +18,7 @@ Dummy.val α /- In Lean4, we should use a different approach. We keep a metavariable context in the command elaborator. -Before, a declaration `D` is sent to the kernel we resolve the metavariables occuring in `D`. +Before, a declaration `D` is sent to the kernel we resolve the metavariables occurring in `D`. We must implement a MetavarContext GC to make sure the metavariable context does not keep increasing. That is, after a declaration is sent to the kernel, we visit all variables in the elaborator context and instantiate assigned metavariables. Then, we delete all assigned metavariables. diff --git a/tests/lean/rewrite.lean b/tests/lean/rewrite.lean index b088fa0df9f5..80dc3bb54c88 100644 --- a/tests/lean/rewrite.lean +++ b/tests/lean/rewrite.lean @@ -85,7 +85,7 @@ example : [f 1, f 2, f 1, f 2] = [0, 0, 0, 0] := by example : [f 1, f 2, f 1, f 2] = [0, 0, 0, 0] := by rw (config := {occs := .neg [1]}) [w] -- Again, the rejected first occurrence nevertheless instantiates the metavariables. - -- Argubly the state here should be `[f 1, 0, f 1, 0] = [0, 0, 0, 0]`, + -- Arguably the state here should be `[f 1, 0, f 1, 0] = [0, 0, 0, 0]`, -- but for now if `[f 1, f 2, 0, f 2] = [0, 0, 0, 0]` trace_state rw [w, w] diff --git a/tests/lean/run/909.lean b/tests/lean/run/909.lean index f2955ed52c67..14f87d448901 100644 --- a/tests/lean/run/909.lean +++ b/tests/lean/run/909.lean @@ -16,7 +16,7 @@ instance (a b : Date) : Decidable (a <= b) := -/ /- -This implemenation evaluates successfully: +This implementation evaluates successfully: instance (a b : Date) : Decidable (a <= b) := dite (a.val <= b.val) isTrue (fun nle => isFalse (fun hf => False.elim (nle hf))) -/ diff --git a/tests/lean/run/meta.lean b/tests/lean/run/meta.lean index b2451c565095..c3518a297705 100644 --- a/tests/lean/run/meta.lean +++ b/tests/lean/run/meta.lean @@ -16,7 +16,7 @@ def mkLam1 : MetaM Expr := /- The following `withLocalDecl` extends the local context with `(x : Nat)`, and executes the lambda with an expression `x`. -/ withLocalDecl `x BinderInfo.default (mkConst `Nat) fun x => - /- Similiar to the method above, but sets `BinderInfo.default`. -/ + /- Similar to the method above, but sets `BinderInfo.default`. -/ withLocalDeclD `y (mkConst `Nat) fun y => do -- Double backticks instruct Lean to resolve the names at compilation time let b ← mkAppM ``HAdd.hAdd #[x, y] -- `x + y` diff --git a/tests/lean/run/newfrontend5.lean b/tests/lean/run/newfrontend5.lean index 57c2def559f7..40caecfd6330 100644 --- a/tests/lean/run/newfrontend5.lean +++ b/tests/lean/run/newfrontend5.lean @@ -44,7 +44,7 @@ The unification constraint is easily solved set_option pp.all true --- The following test got stuck at universe contraints after if fixed the `decAux?` bug. +-- The following test got stuck at universe constraints after if fixed the `decAux?` bug. -- #check let x := (fun f => (f, f)) @id; (x.1 (), x.2 true) -- works -- #check_failure let x := (fun f => (f, f)) id; (x.1 (), x.2 true) -- fails as expected From 9f50f44eed0ea3b49490b77c303b7e4f6e54fc2a Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Sun, 8 Oct 2023 17:22:14 -0700 Subject: [PATCH 28/71] perf: missing cache at `whnfImp` --- src/Lean/Meta/WHNF.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lean/Meta/WHNF.lean b/src/Lean/Meta/WHNF.lean index 4759521b743f..94a3db21a5c8 100644 --- a/src/Lean/Meta/WHNF.lean +++ b/src/Lean/Meta/WHNF.lean @@ -871,8 +871,8 @@ partial def whnfImp (e : Expr) : MetaM Expr := | some v => cache useCache e v | none => match (← unfoldDefinition? e') with - | some e => whnfImp e - | none => cache useCache e e' + | some e'' => cache useCache e (← whnfImp e'') + | none => cache useCache e e' /-- If `e` is a projection function that satisfies `p`, then reduce it -/ def reduceProjOf? (e : Expr) (p : Name → Bool) : MetaM (Option Expr) := do From 00e981edcdf33b05194b8daf2bdfde7d8ff1aaaa Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Mon, 2 Oct 2023 10:32:50 +0200 Subject: [PATCH 29/71] perf: do not inhibit caching of default-level `match` reduction --- src/Lean/Meta/WHNF.lean | 11 ++++--- tests/bench/reduceMatch.lean | 40 ++++++++++++++++++++++++ tests/bench/speedcenter.exec.velcom.yaml | 6 ++++ 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 tests/bench/reduceMatch.lean diff --git a/src/Lean/Meta/WHNF.lean b/src/Lean/Meta/WHNF.lean index 94a3db21a5c8..cc9159aaf093 100644 --- a/src/Lean/Meta/WHNF.lean +++ b/src/Lean/Meta/WHNF.lean @@ -419,10 +419,13 @@ private def whnfMatcher (e : Expr) : MetaM Expr := do For example, `simp [Int.div]` will not unfold the application `Int.div 2 1` occurring in the target. TODO: consider other solutions; investigate whether the solution above produces counterintuitive behavior. -/ - let mut transparency ← getTransparency - if transparency == TransparencyMode.reducible then - transparency := TransparencyMode.instances - withTransparency transparency <| withReader (fun ctx => { ctx with canUnfold? := canUnfoldAtMatcher }) do + if (← getTransparency) matches .instances | .reducible then + -- Also unfold some default-reducible constants; see `canUnfoldAtMatcher` + withTransparency .instances <| withReader (fun ctx => { ctx with canUnfold? := canUnfoldAtMatcher }) do + whnf e + else + -- Do NOT use `canUnfoldAtMatcher` here as it does not affect all/default reducibility and inhibits caching (#2564). + -- In the future, we want to work on better reduction strategies that do not require caching. whnf e def reduceMatcher? (e : Expr) : MetaM ReduceMatcherResult := do diff --git a/tests/bench/reduceMatch.lean b/tests/bench/reduceMatch.lean new file mode 100644 index 000000000000..8fc0af9ee6d8 --- /dev/null +++ b/tests/bench/reduceMatch.lean @@ -0,0 +1,40 @@ +import Lean + +/-! + #2564. `match` reduction currently has some special cases. + When combined with nonlinear functions like `List.insert` below, + it is crucial to preserve sharing during reduction. -/ + +section decidability_instances + +variable {α : Type} {p : α → Prop} [DecidablePred p] + +instance decidableBex : ∀ (l : List α), Decidable (∃ x, x ∈ l → p x) + | [] => isFalse sorry + | x::xs => + match ‹DecidablePred p› x with + | isTrue h₁ => isTrue sorry + | isFalse h₁ => match decidableBex xs with + | isTrue h₂ => isTrue sorry + | isFalse h₂ => isFalse sorry + +instance decidableBall (l : List α) : Decidable (∀ x, x ∈ l → p x) := + match (inferInstance : Decidable <| ∃ x, x ∈ l → ¬ p x) with + | isFalse h => isTrue $ fun x hx => match ‹DecidablePred p› x with + | isTrue h' => h' + | isFalse h' => False.elim $ h sorry + | isTrue h => isFalse sorry + +end decidability_instances + +@[inline] protected def List.insert {α : Type} [DecidableEq α] (a : α) (l : List α) : List α := + if a ∈ l then l else a :: l + +def parts : List (List Nat) := List.insert ([1, 1, 0, 0]) <| List.insert ([0, 0, 1, 1]) <| + List.insert ([1, 0, 0, 1]) <| List.insert ([1, 1, 1, 0]) <| List.insert ([1, 0, 0, 0]) <| + List.insert [1, 2, 3, 4] <| List.insert [5, 6, 7, 8] [] + +#eval show Lean.Elab.Command.CommandElabM _ from + for _ in [0:10] do + Lean.Elab.Command.elabCommand (← + `(example : ∀ (x) (_ : x ∈ parts) (y) (_ : y ∈ parts), x ++ y ∉ parts := by decide)) diff --git a/tests/bench/speedcenter.exec.velcom.yaml b/tests/bench/speedcenter.exec.velcom.yaml index e70cbdab41ba..6cc0d1783d0f 100644 --- a/tests/bench/speedcenter.exec.velcom.yaml +++ b/tests/bench/speedcenter.exec.velcom.yaml @@ -282,6 +282,12 @@ cmd: ./rbmap_library.lean.out 2000000 build_config: cmd: ./compile.sh rbmap_library.lean +- attributes: + description: reduceMatch + tags: [fast, suite] + run_config: + <<: *time + cmd: lean reduceMatch.lean - attributes: description: unionfind tags: [fast, suite] From 41ed5ddf577c68be01ac784ac92fb6aebca81844 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 9 Oct 2023 15:00:56 +1100 Subject: [PATCH 30/71] chore: add missing if statements to pr-release.yml workflow (#2639) --- .github/workflows/pr-release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/pr-release.yml b/.github/workflows/pr-release.yml index f02274bbfbd4..54f912d9a1a5 100644 --- a/.github/workflows/pr-release.yml +++ b/.github/workflows/pr-release.yml @@ -81,6 +81,7 @@ jobs: # Mathlib CI will be responsible for reporting back success or failure # to the PR comments asynchronously. - name: Cleanup workspace + if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} run: | sudo rm -rf * @@ -94,6 +95,7 @@ jobs: fetch-depth: 0 - name: Check if branch exists + if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} id: check_branch run: | git config user.name "leanprover-community-mathlib4-bot" @@ -119,5 +121,6 @@ jobs: fi - name: Push changes + if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} run: | git push origin lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} From ca0e6b0522e2948e8d819886be1e8fc106354947 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 9 Oct 2023 22:04:33 +1100 Subject: [PATCH 31/71] chore: fix MVarId.getType' (#2595) * chore: fix MVarId.getType' * add test --- src/Lean/Meta/Tactic/Util.lean | 5 ++++- tests/lean/2505.lean | 27 +++++++++++++++++++++++++++ tests/lean/2505.lean.expected.out | 3 +++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/lean/2505.lean create mode 100644 tests/lean/2505.lean.expected.out diff --git a/src/Lean/Meta/Tactic/Util.lean b/src/Lean/Meta/Tactic/Util.lean index cc2e010278d1..e6fb759249b0 100644 --- a/src/Lean/Meta/Tactic/Util.lean +++ b/src/Lean/Meta/Tactic/Util.lean @@ -63,8 +63,11 @@ def getMVarType (mvarId : MVarId) : MetaM Expr := /-- Get the type the given metavariable after instantiating metavariables and reducing to weak head normal form. -/ +-- The `instantiateMVars` needs to be on the outside, +-- since `whnf` can unfold local definitions which may introduce metavariables. +-- We don't need an `instantiateMVars` before the `whnf`, since it instantiates as necessary. def _root_.Lean.MVarId.getType' (mvarId : MVarId) : MetaM Expr := do - whnf (← instantiateMVars (← mvarId.getType)) + instantiateMVars (← whnf (← mvarId.getType)) @[deprecated MVarId.getType'] def getMVarType' (mvarId : MVarId) : MetaM Expr := do diff --git a/tests/lean/2505.lean b/tests/lean/2505.lean new file mode 100644 index 000000000000..1121a062377e --- /dev/null +++ b/tests/lean/2505.lean @@ -0,0 +1,27 @@ +import Lean + +open Lean Elab Tactic Meta + +inductive A : Nat → Prop + +def Lean.MVarId.getType'' (mvarId : MVarId) : MetaM Expr := do + instantiateMVars (← whnf (← mvarId.getType)) + +elab "the_target" : tactic => Tactic.withMainContext do + dbg_trace "target : {← (← getMainGoal).getType'}" + dbg_trace "target' : {← (← getMainGoal).getType''}" + +example : True := by + let p := A ?n + case n => exact 1 + have : p := ?h + case h => + the_target + sorry + sorry +/- +Prior to #2595, this gave: + +target : A ?_uniq.3033 +target' : A (OfNat.ofNat.{0} Nat 1 (instOfNatNat 1)) +-/ diff --git a/tests/lean/2505.lean.expected.out b/tests/lean/2505.lean.expected.out new file mode 100644 index 000000000000..6610d40a3544 --- /dev/null +++ b/tests/lean/2505.lean.expected.out @@ -0,0 +1,3 @@ +target : A (OfNat.ofNat.{0} Nat 1 (instOfNatNat 1)) +target' : A (OfNat.ofNat.{0} Nat 1 (instOfNatNat 1)) +2505.lean:14:0-14:7: warning: declaration uses 'sorry' From 833e778cd59f292205cbbf526d29772b11bcd298 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 11 Oct 2023 12:47:59 +1100 Subject: [PATCH 32/71] chore: add axiom for tracking use of reduceBool / reduceNat (#2654) --- src/Init/Core.lean | 16 ++++++++++++++-- tests/lean/reduceBool.lean | 9 +++++++++ tests/lean/reduceBool.lean.expected.out | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 tests/lean/reduceBool.lean create mode 100644 tests/lean/reduceBool.lean.expected.out diff --git a/src/Init/Core.lean b/src/Init/Core.lean index 1a214ee16361..a14aea7316ae 100644 --- a/src/Init/Core.lean +++ b/src/Init/Core.lean @@ -1612,6 +1612,11 @@ class Antisymm {α : Sort u} (r : α → α → Prop) where namespace Lean /-! # Kernel reduction hints -/ +/-- +Depends on the correctness of the Lean compiler, interpreter, and all `[implemented_by ...]` and `[extern ...]` annotations. +-/ +axiom trustCompiler : False + /-- When the kernel tries to reduce a term `Lean.reduceBool c`, it will invoke the Lean interpreter to evaluate `c`. The kernel will not use the interpreter if `c` is not a constant. @@ -1631,7 +1636,10 @@ Recall that the compiler trusts the correctness of all `[implemented_by ...]` an If an extern function is executed, then the trusted code base will also include the implementation of the associated foreign function. -/ -opaque reduceBool (b : Bool) : Bool := b +opaque reduceBool (b : Bool) : Bool := + -- This ensures that `#print axioms` will track use of `reduceBool`. + have := trustCompiler + b /-- Similar to `Lean.reduceBool` for closed `Nat` terms. @@ -1640,7 +1648,11 @@ Remark: we do not have plans for supporting a generic `reduceValue {α} (a : α) The main issue is that it is non-trivial to convert an arbitrary runtime object back into a Lean expression. We believe `Lean.reduceBool` enables most interesting applications (e.g., proof by reflection). -/ -opaque reduceNat (n : Nat) : Nat := n +opaque reduceNat (n : Nat) : Nat := + -- This ensures that `#print axioms` will track use of `reduceNat`. + have := trustCompiler + n + /-- The axiom `ofReduceBool` is used to perform proofs by reflection. See `reduceBool`. diff --git a/tests/lean/reduceBool.lean b/tests/lean/reduceBool.lean new file mode 100644 index 000000000000..d5f17167eb98 --- /dev/null +++ b/tests/lean/reduceBool.lean @@ -0,0 +1,9 @@ +def f := 42 +def f' := Lean.reduceNat f + +#print axioms f' + +def g := false +def g' := Lean.reduceBool g + +#print axioms g' diff --git a/tests/lean/reduceBool.lean.expected.out b/tests/lean/reduceBool.lean.expected.out new file mode 100644 index 000000000000..3dd4d42cef46 --- /dev/null +++ b/tests/lean/reduceBool.lean.expected.out @@ -0,0 +1,2 @@ +'f'' depends on axioms: [Lean.trustCompiler] +'g'' depends on axioms: [Lean.trustCompiler] From 076908d13b92ce8a9052aae20ca4cd09dc4115ee Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 11 Oct 2023 14:08:03 +1100 Subject: [PATCH 33/71] feat: replay constants into an Environment (#2617) * feat: replay constants into an Environment --- src/Lean/Data/NameMap.lean | 7 ++ src/Lean/Declaration.lean | 18 ++-- src/Lean/Replay.lean | 169 ++++++++++++++++++++++++++++++++++ src/Lean/Util/FoldConsts.lean | 19 ++++ 4 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 src/Lean/Replay.lean diff --git a/src/Lean/Data/NameMap.lean b/src/Lean/Data/NameMap.lean index dae6964c4cb5..4fb27f5ed1e8 100644 --- a/src/Lean/Data/NameMap.lean +++ b/src/Lean/Data/NameMap.lean @@ -46,6 +46,13 @@ def contains (s : NameSet) (n : Name) : Bool := RBMap.contains s n instance : ForIn m NameSet Name := inferInstanceAs (ForIn _ (RBTree ..) ..) +/-- The union of two `NameSet`s. -/ +def append (s t : NameSet) : NameSet := + s.mergeBy (fun _ _ _ => .unit) t + +instance : Append NameSet where + append := NameSet.append + end NameSet def NameSSet := SSet Name diff --git a/src/Lean/Declaration.lean b/src/Lean/Declaration.lean index 1b3fb68e3907..ad70c0f4419d 100644 --- a/src/Lean/Declaration.lean +++ b/src/Lean/Declaration.lean @@ -70,11 +70,11 @@ structure ConstantVal where name : Name levelParams : List Name type : Expr - deriving Inhabited + deriving Inhabited, BEq structure AxiomVal extends ConstantVal where isUnsafe : Bool - deriving Inhabited + deriving Inhabited, BEq @[export lean_mk_axiom_val] def mkAxiomValEx (name : Name) (levelParams : List Name) (type : Expr) (isUnsafe : Bool) : AxiomVal := { @@ -119,7 +119,7 @@ structure TheoremVal extends ConstantVal where List of all (including this one) declarations in the same mutual block. See comment at `DefinitionVal.all`. -/ all : List Name := [name] - deriving Inhabited + deriving Inhabited, BEq /-- Value for an opaque constant declaration `opaque x : t := e` -/ structure OpaqueVal extends ConstantVal where @@ -129,7 +129,7 @@ structure OpaqueVal extends ConstantVal where List of all (including this one) declarations in the same mutual block. See comment at `DefinitionVal.all`. -/ all : List Name := [name] - deriving Inhabited + deriving Inhabited, BEq @[export lean_mk_opaque_val] def mkOpaqueValEx (name : Name) (levelParams : List Name) (type : Expr) (value : Expr) (isUnsafe : Bool) (all : List Name) : OpaqueVal := { @@ -272,7 +272,7 @@ structure ConstructorVal extends ConstantVal where /-- Number of fields (i.e., arity - nparams) -/ numFields : Nat isUnsafe : Bool - deriving Inhabited + deriving Inhabited, BEq @[export lean_mk_constructor_val] def mkConstructorValEx (name : Name) (levelParams : List Name) (type : Expr) (induct : Name) (cidx numParams numFields : Nat) (isUnsafe : Bool) : ConstructorVal := { @@ -296,7 +296,7 @@ structure RecursorRule where nfields : Nat /-- Right hand side of the reduction rule -/ rhs : Expr - deriving Inhabited + deriving Inhabited, BEq structure RecursorVal extends ConstantVal where /-- List of all inductive datatypes in the mutual declaration that generated this recursor -/ @@ -322,7 +322,7 @@ structure RecursorVal extends ConstantVal where -/ k : Bool isUnsafe : Bool - deriving Inhabited + deriving Inhabited, BEq @[export lean_mk_recursor_val] def mkRecursorValEx (name : Name) (levelParams : List Name) (type : Expr) (all : List Name) (numParams numIndices numMotives numMinors : Nat) @@ -441,6 +441,10 @@ def isInductive : ConstantInfo → Bool | inductInfo _ => true | _ => false +def inductiveVal! : ConstantInfo → InductiveVal + | .inductInfo val => val + | _ => panic! "Expected a `ConstantInfo.inductInfo`." + /-- List of all (including this one) declarations in the same mutual block. -/ diff --git a/src/Lean/Replay.lean b/src/Lean/Replay.lean new file mode 100644 index 000000000000..d4922b834b7c --- /dev/null +++ b/src/Lean/Replay.lean @@ -0,0 +1,169 @@ +/- +Copyright (c) 2023 Scott Morrison. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison +-/ +import Lean.CoreM +import Lean.Util.FoldConsts + +/-! +# `Lean.Environment.replay` + +`replay env constantMap` will "replay" all the constants in `constantMap : HashMap Name ConstantInfo` into `env`, +sending each declaration to the kernel for checking. + +`replay` does not send constructors or recursors in `constantMap` to the kernel, +but rather checks that they are identical to constructors or recursors generated in the enviroment +after replaying any inductive definitions occurring in `constantMap`. + +`replay` can be used either as: +* a verifier for an `Environment`, by sending everything to the kernel, or +* a mechanism to safely transfer constants from one `Environment` to another. + +-/ + +namespace Lean.Environment + +namespace Replay + +structure Context where + newConstants : HashMap Name ConstantInfo + +structure State where + env : Environment + remaining : NameSet := {} + pending : NameSet := {} + postponedConstructors : NameSet := {} + postponedRecursors : NameSet := {} + +abbrev M := ReaderT Context <| StateRefT State IO + +/-- Check if a `Name` still needs processing. If so, move it from `remaining` to `pending`. -/ +def isTodo (name : Name) : M Bool := do + let r := (← get).remaining + if r.contains name then + modify fun s => { s with remaining := s.remaining.erase name, pending := s.pending.insert name } + return true + else + return false + +/-- Use the current `Environment` to throw a `KernelException`. -/ +def throwKernelException (ex : KernelException) : M Unit := do + let ctx := { fileName := "", options := ({} : KVMap), fileMap := default } + let state := { env := (← get).env } + Prod.fst <$> (Lean.Core.CoreM.toIO · ctx state) do Lean.throwKernelException ex + +/-- Add a declaration, possibly throwing a `KernelException`. -/ +def addDecl (d : Declaration) : M Unit := do + match (← get).env.addDecl d with + | .ok env => modify fun s => { s with env := env } + | .error ex => throwKernelException ex + +mutual +/-- +Check if a `Name` still needs to be processed (i.e. is in `remaining`). + +If so, recursively replay any constants it refers to, +to ensure we add declarations in the right order. + +The construct the `Declaration` from its stored `ConstantInfo`, +and add it to the environment. +-/ +partial def replayConstant (name : Name) : M Unit := do + if ← isTodo name then + let some ci := (← read).newConstants.find? name | unreachable! + replayConstants ci.getUsedConstantsAsSet + -- Check that this name is still pending: a mutual block may have taken care of it. + if (← get).pending.contains name then + match ci with + | .defnInfo info => + addDecl (Declaration.defnDecl info) + | .thmInfo info => + addDecl (Declaration.thmDecl info) + | .axiomInfo info => + addDecl (Declaration.axiomDecl info) + | .opaqueInfo info => + addDecl (Declaration.opaqueDecl info) + | .inductInfo info => + let lparams := info.levelParams + let nparams := info.numParams + let all ← info.all.mapM fun n => do pure <| ((← read).newConstants.find! n) + for o in all do + modify fun s => + { s with remaining := s.remaining.erase o.name, pending := s.pending.erase o.name } + let ctorInfo ← all.mapM fun ci => do + pure (ci, ← ci.inductiveVal!.ctors.mapM fun n => do + pure ((← read).newConstants.find! n)) + -- Make sure we are really finished with the constructors. + for (_, ctors) in ctorInfo do + for ctor in ctors do + replayConstants ctor.getUsedConstantsAsSet + let types : List InductiveType := ctorInfo.map fun ⟨ci, ctors⟩ => + { name := ci.name + type := ci.type + ctors := ctors.map fun ci => { name := ci.name, type := ci.type } } + addDecl (Declaration.inductDecl lparams nparams types false) + -- We postpone checking constructors, + -- and at the end make sure they are identical + -- to the constructors generated when we replay the inductives. + | .ctorInfo info => + modify fun s => { s with postponedConstructors := s.postponedConstructors.insert info.name } + -- Similarly we postpone checking recursors. + | .recInfo info => + modify fun s => { s with postponedRecursors := s.postponedRecursors.insert info.name } + | .quotInfo _ => + addDecl (Declaration.quotDecl) + modify fun s => { s with pending := s.pending.erase name } + +/-- Replay a set of constants one at a time. -/ +partial def replayConstants (names : NameSet) : M Unit := do + for n in names do replayConstant n + +end + +/-- +Check that all postponed constructors are identical to those generated +when we replayed the inductives. +-/ +def checkPostponedConstructors : M Unit := do + for ctor in (← get).postponedConstructors do + match (← get).env.constants.find? ctor, (← read).newConstants.find? ctor with + | some (.ctorInfo info), some (.ctorInfo info') => + if ! (info == info') then throw <| IO.userError s!"Invalid constructor {ctor}" + | _, _ => throw <| IO.userError s!"No such constructor {ctor}" + +/-- +Check that all postponed recursors are identical to those generated +when we replayed the inductives. +-/ +def checkPostponedRecursors : M Unit := do + for ctor in (← get).postponedRecursors do + match (← get).env.constants.find? ctor, (← read).newConstants.find? ctor with + | some (.recInfo info), some (.recInfo info') => + if ! (info == info') then throw <| IO.userError s!"Invalid recursor {ctor}" + | _, _ => throw <| IO.userError s!"No such recursor {ctor}" + +end Replay + +open Replay + +/-- +"Replay" some constants into an `Environment`, sending them to the kernel for checking. + +Throws a `IO.userError` if the kernel rejects a constant, +or if there are malformed recursors or constructors for inductive types. +-/ +def replay (newConstants : HashMap Name ConstantInfo) (env : Environment) : IO Environment := do + let mut remaining : NameSet := ∅ + for (n, ci) in newConstants.toList do + -- We skip unsafe constants, and also partial constants. + -- Later we may want to handle partial constants. + if !ci.isUnsafe && !ci.isPartial then + remaining := remaining.insert n + let (_, s) ← StateRefT'.run (s := { env, remaining }) do + ReaderT.run (r := { newConstants }) do + for n in remaining do + replayConstant n + checkPostponedConstructors + checkPostponedRecursors + return s.env diff --git a/src/Lean/Util/FoldConsts.lean b/src/Lean/Util/FoldConsts.lean index 044b36f30d8a..add657536399 100644 --- a/src/Lean/Util/FoldConsts.lean +++ b/src/Lean/Util/FoldConsts.lean @@ -66,8 +66,27 @@ opaque foldConsts {α : Type} (e : Expr) (init : α) (f : Name → α → α) : def getUsedConstants (e : Expr) : Array Name := e.foldConsts #[] fun c cs => cs.push c +/-- Like `Expr.getUsedConstants`, but produce a `NameSet`. -/ +def getUsedConstantsAsSet (e : Expr) : NameSet := + e.foldConsts {} fun c cs => cs.insert c + end Expr +namespace ConstantInfo + +/-- Return all names appearing in the type or value of a `ConstantInfo`. -/ +def getUsedConstantsAsSet (c : ConstantInfo) : NameSet := + c.type.getUsedConstantsAsSet ++ match c.value? with + | some v => v.getUsedConstantsAsSet + | none => match c with + | .inductInfo val => .ofList val.ctors + | .opaqueInfo val => val.value.getUsedConstantsAsSet + | .ctorInfo val => ({} : NameSet).insert val.name + | .recInfo val => .ofList val.all + | _ => {} + +end ConstantInfo + def getMaxHeight (env : Environment) (e : Expr) : UInt32 := e.foldConsts 0 fun constName max => match env.find? constName with From 115991066d8b810e4ca32243dfa9d07538ed81f3 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Wed, 11 Oct 2023 06:28:54 +0200 Subject: [PATCH 34/71] chore: remove unnecessary `partial` in `ForEachExpr.visit` (#2657) --- src/Lean/Util/ForEachExpr.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Lean/Util/ForEachExpr.lean b/src/Lean/Util/ForEachExpr.lean index d8902efe403b..fec18fcf445e 100644 --- a/src/Lean/Util/ForEachExpr.lean +++ b/src/Lean/Util/ForEachExpr.lean @@ -15,7 +15,7 @@ addresses. Note that the following code is parametric in a monad `m`. variable {ω : Type} {m : Type → Type} [STWorld ω m] [MonadLiftT (ST ω) m] [Monad m] namespace ForEachExpr -partial def visit (g : Expr → m Bool) (e : Expr) : MonadCacheT Expr Unit m Unit := +def visit (g : Expr → m Bool) (e : Expr) : MonadCacheT Expr Unit m Unit := checkCache e fun _ => do if (← g e) then match e with From 97f5ad78045e52a54d12af19d93a604ceea8092f Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Wed, 11 Oct 2023 17:59:03 +1100 Subject: [PATCH 35/71] chore: change trustCompiler axiom to True (#2662) --- src/Init/Core.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Init/Core.lean b/src/Init/Core.lean index a14aea7316ae..f9899767cf41 100644 --- a/src/Init/Core.lean +++ b/src/Init/Core.lean @@ -1615,7 +1615,7 @@ namespace Lean /-- Depends on the correctness of the Lean compiler, interpreter, and all `[implemented_by ...]` and `[extern ...]` annotations. -/ -axiom trustCompiler : False +axiom trustCompiler : True /-- When the kernel tries to reduce a term `Lean.reduceBool c`, it will invoke the Lean interpreter to evaluate `c`. From 7450a8cfa3768cf0992bfdf02686dedb5acadf91 Mon Sep 17 00:00:00 2001 From: David Christiansen Date: Tue, 10 Oct 2023 22:13:05 +0200 Subject: [PATCH 36/71] doc: describe commit conventions for update-stage0 Updates to stage0 should be their own commits. --- doc/dev/bootstrap.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/dev/bootstrap.md b/doc/dev/bootstrap.md index 3fb2ad2411d6..5ee9ff0c1875 100644 --- a/doc/dev/bootstrap.md +++ b/doc/dev/bootstrap.md @@ -69,6 +69,13 @@ Finally, when we want to use new language features in the library, we need to update the stage 0 compiler, which can be done via `make -C stageN update-stage0`. `make update-stage0` without `-C` defaults to stage1. +Updates to `stage0` should be their own commits in the Git history. In +other words, before running `make update-stage0`, please commit your +work. Then, commit the updated `stage0` compiler code with the commit message: +``` +chore: update stage0 +``` + ## Further Bootstrapping Complications As written above, changes in meta code in the current stage usually will only From 0700925bbeb86c7b883719a82241595f5f905e5c Mon Sep 17 00:00:00 2001 From: David Christiansen Date: Tue, 10 Oct 2023 22:16:29 +0200 Subject: [PATCH 37/71] doc: add a brief description of ccache --- doc/dev/index.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/dev/index.md b/doc/dev/index.md index da0befd4fd51..e6e08f13b560 100644 --- a/doc/dev/index.md +++ b/doc/dev/index.md @@ -64,3 +64,10 @@ simply by pushing a tag to your fork of the Lean 4 github repository If you push `my-tag` to a fork in your github account `my_name`, you can then put `my_name/lean4:my-tag` in your `lean-toolchain` file in a project using `lake`. (You must use a tag name that does not start with a numeral, or contain `_`). + +### `ccache` + +Lean's build process uses [`ccache`](https://ccache.dev/) if it is +installed to speed up recompilation of the generated C code. Without +`ccache`, you'll likely spend more time than necessary waiting on +rebuilds - it's a good idea to make sure it's installed. From 856a9b5153d3ad3e634b212e8418b44e81037545 Mon Sep 17 00:00:00 2001 From: Wojciech Nawrocki Date: Tue, 10 Oct 2023 18:49:29 -0400 Subject: [PATCH 38/71] fix: treat pretty-printed names as strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I initially expected `Name`s to always faithfully represent internal data, in particular that a name with macro scopes would have a form such as ```foo._@.Module._hyg.1``, and that tombstones would only appear in types that represent pretty-printed output such as as `String` or `Format`. However, that is not what happens. We have `sanitizeNames` which rewrites the `userName` field of local hypotheses to be `Name.str .anonymous "blah✝"`. Then in the server code, we put these into `names : Array Name`e. This works fine for displaying in the infoview, but if we try to deserialize an `InteractiveHypothesisBundle` inside an RPC method for widget purposes, the `FromJson Name` instance blows up in `String.toName`. I think my preferred solution is to, rather than 'fix' `String.toName` to accept these names with tombstones, stop pretending that they are actual `Name`s and re-type `InteractiveHypothesisBundle.names : Array String`. This should be a backwards-compatible change w.r.t. infoview code as the JSON representation is a string in either case. It is not backwards compatible w.r.t. meta code that uses this field. --- src/Lean/Widget/InteractiveGoal.lean | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Lean/Widget/InteractiveGoal.lean b/src/Lean/Widget/InteractiveGoal.lean index 82025d2bc08c..dff9ea4654c4 100644 --- a/src/Lean/Widget/InteractiveGoal.lean +++ b/src/Lean/Widget/InteractiveGoal.lean @@ -17,8 +17,10 @@ open Server as `h₁ h₂ : α`. We call this a 'hypothesis bundle'. We use `none` instead of `some false` for booleans to save space in the json encoding. -/ structure InteractiveHypothesisBundle where - /-- The user-friendly name for each hypothesis. -/ - names : Array Name + /-- The user-friendly name for each hypothesis. + Note that these are not `Name`s: they are pretty-printed + and do not remember the macro scopes. -/ + names : Array String /-- The ids for each variable. Should have the same length as `names`. -/ fvarIds : Array FVarId type : CodeWithInfos @@ -77,8 +79,7 @@ def InteractiveGoalCore.pretty (g : InteractiveGoalCore) (userName? : Option Str ret := addLine ret let names := hyp.names |>.toList - |>.filter (not ∘ Name.isAnonymous) - |>.map toString + |>.filter (· != toString Name.anonymous) |> " ".intercalate match names with | "" => @@ -114,7 +115,7 @@ instance : EmptyCollection InteractiveGoals := ⟨{goals := #[]}⟩ open Meta in /-- Extend an array of hypothesis bundles with another bundle. -/ def addInteractiveHypothesisBundle (hyps : Array InteractiveHypothesisBundle) - (ids : Array (Name × FVarId)) (type : Expr) (value? : Option Expr := none) : + (ids : Array (String × FVarId)) (type : Expr) (value? : Option Expr := none) : MetaM (Array InteractiveHypothesisBundle) := do if ids.size == 0 then throwError "Can only add a nonzero number of ids as an InteractiveHypothesisBundle." @@ -145,7 +146,7 @@ def goalToInteractive (mvarId : MVarId) : MetaM InteractiveGoal := do let ppImplDetailHyps := pp.implementationDetailHyps.get (← getOptions) let showLetValues := pp.showLetValues.get (← getOptions) withGoalCtx mvarId fun lctx mvarDecl => do - let pushPending (ids : Array (Name × FVarId)) (type? : Option Expr) (hyps : Array InteractiveHypothesisBundle) + let pushPending (ids : Array (String × FVarId)) (type? : Option Expr) (hyps : Array InteractiveHypothesisBundle) : MetaM (Array InteractiveHypothesisBundle) := if ids.isEmpty then pure hyps @@ -153,7 +154,7 @@ def goalToInteractive (mvarId : MVarId) : MetaM InteractiveGoal := do match type? with | none => pure hyps | some type => addInteractiveHypothesisBundle hyps ids type - let mut varNames : Array (Name × FVarId) := #[] + let mut varNames : Array (String × FVarId) := #[] let mut prevType? : Option Expr := none let mut hyps : Array InteractiveHypothesisBundle := #[] for localDecl in lctx do @@ -162,7 +163,10 @@ def goalToInteractive (mvarId : MVarId) : MetaM InteractiveGoal := do else match localDecl with | LocalDecl.cdecl _index fvarId varName type _ _ => - let varName := varName.simpMacroScopes + -- We rely on the fact that `withGoalCtx` runs `LocalContext.sanitizeNames`, + -- so the `userName`s of local hypotheses are already pretty-printed + -- and it suffices to simply `toString` them. + let varName := toString varName let type ← instantiateMVars type if prevType? == none || prevType? == some type then varNames := varNames.push (varName, fvarId) @@ -171,7 +175,7 @@ def goalToInteractive (mvarId : MVarId) : MetaM InteractiveGoal := do varNames := #[(varName, fvarId)] prevType? := some type | LocalDecl.ldecl _index fvarId varName type val _ _ => do - let varName := varName.simpMacroScopes + let varName := toString varName hyps ← pushPending varNames prevType? hyps let type ← instantiateMVars type let val? ← if showLetValues then pure (some (← instantiateMVars val)) else pure none From 14e626a925397f3bb98df071d127b5e2cd2d3b8b Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Wed, 11 Oct 2023 00:26:31 -0400 Subject: [PATCH 39/71] =?UTF-8?q?feat:=20ToMessageData=20(=CE=B1=20=C3=97?= =?UTF-8?q?=20=CE=B2)=20instance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Lean/Message.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Lean/Message.lean b/src/Lean/Message.lean index d2dc1b043485..cfb350827965 100644 --- a/src/Lean/Message.lean +++ b/src/Lean/Message.lean @@ -328,6 +328,8 @@ instance [ToMessageData α] : ToMessageData (List α) := ⟨fun as => MessageDa instance [ToMessageData α] : ToMessageData (Array α) := ⟨fun as => toMessageData as.toList⟩ instance [ToMessageData α] : ToMessageData (Subarray α) := ⟨fun as => toMessageData as.toArray.toList⟩ instance [ToMessageData α] : ToMessageData (Option α) := ⟨fun | none => "none" | some e => "some (" ++ toMessageData e ++ ")"⟩ +instance [ToMessageData α] [ToMessageData β] : ToMessageData (α × β) := + ⟨fun (a, b) => .paren <| toMessageData a ++ "," ++ Format.line ++ toMessageData b⟩ instance : ToMessageData (Option Expr) := ⟨fun | none => "" | some e => toMessageData e⟩ syntax:max "m!" interpolatedStr(term) : term From 57e23917b605d1f1e6b6ff70aa022065d55bb60c Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Mon, 9 Oct 2023 20:45:59 +1100 Subject: [PATCH 40/71] fix: implementation of Array.anyMUnsafe move test --- src/Init/Data/Array/Basic.lean | 5 +++-- tests/lean/run/1921.lean | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 tests/lean/run/1921.lean diff --git a/src/Init/Data/Array/Basic.lean b/src/Init/Data/Array/Basic.lean index dfabaef3acda..fe89ca6149bd 100644 --- a/src/Init/Data/Array/Basic.lean +++ b/src/Init/Data/Array/Basic.lean @@ -328,8 +328,9 @@ unsafe def anyMUnsafe {α : Type u} {m : Type → Type w} [Monad m] (p : α → else any (i+1) stop if start < stop then - if stop ≤ as.size then - any (USize.ofNat start) (USize.ofNat stop) + let stop' := min stop as.size + if start < stop' then + any (USize.ofNat start) (USize.ofNat stop') else pure false else diff --git a/tests/lean/run/1921.lean b/tests/lean/run/1921.lean new file mode 100644 index 000000000000..7d9868de93c2 --- /dev/null +++ b/tests/lean/run/1921.lean @@ -0,0 +1,9 @@ +@[simp] theorem Array.size_singleton : #[a].size = 1 := rfl +@[simp] theorem USize.not_size_le_one : ¬ USize.size ≤ 1 := by cases usize_size_eq <;> simp_all + +def f := #[true].any id 0 USize.size + +-- `native_decide` used to prove `false` here, due to a bug in `Array.anyMUnsafe`. +example : f = true := by native_decide + +example : f = true := by simp [f, Array.any, Array.anyM] From b558b5b91258fffd0f4bbe702ad3976ff0bc14cb Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Wed, 11 Oct 2023 20:36:28 -0400 Subject: [PATCH 41/71] perf: use quick_is_def_eq first --- src/kernel/type_checker.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kernel/type_checker.cpp b/src/kernel/type_checker.cpp index 1527ee2e4bc2..281a17a6d126 100644 --- a/src/kernel/type_checker.cpp +++ b/src/kernel/type_checker.cpp @@ -1003,6 +1003,8 @@ bool type_checker::is_def_eq_core(expr const & t, expr const & s) { check_system("is_definitionally_equal"); bool use_hash = true; lbool r = quick_is_def_eq(t, s, use_hash); + if (r != l_undef) return r == l_true; + // Very basic support for proofs by reflection. If `t` has no free variables and `s` is `Bool.true`, // we fully reduce `t` and check whether result is `s`. // TODO: add metadata to control whether this optimization is used or not. @@ -1011,7 +1013,6 @@ bool type_checker::is_def_eq_core(expr const & t, expr const & s) { return true; } } - if (r != l_undef) return r == l_true; /* Apply whnf (without using delta-reduction or normalizer extensions), *and* From 5d096c3fd88be3e4ae639d994a0317b59d9dba7d Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Thu, 12 Oct 2023 15:00:27 +1100 Subject: [PATCH 42/71] chore: make `Environment.add` private (#2642) * feat: replay constants into an Environment * suggestions from code review * chore: make Environment.add private * patch Lake to use Environment.add via extern --- src/Lean/Environment.lean | 2 +- src/lake/Lake/Load/Elab.lean | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Lean/Environment.lean b/src/Lean/Environment.lean index 59d0bbbf6509..fbd9770d1c50 100644 --- a/src/Lean/Environment.lean +++ b/src/Lean/Environment.lean @@ -851,7 +851,7 @@ private def registerNamePrefixes : Environment → Name → Environment | env, _ => env @[export lean_environment_add] -def add (env : Environment) (cinfo : ConstantInfo) : Environment := +private def add (env : Environment) (cinfo : ConstantInfo) : Environment := let env := registerNamePrefixes env cinfo.name env.addAux cinfo diff --git a/src/lake/Lake/Load/Elab.lean b/src/lake/Lake/Load/Elab.lean index 6dc3775f782a..7917bf670e33 100644 --- a/src/lake/Lake/Load/Elab.lean +++ b/src/lake/Lake/Load/Elab.lean @@ -71,6 +71,13 @@ def elabConfigFile (pkgDir : FilePath) (lakeOpts : NameMap String) else return s.commandState.env +/-- +`Lean.Environment.add` is now private, but exported as `lean_environment_add`. +We call it here via `@[extern]` with a mock implementation. +-/ +@[extern "lean_environment_add"] +private def add (env : Environment) (_ : ConstantInfo) : Environment := env + /-- Import the OLean for the configuration file if `reconfigure` is not set and an up-to-date one exists (i.e., one newer than the configuration and the @@ -99,7 +106,7 @@ def importConfigFile (wsDir pkgDir : FilePath) (lakeOpts : NameMap String) let (mod, _) ← readModuleData olean let mut env ← importModulesUsingCache mod.imports leanOpts 1024 -- Apply constants (does not go through the kernel, so order is irrelevant) - env := mod.constants.foldl (·.add) env + env := mod.constants.foldl add env -- Apply extension entries (`PersistentEnvExtension.addEntryFn` is pure and -- does not have access to the whole environment, so no dependency worries -- here either) From 6bdfde7939d57d968c5d00d14a8329d8cd7aa037 Mon Sep 17 00:00:00 2001 From: Mario Carneiro Date: Wed, 11 Oct 2023 23:08:46 -0400 Subject: [PATCH 43/71] fix: quot reduction bug --- src/kernel/quot.h | 2 +- tests/lean/run/2672.lean | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/lean/run/2672.lean diff --git a/src/kernel/quot.h b/src/kernel/quot.h index 0c4714385052..ddfd269ff97b 100644 --- a/src/kernel/quot.h +++ b/src/kernel/quot.h @@ -58,7 +58,7 @@ template optional quot_reduce_rec(expr const & e, WHNF cons expr mk = whnf(args[mk_pos]); expr const & mk_fn = get_app_fn(mk); - if (!is_constant(mk_fn) || const_name(mk_fn) != *quot_consts::g_quot_mk) + if (!is_constant(mk_fn) || const_name(mk_fn) != *quot_consts::g_quot_mk || get_app_num_args(mk) != 3) return none_expr(); expr const & f = args[arg_pos]; diff --git a/tests/lean/run/2672.lean b/tests/lean/run/2672.lean new file mode 100644 index 000000000000..5995644624d4 --- /dev/null +++ b/tests/lean/run/2672.lean @@ -0,0 +1,13 @@ +import Lean +open Lean Elab Term + +elab "foo" t:term "," s:term : term => do + let e ← Elab.Term.elabTermAndSynthesize t none + let e2 ← Elab.Term.elabTermAndSynthesize s none + let t ← ofExceptKernelException (Kernel.whnf (← getEnv) (← getLCtx) (.app e e2)) + println! t + return e + +variable {α : Sort u} {r : α → α → Prop} {β : Sort v} (f : α → β) + (H : ∀ (a b : α), r a b → f a = f b) +example := foo @Quot.lift.{u, v} α r β f H, @Quot.mk.{u} From 99b78bcc23d759ed9af55a3cccae15da51c0730b Mon Sep 17 00:00:00 2001 From: tydeu Date: Thu, 14 Sep 2023 14:26:22 -0400 Subject: [PATCH 44/71] fix: `stdin := .null` in `IO.Process.output` --- RELEASES.md | 1 + src/Init/System/IO.lean | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index a4287e9d6d26..215a8a044613 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,6 +10,7 @@ Please check the [releases](https://github.com/leanprover/lean4/releases) page f v4.3.0 (development in progress) --------- +* `IO.Process.output` no longer inherits the standard input of the caller. * The derive handler for `DecidableEq` [now handles](https://github.com/leanprover/lean4/pull/2591) mutual inductive types. * [Show path of failed import in Lake](https://github.com/leanprover/lean4/pull/2616). * [Fix linker warnings on macOS](https://github.com/leanprover/lean4/pull/2598). diff --git a/src/Init/System/IO.lean b/src/Init/System/IO.lean index fedc48dcd0d3..a204c1147fc2 100644 --- a/src/Init/System/IO.lean +++ b/src/Init/System/IO.lean @@ -638,9 +638,12 @@ structure Output where stdout : String stderr : String -/-- Run process to completion and capture output. -/ +/-- +Run process to completion and capture output. +The process does not inherit the standard input of the caller. +-/ def output (args : SpawnArgs) : IO Output := do - let child ← spawn { args with stdout := Stdio.piped, stderr := Stdio.piped } + let child ← spawn { args with stdout := .piped, stderr := .piped, stdin := .null } let stdout ← IO.asTask child.stdout.readToEnd Task.Priority.dedicated let stderr ← child.stderr.readToEnd let exitCode ← child.wait From 275af93904a17e6310550372bfb6feab22aafeb4 Mon Sep 17 00:00:00 2001 From: tydeu Date: Thu, 12 Oct 2023 15:33:22 -0400 Subject: [PATCH 45/71] test: lake: show module with failed import --- src/lake/Lake/Build/Module.lean | 5 ++--- src/lake/tests/badImport/.gitignore | 1 + src/lake/tests/badImport/Lib/A.lean | 1 + src/lake/tests/badImport/Lib/B.lean | 1 + src/lake/tests/badImport/X.lean | 1 + src/lake/tests/badImport/clean.sh | 1 + src/lake/tests/badImport/lakefile.lean | 7 +++++++ src/lake/tests/badImport/test.sh | 14 ++++++++++++++ 8 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/lake/tests/badImport/.gitignore create mode 100644 src/lake/tests/badImport/Lib/A.lean create mode 100644 src/lake/tests/badImport/Lib/B.lean create mode 100644 src/lake/tests/badImport/X.lean create mode 100755 src/lake/tests/badImport/clean.sh create mode 100644 src/lake/tests/badImport/lakefile.lean create mode 100755 src/lake/tests/badImport/test.sh diff --git a/src/lake/Lake/Build/Module.lean b/src/lake/Lake/Build/Module.lean index ee4444b9bc9a..6eeace9f02af 100644 --- a/src/lake/Lake/Build/Module.lean +++ b/src/lake/Lake/Build/Module.lean @@ -60,7 +60,7 @@ building an `Array` product of its direct local imports. -/ def Module.recParseImports (mod : Module) : IndexBuildM (Array Module) := do let callstack : CallStack BuildKey ← EquipT.lift <| CycleT.readCallStack - let contents ← liftM <| tryCatch (IO.FS.readFile mod.leanFile) (fun err => + let contents ← liftM <| tryCatch (IO.FS.readFile mod.leanFile) fun err => -- filter out only modules from build key, and remove adjacent duplicates (squeeze), -- since Lake visits multiple nested facets of the same module. let callstack := callstack.filterMap (fun bk => @@ -69,8 +69,7 @@ def Module.recParseImports (mod : Module) : IndexBuildM (Array Module) := do | _ => .none ) |> List.squeeze let breadcrumb := String.intercalate " ▸ " callstack.reverse - throw <| IO.userError s!"({breadcrumb}): {err}" - ) + error s!"{breadcrumb}: {err}" let imports ← Lean.parseImports' contents mod.leanFile.toString let mods ← imports.foldlM (init := OrdModuleSet.empty) fun set imp => findModule? imp.module <&> fun | some mod => set.insert mod | none => set diff --git a/src/lake/tests/badImport/.gitignore b/src/lake/tests/badImport/.gitignore new file mode 100644 index 000000000000..b96c2ef5482d --- /dev/null +++ b/src/lake/tests/badImport/.gitignore @@ -0,0 +1 @@ +lakefile.olean diff --git a/src/lake/tests/badImport/Lib/A.lean b/src/lake/tests/badImport/Lib/A.lean new file mode 100644 index 000000000000..895a99b39af5 --- /dev/null +++ b/src/lake/tests/badImport/Lib/A.lean @@ -0,0 +1 @@ +import Lib.A diff --git a/src/lake/tests/badImport/Lib/B.lean b/src/lake/tests/badImport/Lib/B.lean new file mode 100644 index 000000000000..49a93768683e --- /dev/null +++ b/src/lake/tests/badImport/Lib/B.lean @@ -0,0 +1 @@ +import Lib.C diff --git a/src/lake/tests/badImport/X.lean b/src/lake/tests/badImport/X.lean new file mode 100644 index 000000000000..2bfb39bdb50e --- /dev/null +++ b/src/lake/tests/badImport/X.lean @@ -0,0 +1 @@ +import Y diff --git a/src/lake/tests/badImport/clean.sh b/src/lake/tests/badImport/clean.sh new file mode 100755 index 000000000000..e30197eeaf9b --- /dev/null +++ b/src/lake/tests/badImport/clean.sh @@ -0,0 +1 @@ +rm -f lakefile.olean diff --git a/src/lake/tests/badImport/lakefile.lean b/src/lake/tests/badImport/lakefile.lean new file mode 100644 index 000000000000..de8ad6ea316c --- /dev/null +++ b/src/lake/tests/badImport/lakefile.lean @@ -0,0 +1,7 @@ +import Lake +open Lake DSL + +package test + +lean_lib X +lean_lib Lib diff --git a/src/lake/tests/badImport/test.sh b/src/lake/tests/badImport/test.sh new file mode 100755 index 000000000000..8c02a8a48bb9 --- /dev/null +++ b/src/lake/tests/badImport/test.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euxo pipefail + +LAKE=${LAKE:-../../build/bin/lake} + +./clean.sh + +# Test that failed imports show the module that imported them +# https://github.com/leanprover/lake/issues/25 +# https://github.com/leanprover/lean4/issues/2569 +# https://github.com/leanprover/lean4/issues/2415 + +($LAKE build +X 2>&1 && exit 1 || true) | grep -F "X.lean" +($LAKE print-paths Lib.B 2>&1 && exit 1 || true) | grep -F "Lib.B" From 42802f9788a8089ef93baf318f37360adb9fbd4e Mon Sep 17 00:00:00 2001 From: tydeu Date: Fri, 29 Sep 2023 11:19:25 -0400 Subject: [PATCH 46/71] feat: lake: `postUpdate?` + test --- RELEASES.md | 1 + src/lake/Lake/Config/Package.lean | 30 ++++++ src/lake/Lake/Load/Main.lean | 108 ++++++++++---------- src/lake/README.md | 1 + src/lake/tests/postUpdate/.gitignore | 3 + src/lake/tests/postUpdate/clean.sh | 2 + src/lake/tests/postUpdate/dep/hello.lean | 2 + src/lake/tests/postUpdate/dep/lakefile.lean | 18 ++++ src/lake/tests/postUpdate/lakefile.lean | 5 + src/lake/tests/postUpdate/test.sh | 16 +++ 10 files changed, 134 insertions(+), 52 deletions(-) create mode 100644 src/lake/tests/postUpdate/.gitignore create mode 100755 src/lake/tests/postUpdate/clean.sh create mode 100644 src/lake/tests/postUpdate/dep/hello.lean create mode 100644 src/lake/tests/postUpdate/dep/lakefile.lean create mode 100644 src/lake/tests/postUpdate/lakefile.lean create mode 100755 src/lake/tests/postUpdate/test.sh diff --git a/RELEASES.md b/RELEASES.md index 215a8a044613..cd8413ed31dd 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -14,6 +14,7 @@ v4.3.0 (development in progress) * The derive handler for `DecidableEq` [now handles](https://github.com/leanprover/lean4/pull/2591) mutual inductive types. * [Show path of failed import in Lake](https://github.com/leanprover/lean4/pull/2616). * [Fix linker warnings on macOS](https://github.com/leanprover/lean4/pull/2598). +* **Lake:** Add `postUpdate?` package configuration option. Used by a package to specify some code which should be run after a successful `lake update` of the package or one of its downstream dependencies. ([lake#185](https://github.com/leanprover/lake/issues/185)) v4.2.0 --------- diff --git a/src/lake/Lake/Config/Package.lean b/src/lake/Lake/Config/Package.lean index a387bba7f266..825e4c010342 100644 --- a/src/lake/Lake/Config/Package.lean +++ b/src/lake/Lake/Config/Package.lean @@ -90,6 +90,32 @@ structure PackageConfig extends WorkspaceConfig, LeanConfig where /-- An `Array` of target names to build whenever the package is used. -/ extraDepTargets : Array Name := #[] + /-- + A post-`lake update` hook. The monadic action is run after a successful + `lake update` execution on this package or one of its downstream dependents. + Defaults to `none`. + + As an example, Mathlib can use this feature to synchronize the Lean toolchain + and run `cache get`: + + ``` + package mathlib where + postUpdate? := some do + let some pkg ← findPackage? `mathlib + | error "mathlib is missing from workspace" + let wsToolchainFile := (← getRootPackage).dir / "lean-toolchain" + let mathlibToolchain ← IO.FS.readFile <| pkg.dir / "lean-toolchain" + IO.FS.writeFile wsToolchainFile mathlibToolchain + let some exe := pkg.findLeanExe? `cache + | error s!"{pkg.name}: cache is missing from the package" + let exeFile ← runBuild (exe.build >>= (·.await)) + let exitCode ← env exeFile.toString #["get"] + if exitCode ≠ 0 then + error s!"{pkg.name}: failed to fetch cache" + ``` + -/ + postUpdate? : Option (LakeT LogIO PUnit) := none + /-- Whether to compile each of the package's module into a native shared library that is loaded whenever the module is imported. This speeds up evaluation of @@ -263,6 +289,10 @@ namespace Package @[inline] def extraDepTargets (self : Package) : Array Name := self.config.extraDepTargets +/-- The package's `postUpdate?` configuration. -/ +@[inline] def postUpdate? (self : Package) := + self.config.postUpdate? + /-- The package's `releaseRepo?` configuration. -/ @[inline] def releaseRepo? (self : Package) : Option String := self.config.releaseRepo? diff --git a/src/lake/Lake/Load/Main.lean b/src/lake/Lake/Load/Main.lean index ee34a8f363c7..bdb743867565 100644 --- a/src/lake/Lake/Load/Main.lean +++ b/src/lake/Lake/Load/Main.lean @@ -40,6 +40,50 @@ def loadDepPackage (wsDir : FilePath) (dep : MaterializedDep) remoteUrl? := dep.remoteUrl? } +/-- +Load a `Workspace` for a Lake package by elaborating its configuration file. +Does not resolve dependencies. +-/ +def loadWorkspaceRoot (config : LoadConfig) : LogIO Workspace := do + Lean.searchPathRef.set config.env.leanSearchPath + let configEnv ← importConfigFile config.rootDir config.rootDir + config.configOpts config.leanOpts config.configFile config.reconfigure + let pkgConfig ← IO.ofExcept <| PackageConfig.loadFromEnv configEnv config.leanOpts + let root := { + configEnv, leanOpts := config.leanOpts + dir := config.rootDir, config := pkgConfig + } + return { + root, lakeEnv := config.env + moduleFacetConfigs := initModuleFacetConfigs + packageFacetConfigs := initPackageFacetConfigs + libraryFacetConfigs := initLibraryFacetConfigs + } + +/-- +Finalize the workspace's root and its transitive dependencies +and add them to the workspace. +-/ +def Workspace.finalize (ws : Workspace) : LogIO Workspace := do + have : MonadStore Name Package (StateT Workspace LogIO) := { + fetch? := fun name => return (← get).findPackage? name + store := fun _ pkg => modify (·.addPackage pkg) + } + let (res, ws) ← EStateT.run ws do + buildTop (·.name) ws.root fun pkg load => do + let depPkgs ← pkg.deps.mapM load + set <| ← IO.ofExcept <| (← get).addFacetsFromEnv pkg.configEnv pkg.leanOpts + let pkg ← pkg.finalize depPkgs + return pkg + match res with + | Except.ok root => + return {ws with root} + | Except.error cycle => do + let cycle := cycle.map (s!" {·}") + error <| + s!"oops! dependency load cycle detected (this likely indicates a bug in Lake):\n" ++ + "\n".intercalate cycle + /-- Rebuild the workspace's Lake manifest and materialize missing dependencies. @@ -51,7 +95,7 @@ root dependencies. Otherwise, only update the root dependencies specified. If `reconfigure`, elaborate configuration files while updating, do not use OLeans. -/ def buildUpdatedManifest (ws : Workspace) -(toUpdate : NameSet := {}) (reconfigure := true) : LogIO (Workspace × Manifest) := do +(toUpdate : NameSet := {}) (reconfigure := true) : LogIO Workspace := do let res ← StateT.run (s := mkOrdNameMap MaterializedDep) <| EStateT.run' (mkNameMap Package) do -- Use manifest versions of root packages that should not be updated unless toUpdate.isEmpty do @@ -86,57 +130,19 @@ def buildUpdatedManifest (ws : Workspace) return {pkg with opaqueDeps := ← deps.mapM (.mk <$> resolve ·)} match res with | (.ok root, deps) => + let ws : Workspace ← {ws with root}.finalize + LakeT.run ⟨ws⟩ <| ws.packages.forM fun pkg => do + if let some postUpdate := pkg.postUpdate? then + logInfo s!"{pkg.name}: running post-update hook" + postUpdate let manifest : Manifest := {name? := ws.root.name, packagesDir? := ws.relPkgsDir} - let manifest := deps.foldl (fun m d => m.addPackage d.manifestEntry) manifest - return ({ws with root}, manifest) + let manifest := deps.foldl (·.addPackage ·.manifestEntry) manifest + manifest.saveToFile ws.manifestFile + return ws | (.error cycle, _) => let cycle := cycle.map (s!" {·}") error s!"dependency cycle detected:\n{"\n".intercalate cycle}" -/-- -Load a `Workspace` for a Lake package by elaborating its configuration file. -Does not resolve dependencies. --/ -def loadWorkspaceRoot (config : LoadConfig) : LogIO Workspace := do - Lean.searchPathRef.set config.env.leanSearchPath - let configEnv ← importConfigFile config.rootDir config.rootDir - config.configOpts config.leanOpts config.configFile config.reconfigure - let pkgConfig ← IO.ofExcept <| PackageConfig.loadFromEnv configEnv config.leanOpts - let root := { - configEnv, leanOpts := config.leanOpts - dir := config.rootDir, config := pkgConfig - } - return { - root, lakeEnv := config.env - moduleFacetConfigs := initModuleFacetConfigs - packageFacetConfigs := initPackageFacetConfigs - libraryFacetConfigs := initLibraryFacetConfigs - } - -/-- -Finalize the workspace's root and its transitive dependencies -and add them to the workspace. --/ -def Workspace.finalize (ws : Workspace) : LogIO Workspace := do - have : MonadStore Name Package (StateT Workspace LogIO) := { - fetch? := fun name => return (← get).findPackage? name - store := fun _ pkg => modify (·.addPackage pkg) - } - let (res, ws) ← EStateT.run ws do - buildTop (·.name) ws.root fun pkg load => do - let depPkgs ← pkg.deps.mapM load - set <| ← IO.ofExcept <| (← get).addFacetsFromEnv pkg.configEnv pkg.leanOpts - let pkg ← pkg.finalize depPkgs - return pkg - match res with - | Except.ok root => - return {ws with root} - | Except.error cycle => do - let cycle := cycle.map (s!" {·}") - error <| - s!"oops! dependency load cycle detected (this likely indicates a bug in Lake):\n" ++ - "\n".intercalate cycle - /-- Resolving a workspace's dependencies using a manifest, downloading and/or updating them as necessary. @@ -200,9 +206,7 @@ def loadWorkspace (config : LoadConfig) (updateDeps := false) : LogIO Workspace let rc := config.reconfigure let ws ← loadWorkspaceRoot config if updateDeps then - let (ws, manifest) ← buildUpdatedManifest ws {} rc - manifest.saveToFile ws.manifestFile - ws.finalize + buildUpdatedManifest ws {} rc else ws.materializeDeps (← Manifest.loadOrEmpty ws.manifestFile) rc @@ -210,5 +214,5 @@ def loadWorkspace (config : LoadConfig) (updateDeps := false) : LogIO Workspace def updateManifest (config : LoadConfig) (toUpdate : NameSet := {}) : LogIO Unit := do let rc := config.reconfigure let ws ← loadWorkspaceRoot config - let (ws, manifest) ← buildUpdatedManifest ws toUpdate rc - manifest.saveToFile ws.manifestFile + discard <| buildUpdatedManifest ws toUpdate rc + diff --git a/src/lake/README.md b/src/lake/README.md index 74c4af06e02f..b0aed5b62bdf 100644 --- a/src/lake/README.md +++ b/src/lake/README.md @@ -164,6 +164,7 @@ Lake provides a large assortment of configuration options for packages. ### Build & Run +* `postUpdate?`: A post-`lake update` hook. The monadic action is run after a successful `lake update` execution on this package or one of its downstream dependents. Defaults to `none`. See the option's docstring for a complete example. * `precompileModules`: Whether to compile each module into a native shared library that is loaded whenever the module is imported. This speeds up the evaluation of metaprograms and enables the interpreter to run functions marked `@[extern]`. Defaults to `false`. * `moreServerArgs`: Additional arguments to pass to the Lean language server (i.e., `lean --server`) launched by `lake serve`. * `buildType`: The `BuildType` of targets in the package (see [`CMAKE_BUILD_TYPE`](https://stackoverflow.com/a/59314670)). One of `debug`, `relWithDebInfo`, `minSizeRel`, or `release`. Defaults to `release`. diff --git a/src/lake/tests/postUpdate/.gitignore b/src/lake/tests/postUpdate/.gitignore new file mode 100644 index 000000000000..01d08f365a86 --- /dev/null +++ b/src/lake/tests/postUpdate/.gitignore @@ -0,0 +1,3 @@ +lakefile.olean +lake-manifest.json +toolchain diff --git a/src/lake/tests/postUpdate/clean.sh b/src/lake/tests/postUpdate/clean.sh new file mode 100755 index 000000000000..bc1bcab717ca --- /dev/null +++ b/src/lake/tests/postUpdate/clean.sh @@ -0,0 +1,2 @@ +rm -rf dep/build dep/lakefile.olean dep/toolchain +rm -f lake-manifest.json lakefile.olean toolchain diff --git a/src/lake/tests/postUpdate/dep/hello.lean b/src/lake/tests/postUpdate/dep/hello.lean new file mode 100644 index 000000000000..314d66b2e751 --- /dev/null +++ b/src/lake/tests/postUpdate/dep/hello.lean @@ -0,0 +1,2 @@ +def main (args : List String) : IO Unit := do + IO.println s!"post-update hello w/ arguments: {args}" diff --git a/src/lake/tests/postUpdate/dep/lakefile.lean b/src/lake/tests/postUpdate/dep/lakefile.lean new file mode 100644 index 000000000000..96430764a369 --- /dev/null +++ b/src/lake/tests/postUpdate/dep/lakefile.lean @@ -0,0 +1,18 @@ +import Lake +open Lake DSL + +package dep where + postUpdate? := some do + let some pkg ← findPackage? `dep + | error "dep is missing from workspace" + let wsToolchainFile := (← getRootPackage).dir / "toolchain" + let depToolchain ← IO.FS.readFile <| pkg.dir / "toolchain" + IO.FS.writeFile wsToolchainFile depToolchain + let some exe := pkg.findLeanExe? `hello + | error s!"{pkg.name}: hello is missing from the package" + let exeFile ← runBuild (exe.build >>= (·.await)) + let exitCode ← env exeFile.toString #["get"] + if exitCode ≠ 0 then + error s!"{pkg.name}: failed to fetch hello" + +lean_exe hello diff --git a/src/lake/tests/postUpdate/lakefile.lean b/src/lake/tests/postUpdate/lakefile.lean new file mode 100644 index 000000000000..8a0940dfdc52 --- /dev/null +++ b/src/lake/tests/postUpdate/lakefile.lean @@ -0,0 +1,5 @@ +import Lake +open Lake DSL + +package test +require dep from "dep" diff --git a/src/lake/tests/postUpdate/test.sh b/src/lake/tests/postUpdate/test.sh new file mode 100755 index 000000000000..e5d31b140b3b --- /dev/null +++ b/src/lake/tests/postUpdate/test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euxo pipefail + +LAKE=${LAKE:-../../build/bin/lake} + +./clean.sh + +# Test the `postUpdate?` configuration option and the docstring example. +# If the Lake API experiences changes, this test and the docstring should be +# updated in tandem. + +echo "root" > toolchain +echo "dep" > dep/toolchain +$LAKE update | grep -F "post-update hello w/ arguments: [get]" +test "`cat toolchain`" = dep + From bf48a18cf9d4d1be2063a2af091520756a992156 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Fri, 6 Oct 2023 16:11:41 +0200 Subject: [PATCH 47/71] feat: move `check_interrupted` from unused thread class to `Task` cancellation --- src/runtime/interrupt.cpp | 24 ++------------------- src/runtime/interrupt.h | 44 +-------------------------------------- 2 files changed, 3 insertions(+), 65 deletions(-) diff --git a/src/runtime/interrupt.cpp b/src/runtime/interrupt.cpp index f3bbb2d4210c..85503e985e0a 100644 --- a/src/runtime/interrupt.cpp +++ b/src/runtime/interrupt.cpp @@ -9,6 +9,7 @@ Author: Leonardo de Moura #include "runtime/interrupt.h" #include "runtime/exception.h" #include "runtime/memory.h" +#include "lean/lean.h" namespace lean { LEAN_THREAD_VALUE(size_t, g_max_heartbeat, 0); @@ -38,16 +39,8 @@ void check_heartbeat() { throw_heartbeat_exception(); } -LEAN_THREAD_VALUE(atomic_bool *, g_interrupt_flag, nullptr); - -scoped_interrupt_flag::scoped_interrupt_flag(atomic_bool * flag) : flet(g_interrupt_flag, flag) {} - -static bool interrupt_requested() { - return g_interrupt_flag && g_interrupt_flag->load(); -} - void check_interrupted() { - if (interrupt_requested() && !std::uncaught_exception()) { + if (lean_io_check_canceled_core() && !std::uncaught_exception()) { throw interrupted(); } } @@ -72,17 +65,4 @@ void sleep_for(unsigned ms, unsigned step_ms) { this_thread::sleep_for(r); check_interrupted(); } - -bool interruptible_thread::interrupted() const { - return m_flag.load(); -} - -void interruptible_thread::request_interrupt() { - m_flag.store(true); -} - -void interruptible_thread::join() { - m_thread.join(); -} - } diff --git a/src/runtime/interrupt.h b/src/runtime/interrupt.h index a01a5394048c..f24868e314bb 100644 --- a/src/runtime/interrupt.h +++ b/src/runtime/interrupt.h @@ -42,12 +42,8 @@ class scope_max_heartbeat : flet { void check_heartbeat(); -struct scoped_interrupt_flag : flet { - scoped_interrupt_flag(atomic_bool *); // NOLINT -}; - /** - \brief Throw an interrupted exception if the (interrupt) flag is set. + \brief Throw an interrupted exception if the current task is marked cancelled. */ void check_interrupted(); @@ -65,42 +61,4 @@ constexpr unsigned g_small_sleep = 10; */ void sleep_for(unsigned ms, unsigned step_ms = g_small_sleep); inline void sleep_for(chrono::milliseconds const & ms) { sleep_for(ms.count(), 10); } - -/** - \brief Thread that provides a method for setting its interrupt flag. -*/ -class interruptible_thread { -public: - template - interruptible_thread(Function && fun): - m_thread([&, fun]() { - save_stack_info(false); - scoped_interrupt_flag scope_int_flag(&m_flag); - fun(); - }) - {} - - /** - \brief Return true iff an interrupt request has been made to the current thread. - */ - bool interrupted() const; - /** - \brief Send a interrupt request to the current thread. Return - true iff the request has been successfully performed. - */ - void request_interrupt(); - - void join(); -private: - atomic_bool m_flag; - lthread m_thread; -}; - -#if !defined(LEAN_MULTI_THREAD) -inline void check_threadsafe() { - throw exception("Lean was compiled without support for multi-threading"); -} -#else -inline void check_threadsafe() {} -#endif } From 2070df2328397abd3552e2e44f33d6e4c20afac7 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Fri, 6 Oct 2023 16:51:16 +0200 Subject: [PATCH 48/71] feat: check task cancellation in elaborator --- src/Lean/CoreM.lean | 12 +++++++++++- src/Lean/Elab/Do.lean | 2 +- src/Lean/Elab/Term.lean | 2 +- src/Lean/Meta/ExprDefEq.lean | 2 +- src/Lean/Meta/SynthInstance.lean | 5 +++-- src/Lean/Meta/Tactic/Simp/Main.lean | 2 +- src/Lean/Meta/WHNF.lean | 2 +- src/Lean/PrettyPrinter/Delaborator/Basic.lean | 2 +- .../PrettyPrinter/Delaborator/TopDownAnalyze.lean | 2 +- 9 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/Lean/CoreM.lean b/src/Lean/CoreM.lean index c38191e82f38..2b87d66d8ec1 100644 --- a/src/Lean/CoreM.lean +++ b/src/Lean/CoreM.lean @@ -199,6 +199,11 @@ instance [MetaEval α] : MetaEval (CoreM α) where protected def withIncRecDepth [Monad m] [MonadControlT CoreM m] (x : m α) : m α := controlAt CoreM fun runInBase => withIncRecDepth (runInBase x) +def checkInterrupted : CoreM Unit := do + if (← IO.checkCanceled) then + -- should never be visible to users! + throw <| Exception.error .missing "elaboration interrupted" + def throwMaxHeartbeat (moduleName : Name) (optionName : Name) (max : Nat) : CoreM Unit := do let msg := s!"(deterministic) timeout at '{moduleName}', maximum number of heartbeats ({max/1000}) has been reached (use 'set_option {optionName} ' to set the limit)" throw <| Exception.error (← getRef) (MessageData.ofFormat (Std.Format.text msg)) @@ -212,6 +217,11 @@ def checkMaxHeartbeatsCore (moduleName : String) (optionName : Name) (max : Nat) def checkMaxHeartbeats (moduleName : String) : CoreM Unit := do checkMaxHeartbeatsCore moduleName `maxHeartbeats (← read).maxHeartbeats +def checkSystem (moduleName : String) : CoreM Unit := do + -- TODO: bring back more checks from the C++ implementation + checkInterrupted + checkMaxHeartbeats moduleName + private def withCurrHeartbeatsImp (x : CoreM α) : CoreM α := do let heartbeats ← IO.getNumHeartbeats withReader (fun ctx => { ctx with initHeartbeats := heartbeats }) x @@ -240,7 +250,7 @@ instance : MonadLog CoreM where end Core -export Core (CoreM mkFreshUserName checkMaxHeartbeats withCurrHeartbeats) +export Core (CoreM mkFreshUserName checkSystem withCurrHeartbeats) @[inline] def withAtLeastMaxRecDepth [MonadFunctorT CoreM m] (max : Nat) : m α → m α := monadMap (m := CoreM) <| withReader (fun ctx => { ctx with maxRecDepth := Nat.max max ctx.maxRecDepth }) diff --git a/src/Lean/Elab/Do.lean b/src/Lean/Elab/Do.lean index 386522349890..85392b5d38d8 100644 --- a/src/Lean/Elab/Do.lean +++ b/src/Lean/Elab/Do.lean @@ -1595,7 +1595,7 @@ mutual partial def doSeqToCode : List Syntax → M CodeBlock | [] => do liftMacroM mkPureUnitAction | doElem::doElems => withIncRecDepth <| withRef doElem do - checkMaxHeartbeats "`do`-expander" + checkSystem "`do`-expander" match (← liftMacroM <| expandMacro? doElem) with | some doElem => doSeqToCode (doElem::doElems) | none => diff --git a/src/Lean/Elab/Term.lean b/src/Lean/Elab/Term.lean index e2d699aa316a..778d599a8a22 100644 --- a/src/Lean/Elab/Term.lean +++ b/src/Lean/Elab/Term.lean @@ -1354,7 +1354,7 @@ private partial def elabTermAux (expectedType? : Option Expr) (catchExPostpone : | .missing => mkSyntheticSorryFor expectedType? | stx => withFreshMacroScope <| withIncRecDepth do withTraceNode `Elab.step (fun _ => return m!"expected type: {expectedType?}, term\n{stx}") do - checkMaxHeartbeats "elaborator" + checkSystem "elaborator" let env ← getEnv let result ← match (← liftMacroM (expandMacroImpl? env stx)) with | some (decl, stxNew?) => diff --git a/src/Lean/Meta/ExprDefEq.lean b/src/Lean/Meta/ExprDefEq.lean index e1224b5d9e43..44cdc5014150 100644 --- a/src/Lean/Meta/ExprDefEq.lean +++ b/src/Lean/Meta/ExprDefEq.lean @@ -1812,7 +1812,7 @@ private def cacheResult (key : Expr × Expr) (result : Bool) : MetaM Unit := do @[export lean_is_expr_def_eq] partial def isExprDefEqAuxImpl (t : Expr) (s : Expr) : MetaM Bool := withIncRecDepth do withTraceNodeBefore `Meta.isDefEq (return m!"{t} =?= {s}") do - checkMaxHeartbeats "isDefEq" + checkSystem "isDefEq" whenUndefDo (isDefEqQuick t s) do whenUndefDo (isDefEqProofIrrel t s) do /- diff --git a/src/Lean/Meta/SynthInstance.lean b/src/Lean/Meta/SynthInstance.lean index 15f2bcc61acb..0a315f985ff8 100644 --- a/src/Lean/Meta/SynthInstance.lean +++ b/src/Lean/Meta/SynthInstance.lean @@ -175,7 +175,8 @@ structure State where abbrev SynthM := ReaderT Context $ StateRefT State MetaM -def checkMaxHeartbeats : SynthM Unit := do +def checkSystem : SynthM Unit := do + Core.checkInterrupted Core.checkMaxHeartbeatsCore "typeclass" `synthInstance.maxHeartbeats (← read).maxHeartbeats @[inline] def mapMetaM (f : forall {α}, MetaM α → MetaM α) {α} : SynthM α → SynthM α := @@ -552,7 +553,7 @@ def resume : SynthM Unit := do consume { key := cNode.key, mvar := cNode.mvar, subgoals := rest, mctx, size := cNode.size + answer.size } def step : SynthM Bool := do - checkMaxHeartbeats + checkSystem let s ← get if !s.resumeStack.isEmpty then resume diff --git a/src/Lean/Meta/Tactic/Simp/Main.lean b/src/Lean/Meta/Tactic/Simp/Main.lean index 4fca5307a049..08c1c03a89f1 100644 --- a/src/Lean/Meta/Tactic/Simp/Main.lean +++ b/src/Lean/Meta/Tactic/Simp/Main.lean @@ -268,7 +268,7 @@ where e partial def simp (e : Expr) : M Result := withIncRecDepth do - checkMaxHeartbeats "simp" + checkSystem "simp" let cfg ← getConfig if (← isProof e) then return { expr := e } diff --git a/src/Lean/Meta/WHNF.lean b/src/Lean/Meta/WHNF.lean index cc9159aaf093..5ae44c8acec9 100644 --- a/src/Lean/Meta/WHNF.lean +++ b/src/Lean/Meta/WHNF.lean @@ -861,7 +861,7 @@ private def cache (useCache : Bool) (e r : Expr) : MetaM Expr := do @[export lean_whnf] partial def whnfImp (e : Expr) : MetaM Expr := withIncRecDepth <| whnfEasyCases e fun e => do - checkMaxHeartbeats "whnf" + checkSystem "whnf" let useCache ← useWHNFCache e match (← cached? useCache e) with | some e' => pure e' diff --git a/src/Lean/PrettyPrinter/Delaborator/Basic.lean b/src/Lean/PrettyPrinter/Delaborator/Basic.lean index 2e1ebeb6ada3..f557f93e9836 100644 --- a/src/Lean/PrettyPrinter/Delaborator/Basic.lean +++ b/src/Lean/PrettyPrinter/Delaborator/Basic.lean @@ -240,7 +240,7 @@ partial def delabFor : Name → Delab <|> if k.isAtomic then failure else delabFor k.getRoot partial def delab : Delab := do - checkMaxHeartbeats "delab" + checkSystem "delab" let e ← getExpr -- no need to hide atomic proofs diff --git a/src/Lean/PrettyPrinter/Delaborator/TopDownAnalyze.lean b/src/Lean/PrettyPrinter/Delaborator/TopDownAnalyze.lean index ee89be8e3080..c62292de3a18 100644 --- a/src/Lean/PrettyPrinter/Delaborator/TopDownAnalyze.lean +++ b/src/Lean/PrettyPrinter/Delaborator/TopDownAnalyze.lean @@ -351,7 +351,7 @@ abbrev AnalyzeAppM := ReaderT App.Context (StateT App.State AnalyzeM) mutual partial def analyze (parentIsApp : Bool := false) : AnalyzeM Unit := do - checkMaxHeartbeats "Delaborator.topDownAnalyze" + checkSystem "Delaborator.topDownAnalyze" trace[pp.analyze] "{(← read).knowsType}.{(← read).knowsLevel}" let e ← getExpr let opts ← getOptions From 14c640c15e30c19c3c196afe38347b278ff34b13 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Tue, 10 Oct 2023 17:26:54 +0200 Subject: [PATCH 49/71] feat: translate `interrupted` kernel exception --- src/Lean/Environment.lean | 1 + src/Lean/Message.lean | 1 + src/kernel/kernel_exception.h | 19 ++++--------------- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/Lean/Environment.lean b/src/Lean/Environment.lean index fbd9770d1c50..9bb59cb8701f 100644 --- a/src/Lean/Environment.lean +++ b/src/Lean/Environment.lean @@ -230,6 +230,7 @@ inductive KernelException where | deterministicTimeout | excessiveMemory | deepRecursion + | interrupted namespace Environment diff --git a/src/Lean/Message.lean b/src/Lean/Message.lean index cfb350827965..459873e4d28b 100644 --- a/src/Lean/Message.lean +++ b/src/Lean/Message.lean @@ -370,6 +370,7 @@ def toMessageData (e : KernelException) (opts : Options) : MessageData := | deterministicTimeout => "(kernel) deterministic timeout" | excessiveMemory => "(kernel) excessive memory consumption detected" | deepRecursion => "(kernel) deep recursion detected" + | interrupted => "(kernel) interrupted" end KernelException end Lean diff --git a/src/kernel/kernel_exception.h b/src/kernel/kernel_exception.h index f5d66133eee5..930185828fbd 100644 --- a/src/kernel/kernel_exception.h +++ b/src/kernel/kernel_exception.h @@ -7,6 +7,7 @@ Author: Leonardo de Moura #pragma once #include "kernel/environment.h" #include "kernel/local_ctx.h" +#include "runtime/interrupt.h" namespace lean { /** \brief Base class for all kernel exceptions. */ @@ -145,21 +146,6 @@ an `kernel_exception` or `exception`. Then, convert result into `Except KernelEx where `T` is the type of the lean objected represented by `A`. We use the constructor `KernelException.other ` to handle C++ `exception` objects which are not `kernel_exception`. -``` -inductive KernelException -0 | unknownConstant (env : Environment) (name : Name) -1 | alreadyDeclared (env : Environment) (name : Name) -2 | declTypeMismatch (env : Environment) (decl : Declaration) (givenType : Expr) -3 | declHasMVars (env : Environment) (name : Name) (expr : Expr) -4 | declHasFVars (env : Environment) (name : Name) (expr : Expr) -5 | funExpected (env : Environment) (lctx : LocalContext) (expr : Expr) -6 | typeExpected (env : Environment) (lctx : LocalContext) (expr : Expr) -7 | letTypeMismatch (env : Environment) (lctx : LocalContext) (name : Name) (givenType : Expr) (expectedType : Expr) -8 | exprTypeMismatch (env : Environment) (lctx : LocalContext) (expr : Expr) (expectedType : Expr) -9 | appTypeMismatch (env : Environment) (lctx : LocalContext) (app : Expr) (funType : Expr) (argType : Expr) -10 | invalidProj (env : Environment) (lctx : LocalContext) (proj : Expr) -11 | other (msg : String) -``` */ template object * catch_kernel_exceptions(std::function const & f) { @@ -211,6 +197,9 @@ object * catch_kernel_exceptions(std::function const & f) { } catch (stack_space_exception & ex) { // 14 | deepRecursion return mk_cnstr(0, box(14)).steal(); + } catch (interrupted & ex) { + // 15 | interrupted + return mk_cnstr(0, box(15)).steal(); } } } From a2e2481c51e12166dc1163ff7b8e27613c4ebaea Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Tue, 10 Oct 2023 17:27:10 +0200 Subject: [PATCH 50/71] feat: cancel tasks on document edit --- src/Lean/Server/AsyncList.lean | 14 ++++++++++++++ src/Lean/Server/FileWorker.lean | 2 ++ 2 files changed, 16 insertions(+) diff --git a/src/Lean/Server/AsyncList.lean b/src/Lean/Server/AsyncList.lean index 5da2648899e2..dc4abbc688c7 100644 --- a/src/Lean/Server/AsyncList.lean +++ b/src/Lean/Server/AsyncList.lean @@ -112,6 +112,20 @@ partial def getFinishedPrefix : AsyncList ε α → BaseIO (List α × Option ε def waitHead? (as : AsyncList ε α) : Task (Except ε (Option α)) := as.waitFind? fun _ => true +/-- Cancels all tasks in the list. -/ +partial def cancel : AsyncList ε α → BaseIO Unit + | cons _ tl => tl.cancel + | nil => pure () + | delayed tl => do + -- mind the order: if we asked the task whether it is still running + -- *before* cancelling it, it could be the case that it finished + -- just in between and has enqueued a dependent task that we would + -- miss (recall that cancellation is inherited by dependent tasks) + IO.cancel tl + if (← hasFinished tl) then + if let .ok t := tl.get then + t.cancel + end AsyncList end IO diff --git a/src/Lean/Server/FileWorker.lean b/src/Lean/Server/FileWorker.lean index 99815d87da7d..63068c59f352 100644 --- a/src/Lean/Server/FileWorker.lean +++ b/src/Lean/Server/FileWorker.lean @@ -296,6 +296,7 @@ section Updates let changePos := oldDoc.meta.text.source.firstDiffPos newMeta.text.source -- Ignore exceptions, we are only interested in the successful snapshots let (cmdSnaps, _) ← oldDoc.cmdSnaps.getFinishedPrefix + oldDoc.cmdSnaps.cancel -- NOTE(WN): we invalidate eagerly as `endPos` consumes input greedily. To re-elaborate only -- when really necessary, we could do a whitespace-aware `Syntax` comparison instead. let mut validSnaps ← pure (cmdSnaps.takeWhile (fun s => s.endPos < changePos)) @@ -461,6 +462,7 @@ section MainLoop | Message.notification "exit" none => let doc := st.doc doc.cancelTk.set + doc.cmdSnaps.cancel return () | Message.notification method (some params) => handleNotification method (toJson params) From c0e3b9568e92cea8cf1c07ff911da78462c0ed57 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Tue, 10 Oct 2023 17:20:48 +0200 Subject: [PATCH 51/71] fix: do not throw interrupt exceptions inside pure functions --- src/kernel/expr_eq_fn.cpp | 6 +++++- src/kernel/replace_fn.cpp | 4 +++- src/runtime/interrupt.cpp | 5 +++-- src/runtime/interrupt.h | 6 +++++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/kernel/expr_eq_fn.cpp b/src/kernel/expr_eq_fn.cpp index d3942470d615..814faa018bb0 100644 --- a/src/kernel/expr_eq_fn.cpp +++ b/src/kernel/expr_eq_fn.cpp @@ -60,7 +60,11 @@ template class expr_eq_fn { eq_cache & m_cache; - static void check_system() { ::lean::check_system("expression equality test"); } + static void check_system() { + // as this function is used by the pure `Expr.equal`, + // we cannot throw a non-fatal exception here + ::lean::check_system("expression equality test", /* do_check_interrupted */ false); + } bool apply(expr const & a, expr const & b) { if (is_eqp(a, b)) return true; diff --git a/src/kernel/replace_fn.cpp b/src/kernel/replace_fn.cpp index f0b995d6d1f9..b4fc06b0e549 100644 --- a/src/kernel/replace_fn.cpp +++ b/src/kernel/replace_fn.cpp @@ -73,7 +73,9 @@ class replace_rec_fn { return *r; shared = true; } - check_system("replace"); + // as this function is used by pure functions such as `lean_expr_instantiate`, + // we cannot throw a non-fatal exception here + check_system("replace", /* do_check_interrupted */ false); if (optional r = m_f(e, offset)) { return save_result(e, offset, *r, shared); diff --git a/src/runtime/interrupt.cpp b/src/runtime/interrupt.cpp index 85503e985e0a..0bc31d07387f 100644 --- a/src/runtime/interrupt.cpp +++ b/src/runtime/interrupt.cpp @@ -45,10 +45,11 @@ void check_interrupted() { } } -void check_system(char const * component_name) { +void check_system(char const * component_name, bool do_check_interrupted) { check_stack(component_name); check_memory(component_name); - check_interrupted(); + if (do_check_interrupted) + check_interrupted(); check_heartbeat(); } diff --git a/src/runtime/interrupt.h b/src/runtime/interrupt.h index f24868e314bb..ace464cc899b 100644 --- a/src/runtime/interrupt.h +++ b/src/runtime/interrupt.h @@ -49,8 +49,12 @@ void check_interrupted(); /** \brief Check system resources: stack, memory, heartbeat, interrupt flag. + + `do_check_interrupted` should be set to `false` in places where a C++ exception + is not caught and would bring down the entire process as interruption + should not be a fatal error. */ -void check_system(char const * component_name); +void check_system(char const * component_name, bool do_check_interrupted = true); constexpr unsigned g_small_sleep = 10; From 5aae74199b6cc2eb01619f0eaa04285c76cd388d Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Thu, 12 Oct 2023 10:02:10 +0200 Subject: [PATCH 52/71] fix: switch to C++ interruption whitelist --- src/kernel/expr_eq_fn.cpp | 4 +--- src/kernel/replace_fn.cpp | 4 +--- src/kernel/type_checker.cpp | 6 +++--- src/runtime/interrupt.h | 6 +++--- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/kernel/expr_eq_fn.cpp b/src/kernel/expr_eq_fn.cpp index 814faa018bb0..647bbec2d318 100644 --- a/src/kernel/expr_eq_fn.cpp +++ b/src/kernel/expr_eq_fn.cpp @@ -61,9 +61,7 @@ class expr_eq_fn { eq_cache & m_cache; static void check_system() { - // as this function is used by the pure `Expr.equal`, - // we cannot throw a non-fatal exception here - ::lean::check_system("expression equality test", /* do_check_interrupted */ false); + ::lean::check_system("expression equality test"); } bool apply(expr const & a, expr const & b) { diff --git a/src/kernel/replace_fn.cpp b/src/kernel/replace_fn.cpp index b4fc06b0e549..f0b995d6d1f9 100644 --- a/src/kernel/replace_fn.cpp +++ b/src/kernel/replace_fn.cpp @@ -73,9 +73,7 @@ class replace_rec_fn { return *r; shared = true; } - // as this function is used by pure functions such as `lean_expr_instantiate`, - // we cannot throw a non-fatal exception here - check_system("replace", /* do_check_interrupted */ false); + check_system("replace"); if (optional r = m_f(e, offset)) { return save_result(e, offset, *r, shared); diff --git a/src/kernel/type_checker.cpp b/src/kernel/type_checker.cpp index 281a17a6d126..6ba0b00dbf40 100644 --- a/src/kernel/type_checker.cpp +++ b/src/kernel/type_checker.cpp @@ -286,7 +286,7 @@ expr type_checker::infer_type_core(expr const & e, bool infer_only) { throw kernel_exception(env(), "type checker does not support loose bound variables, replace them with free variables before invoking it"); lean_assert(!has_loose_bvars(e)); - check_system("type checker"); + check_system("type checker", /* do_check_interrupted */ true); auto it = m_st->m_infer_type[infer_only].find(e); if (it != m_st->m_infer_type[infer_only].end()) @@ -409,7 +409,7 @@ static bool is_let_fvar(local_ctx const & lctx, expr const & e) { If `cheap == true`, then we don't perform delta-reduction when reducing major premise of recursors and projections. We also do not cache results. */ expr type_checker::whnf_core(expr const & e, bool cheap_rec, bool cheap_proj) { - check_system("type checker: whnf"); + check_system("type checker: whnf", /* do_check_interrupted */ true); // handle easy cases switch (e.kind()) { @@ -1000,7 +1000,7 @@ bool type_checker::is_def_eq_unit_like(expr const & t, expr const & s) { } bool type_checker::is_def_eq_core(expr const & t, expr const & s) { - check_system("is_definitionally_equal"); + check_system("is_definitionally_equal", /* do_check_interrupted */ true); bool use_hash = true; lbool r = quick_is_def_eq(t, s, use_hash); if (r != l_undef) return r == l_true; diff --git a/src/runtime/interrupt.h b/src/runtime/interrupt.h index ace464cc899b..4e628fb511ee 100644 --- a/src/runtime/interrupt.h +++ b/src/runtime/interrupt.h @@ -50,11 +50,11 @@ void check_interrupted(); /** \brief Check system resources: stack, memory, heartbeat, interrupt flag. - `do_check_interrupted` should be set to `false` in places where a C++ exception - is not caught and would bring down the entire process as interruption + `do_check_interrupted` should only be set to `true` in places where a C++ exception + is caught and would not bring down the entire process as interruption should not be a fatal error. */ -void check_system(char const * component_name, bool do_check_interrupted = true); +void check_system(char const * component_name, bool do_check_interrupted = false); constexpr unsigned g_small_sleep = 10; From 6494af4513da28b13f3e3175e4cf59e24ad05dc8 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Thu, 12 Oct 2023 14:05:00 +0200 Subject: [PATCH 53/71] perf: inline `checkInterrupted` Amazingly, the extra result allocation seems to have triggered a mathlib heartbeat timeout --- src/Lean/CoreM.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Lean/CoreM.lean b/src/Lean/CoreM.lean index 2b87d66d8ec1..ce19929d3a4e 100644 --- a/src/Lean/CoreM.lean +++ b/src/Lean/CoreM.lean @@ -199,7 +199,7 @@ instance [MetaEval α] : MetaEval (CoreM α) where protected def withIncRecDepth [Monad m] [MonadControlT CoreM m] (x : m α) : m α := controlAt CoreM fun runInBase => withIncRecDepth (runInBase x) -def checkInterrupted : CoreM Unit := do +@[inline] def checkInterrupted : CoreM Unit := do if (← IO.checkCanceled) then -- should never be visible to users! throw <| Exception.error .missing "elaboration interrupted" From 9f63a9f28889288c6dbca1961af6679f91d5417f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Oct 2023 07:57:12 +0000 Subject: [PATCH 54/71] doc: update changelog --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index cd8413ed31dd..84c95fd56db3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,6 +10,8 @@ Please check the [releases](https://github.com/leanprover/lean4/releases) page f v4.3.0 (development in progress) --------- +* [Cancel outstanding tasks on document edit in the language server](https://github.com/leanprover/lean4/pull/2648). + * `IO.Process.output` no longer inherits the standard input of the caller. * The derive handler for `DecidableEq` [now handles](https://github.com/leanprover/lean4/pull/2591) mutual inductive types. * [Show path of failed import in Lake](https://github.com/leanprover/lean4/pull/2616). From f3de5eb1e8dc0708cd5b7983c282cace6e025957 Mon Sep 17 00:00:00 2001 From: tydeu Date: Tue, 10 Oct 2023 16:19:17 -0400 Subject: [PATCH 55/71] feat: lake: `--no-build` to exit before a build --- src/lake/Lake/Build/Common.lean | 4 ++++ src/lake/Lake/Build/Context.lean | 9 +++++++++ src/lake/Lake/CLI/Main.lean | 3 +++ src/lake/tests/noBuild/.gitignore | 2 ++ src/lake/tests/noBuild/Test.lean | 0 src/lake/tests/noBuild/clean.sh | 1 + src/lake/tests/noBuild/lakefile.lean | 5 +++++ src/lake/tests/noBuild/test.sh | 24 ++++++++++++++++++++++++ 8 files changed, 48 insertions(+) create mode 100644 src/lake/tests/noBuild/.gitignore create mode 100644 src/lake/tests/noBuild/Test.lean create mode 100755 src/lake/tests/noBuild/clean.sh create mode 100644 src/lake/tests/noBuild/lakefile.lean create mode 100755 src/lake/tests/noBuild/test.sh diff --git a/src/lake/Lake/Build/Common.lean b/src/lake/Lake/Build/Common.lean index 424a8d710b3e..3935c6c22323 100644 --- a/src/lake/Lake/Build/Common.lean +++ b/src/lake/Lake/Build/Common.lean @@ -31,6 +31,8 @@ of the `traceFile`. If rebuilt, save the new `depTrace` to the `tracefile`. @[inline] def buildUnlessUpToDate [CheckExists ι] [GetMTime ι] (info : ι) (depTrace : BuildTrace) (traceFile : FilePath) (build : JobM PUnit) : JobM PUnit := do unless (← depTrace.checkUpToDate info traceFile) do + if (← getNoBuild) then + IO.Process.exit noBuildCode.toUInt8 build depTrace.writeToFile traceFile @@ -69,6 +71,8 @@ def buildFileUnlessUpToDate (file : FilePath) if (← depTrace.checkUpToDate file traceFile) then fetchFileTrace file else + if (← getNoBuild) then + IO.Process.exit noBuildCode.toUInt8 build depTrace.writeToFile traceFile return .mk (← cacheFileHash file) (← getMTime file) diff --git a/src/lake/Lake/Build/Context.lean b/src/lake/Lake/Build/Context.lean index a775c2d2eeaf..42fd52ef3421 100644 --- a/src/lake/Lake/Build/Context.lean +++ b/src/lake/Lake/Build/Context.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mac Malone -/ import Lake.Util.Log +import Lake.Util.Exit import Lake.Util.Task import Lake.Util.Error import Lake.Util.OptionIO @@ -15,10 +16,15 @@ import Lake.Build.Topological open System namespace Lake +/-- Exit code to return if `--no-build` is set and a build is required. -/ +def noBuildCode : ExitCode := 3 + /-- Configuration options for a Lake build. -/ structure BuildConfig where oldMode : Bool := false trustHash : Bool := true + /-- Early exit if a target has to be rebuilt. -/ + noBuild : Bool := false /-- A Lake context with a build configuration and additional build data. -/ structure BuildContext extends BuildConfig, Context where @@ -41,6 +47,9 @@ abbrev BuildT := ReaderT BuildContext @[inline] def getTrustHash [Monad m] : BuildT m Bool := (·.trustHash) <$> getBuildConfig +@[inline] def getNoBuild [Monad m] : BuildT m Bool := + (·.noBuild) <$> getBuildConfig + /-- The monad for the Lake build manager. -/ abbrev SchedulerM := BuildT <| LogT BaseIO diff --git a/src/lake/Lake/CLI/Main.lean b/src/lake/Lake/CLI/Main.lean index 975985ff8e32..b730c8d8a2dd 100644 --- a/src/lake/Lake/CLI/Main.lean +++ b/src/lake/Lake/CLI/Main.lean @@ -38,6 +38,7 @@ structure LakeOptions where reconfigure : Bool := false oldMode : Bool := false trustHash : Bool := true + noBuild : Bool := false /-- Get the Lean installation. Error if missing. -/ def LakeOptions.getLeanInstall (opts : LakeOptions) : Except CliError LeanInstall := @@ -74,6 +75,7 @@ def LakeOptions.mkLoadConfig (opts : LakeOptions) : EIO CliError LoadConfig := def LakeOptions.mkBuildConfig (opts : LakeOptions) : BuildConfig where oldMode := opts.oldMode trustHash := opts.trustHash + noBuild := opts.noBuild export LakeOptions (mkLoadConfig mkBuildConfig) @@ -153,6 +155,7 @@ def lakeLongOption : (opt : String) → CliM PUnit | "--update" => modifyThe LakeOptions ({· with updateDeps := true}) | "--reconfigure" => modifyThe LakeOptions ({· with reconfigure := true}) | "--old" => modifyThe LakeOptions ({· with oldMode := true}) +| "--no-build" => modifyThe LakeOptions ({· with noBuild := true}) | "--rehash" => modifyThe LakeOptions ({· with trustHash := false}) | "--dir" => do let rootDir ← takeOptArg "--dir" "path"; modifyThe LakeOptions ({· with rootDir}) | "--file" => do let configFile ← takeOptArg "--file" "path"; modifyThe LakeOptions ({· with configFile}) diff --git a/src/lake/tests/noBuild/.gitignore b/src/lake/tests/noBuild/.gitignore new file mode 100644 index 000000000000..929fb1db692e --- /dev/null +++ b/src/lake/tests/noBuild/.gitignore @@ -0,0 +1,2 @@ +build +lakefile.olean diff --git a/src/lake/tests/noBuild/Test.lean b/src/lake/tests/noBuild/Test.lean new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/lake/tests/noBuild/clean.sh b/src/lake/tests/noBuild/clean.sh new file mode 100755 index 000000000000..158232186394 --- /dev/null +++ b/src/lake/tests/noBuild/clean.sh @@ -0,0 +1 @@ +rm -rf build diff --git a/src/lake/tests/noBuild/lakefile.lean b/src/lake/tests/noBuild/lakefile.lean new file mode 100644 index 000000000000..c55727c327ef --- /dev/null +++ b/src/lake/tests/noBuild/lakefile.lean @@ -0,0 +1,5 @@ +import Lake +open Lake DSL + +package test +lean_lib Test diff --git a/src/lake/tests/noBuild/test.sh b/src/lake/tests/noBuild/test.sh new file mode 100755 index 000000000000..94f1e5cf3c57 --- /dev/null +++ b/src/lake/tests/noBuild/test.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euxo pipefail + +# Tests that Lake properly exits before normal builds occur +# when `--no-build` is passed on the command line. + +./clean.sh + +NO_BUILD_CODE=3 +LAKE=${LAKE:-../../build/bin/lake} + +# Test `--no-build` for print-paths and module builds (`buildUnlessUpToDate`) +$LAKE print-paths Test --no-build && exit 1 || [ $? = $NO_BUILD_CODE ] +test ! -f build/lib/Test.olean +$LAKE build Test +test -f build/lib/Test.olean +$LAKE print-paths Test --no-build + +# Test `--no-build` for file builds (`buildFileUnlessUpToDate`) +$LAKE build +Test:o --no-build && exit 1 || [ $? = $NO_BUILD_CODE ] +test ! -f build/ir/Test.o +$LAKE build +Test:o +test -f build/ir/Test.o +$LAKE build +Test:o --no-build From 4e1d95ce5865248a0bffb51735bdf53b6e6957c4 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Wed, 11 Oct 2023 10:33:35 +0200 Subject: [PATCH 56/71] feat: pass along extra `print-paths` flags and handle no-build Lake error in server --- src/Lean/Data/Lsp/Extra.lean | 8 ++++++++ src/Lean/Server/FileWorker.lean | 2 ++ src/Lean/Server/Watchdog.lean | 10 ++++++---- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Lean/Data/Lsp/Extra.lean b/src/Lean/Data/Lsp/Extra.lean index 0a1478477cfd..33f36f15584d 100644 --- a/src/Lean/Data/Lsp/Extra.lean +++ b/src/Lean/Data/Lsp/Extra.lean @@ -5,6 +5,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Marc Huisinga, Wojciech Nawrocki -/ import Lean.Data.Lsp.Basic +import Lean.Data.Lsp.TextSync import Lean.Server.Rpc.Basic /-! This file contains Lean-specific extensions to LSP. See the structures below for which @@ -13,6 +14,13 @@ additional requests and notifications are supported. -/ namespace Lean.Lsp open Json +structure LeanDidOpenTextDocumentParams extends DidOpenTextDocumentParams where + /-- + Further flags passed to `lake print-paths` for the opened document. + Used for forwarding `--no-build` on initial open. -/ + extraPrintPathsFlags? : Option (Array String) + deriving FromJson, ToJson + /-- `textDocument/waitForDiagnostics` client->server request. Yields a response when all the diagnostics for a version of the document greater or equal to the diff --git a/src/Lean/Server/FileWorker.lean b/src/Lean/Server/FileWorker.lean index 63068c59f352..1657b9506c2c 100644 --- a/src/Lean/Server/FileWorker.lean +++ b/src/Lean/Server/FileWorker.lean @@ -187,6 +187,8 @@ section Initialization paths.loadDynlibPaths.forM loadDynlib paths.srcPath.mapM realPathNormalized | 2 => pure [] -- no lakefile.lean + -- error from `--no-build` + | 3 => throwServerError s!"Imports are out of date and must be rebuilt; use the \"Refresh File Dependencies\" command in your editor\n\n{stdout}" | _ => throwServerError s!"`{cmdStr}` failed:\n{stdout}\nstderr:\n{stderr}" def compileHeader (m : DocumentMeta) (hOut : FS.Stream) (opts : Options) (hasWidgets : Bool) diff --git a/src/Lean/Server/Watchdog.lean b/src/Lean/Server/Watchdog.lean index 4c4707d0338c..ee03f9a45432 100644 --- a/src/Lean/Server/Watchdog.lean +++ b/src/Lean/Server/Watchdog.lean @@ -237,7 +237,7 @@ section ServerM | Except.ok ev => ev | Except.error e => WorkerEvent.ioError e - def startFileWorker (m : DocumentMeta) : ServerM Unit := do + def startFileWorker (m : DocumentMeta) (extraPrintPathsFlags : Array String := #[]) : ServerM Unit := do publishProgressAtPos m 0 (← read).hOut let st ← read let workerProc ← Process.spawn { @@ -267,7 +267,9 @@ section ServerM languageId := "lean" version := m.version text := m.text.source - } : DidOpenTextDocumentParams + } + extraPrintPathsFlags? := extraPrintPathsFlags + : LeanDidOpenTextDocumentParams } } updateFileWorkers fw @@ -379,14 +381,14 @@ def handleWorkspaceSymbol (p : WorkspaceSymbolParams) : ServerM (Array SymbolInf end RequestHandling section NotificationHandling - def handleDidOpen (p : DidOpenTextDocumentParams) : ServerM Unit := + def handleDidOpen (p : LeanDidOpenTextDocumentParams) : ServerM Unit := let doc := p.textDocument /- NOTE(WN): `toFileMap` marks line beginnings as immediately following "\n", which should be enough to handle both LF and CRLF correctly. This is because LSP always refers to characters by (line, column), so if we get the line number correct it shouldn't matter that there is a CR there. -/ - startFileWorker ⟨doc.uri, doc.version, doc.text.toFileMap⟩ + startFileWorker ⟨doc.uri, doc.version, doc.text.toFileMap⟩ (p.extraPrintPathsFlags?.getD #[]) def handleDidChange (p : DidChangeTextDocumentParams) : ServerM Unit := do let doc := p.textDocument From 9945fa04d62ab91f782e77eb421ae2009a52644f Mon Sep 17 00:00:00 2001 From: mhuisi Date: Thu, 12 Oct 2023 15:09:37 +0200 Subject: [PATCH 57/71] feat: FileWorker handling of --no-build --- src/Lean/Data/Lsp/Extra.lean | 2 +- src/Lean/Server/FileWorker.lean | 9 +++++---- src/Lean/Server/Utils.lean | 7 ++++--- src/Lean/Server/Watchdog.lean | 8 ++++---- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Lean/Data/Lsp/Extra.lean b/src/Lean/Data/Lsp/Extra.lean index 33f36f15584d..1c4849021416 100644 --- a/src/Lean/Data/Lsp/Extra.lean +++ b/src/Lean/Data/Lsp/Extra.lean @@ -18,7 +18,7 @@ structure LeanDidOpenTextDocumentParams extends DidOpenTextDocumentParams where /-- Further flags passed to `lake print-paths` for the opened document. Used for forwarding `--no-build` on initial open. -/ - extraPrintPathsFlags? : Option (Array String) + extraPrintPathsFlags? : Option (Array String) := none deriving FromJson, ToJson /-- `textDocument/waitForDiagnostics` client->server request. diff --git a/src/Lean/Server/FileWorker.lean b/src/Lean/Server/FileWorker.lean index 1657b9506c2c..1c9bd3b7c155 100644 --- a/src/Lean/Server/FileWorker.lean +++ b/src/Lean/Server/FileWorker.lean @@ -159,7 +159,7 @@ section Initialization Compilation progress is reported to `hOut` via LSP notifications. Return the search path for source files. -/ partial def lakeSetupSearchPath (lakePath : System.FilePath) (m : DocumentMeta) (imports : Array Import) (hOut : FS.Stream) : IO SearchPath := do - let args := #["print-paths"] ++ imports.map (toString ·.module) + let args := #["print-paths"] ++ imports.map (toString ·.module) ++ m.extraPrintPathsFlags let cmdStr := " ".intercalate (toString lakePath :: args.toList) let lakeProc ← Process.spawn { stdin := Process.Stdio.null @@ -336,7 +336,7 @@ section NotificationHandling let newVersion := docId.version?.getD 0 if ¬ changes.isEmpty then let newDocText := foldDocumentChanges changes oldDoc.meta.text - updateDocument ⟨docId.uri, newVersion, newDocText⟩ + updateDocument ⟨docId.uri, newVersion, newDocText, oldDoc.meta.extraPrintPathsFlags⟩ def handleCancelRequest (p : CancelParams) : WorkerM Unit := do updatePendingRequests (fun pendingRequests => pendingRequests.erase p.id) @@ -476,14 +476,15 @@ def initAndRunWorker (i o e : FS.Stream) (opts : Options) : IO UInt32 := do let i ← maybeTee "fwIn.txt" false i let o ← maybeTee "fwOut.txt" true o let initParams ← i.readLspRequestAs "initialize" InitializeParams - let ⟨_, param⟩ ← i.readLspNotificationAs "textDocument/didOpen" DidOpenTextDocumentParams + let ⟨_, param⟩ ← i.readLspNotificationAs "textDocument/didOpen" LeanDidOpenTextDocumentParams + let extraPrintPathsFlags := param.extraPrintPathsFlags?.getD #[] let doc := param.textDocument /- NOTE(WN): `toFileMap` marks line beginnings as immediately following "\n", which should be enough to handle both LF and CRLF correctly. This is because LSP always refers to characters by (line, column), so if we get the line number correct it shouldn't matter that there is a CR there. -/ - let meta : DocumentMeta := ⟨doc.uri, doc.version, doc.text.toFileMap⟩ + let meta : DocumentMeta := ⟨doc.uri, doc.version, doc.text.toFileMap, extraPrintPathsFlags⟩ let e := e.withPrefix s!"[{param.textDocument.uri}] " let _ ← IO.setStderr e try diff --git a/src/Lean/Server/Utils.lean b/src/Lean/Server/Utils.lean index 4827739d4205..ee0fd9cc9cd8 100644 --- a/src/Lean/Server/Utils.lean +++ b/src/Lean/Server/Utils.lean @@ -65,9 +65,10 @@ end IO namespace Lean.Server structure DocumentMeta where - uri : Lsp.DocumentUri - version : Nat - text : FileMap + uri : Lsp.DocumentUri + version : Nat + text : FileMap + extraPrintPathsFlags : Array String deriving Inhabited def DocumentMeta.mkInputContext (doc : DocumentMeta) : Parser.InputContext where diff --git a/src/Lean/Server/Watchdog.lean b/src/Lean/Server/Watchdog.lean index ee03f9a45432..278d6ea177af 100644 --- a/src/Lean/Server/Watchdog.lean +++ b/src/Lean/Server/Watchdog.lean @@ -237,7 +237,7 @@ section ServerM | Except.ok ev => ev | Except.error e => WorkerEvent.ioError e - def startFileWorker (m : DocumentMeta) (extraPrintPathsFlags : Array String := #[]) : ServerM Unit := do + def startFileWorker (m : DocumentMeta) : ServerM Unit := do publishProgressAtPos m 0 (← read).hOut let st ← read let workerProc ← Process.spawn { @@ -268,7 +268,7 @@ section ServerM version := m.version text := m.text.source } - extraPrintPathsFlags? := extraPrintPathsFlags + extraPrintPathsFlags? := m.extraPrintPathsFlags : LeanDidOpenTextDocumentParams } } @@ -388,7 +388,7 @@ section NotificationHandling This is because LSP always refers to characters by (line, column), so if we get the line number correct it shouldn't matter that there is a CR there. -/ - startFileWorker ⟨doc.uri, doc.version, doc.text.toFileMap⟩ (p.extraPrintPathsFlags?.getD #[]) + startFileWorker ⟨doc.uri, doc.version, doc.text.toFileMap, p.extraPrintPathsFlags?.getD #[]⟩ def handleDidChange (p : DidChangeTextDocumentParams) : ServerM Unit := do let doc := p.textDocument @@ -399,7 +399,7 @@ section NotificationHandling if changes.isEmpty then return let newDocText := foldDocumentChanges changes oldDoc.text - let newDoc : DocumentMeta := ⟨doc.uri, newVersion, newDocText⟩ + let newDoc : DocumentMeta := ⟨doc.uri, newVersion, newDocText, oldDoc.extraPrintPathsFlags⟩ updateFileWorkers { fw with doc := newDoc } tryWriteMessage doc.uri (Notification.mk "textDocument/didChange" p) (restartCrashedWorker := true) From 253a5b931d16155930f4bd7775feaee836504728 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Thu, 12 Oct 2023 17:56:44 +0200 Subject: [PATCH 58/71] fix: correct handling of FileWorker restarts --- src/Lean/Data/Lsp/Extra.lean | 17 +++++++++++++---- src/Lean/Server/FileWorker.lean | 9 +++++---- src/Lean/Server/Utils.lean | 8 ++++---- src/Lean/Server/Watchdog.lean | 16 ++++++++++++---- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/Lean/Data/Lsp/Extra.lean b/src/Lean/Data/Lsp/Extra.lean index 1c4849021416..6f147b8424fe 100644 --- a/src/Lean/Data/Lsp/Extra.lean +++ b/src/Lean/Data/Lsp/Extra.lean @@ -14,11 +14,20 @@ additional requests and notifications are supported. -/ namespace Lean.Lsp open Json +/-- + Controls when dependencies are built on `textDocument/didOpen` notifications. +-/ +inductive DependencyBuildMode where + /-- Always build dependencies. -/ + | always + /-- Build dependencies once, but then do not build them again on import changes / crashes. Used for `didOpen` notifications that are explicitly intended for manually triggering the build. -/ + | once + /-- Never build dependencies. -/ + | never + deriving FromJson, ToJson, Inhabited + structure LeanDidOpenTextDocumentParams extends DidOpenTextDocumentParams where - /-- - Further flags passed to `lake print-paths` for the opened document. - Used for forwarding `--no-build` on initial open. -/ - extraPrintPathsFlags? : Option (Array String) := none + dependencyBuildMode : DependencyBuildMode := .always -- Compatibility with clients pre-build-mode deriving FromJson, ToJson /-- `textDocument/waitForDiagnostics` client->server request. diff --git a/src/Lean/Server/FileWorker.lean b/src/Lean/Server/FileWorker.lean index 1c9bd3b7c155..22f934f42c5f 100644 --- a/src/Lean/Server/FileWorker.lean +++ b/src/Lean/Server/FileWorker.lean @@ -159,7 +159,9 @@ section Initialization Compilation progress is reported to `hOut` via LSP notifications. Return the search path for source files. -/ partial def lakeSetupSearchPath (lakePath : System.FilePath) (m : DocumentMeta) (imports : Array Import) (hOut : FS.Stream) : IO SearchPath := do - let args := #["print-paths"] ++ imports.map (toString ·.module) ++ m.extraPrintPathsFlags + let mut args := #["print-paths"] ++ imports.map (toString ·.module) + if m.dependencyBuildMode matches .never then + args := args.push "--no-build" let cmdStr := " ".intercalate (toString lakePath :: args.toList) let lakeProc ← Process.spawn { stdin := Process.Stdio.null @@ -336,7 +338,7 @@ section NotificationHandling let newVersion := docId.version?.getD 0 if ¬ changes.isEmpty then let newDocText := foldDocumentChanges changes oldDoc.meta.text - updateDocument ⟨docId.uri, newVersion, newDocText, oldDoc.meta.extraPrintPathsFlags⟩ + updateDocument ⟨docId.uri, newVersion, newDocText, oldDoc.meta.dependencyBuildMode⟩ def handleCancelRequest (p : CancelParams) : WorkerM Unit := do updatePendingRequests (fun pendingRequests => pendingRequests.erase p.id) @@ -477,14 +479,13 @@ def initAndRunWorker (i o e : FS.Stream) (opts : Options) : IO UInt32 := do let o ← maybeTee "fwOut.txt" true o let initParams ← i.readLspRequestAs "initialize" InitializeParams let ⟨_, param⟩ ← i.readLspNotificationAs "textDocument/didOpen" LeanDidOpenTextDocumentParams - let extraPrintPathsFlags := param.extraPrintPathsFlags?.getD #[] let doc := param.textDocument /- NOTE(WN): `toFileMap` marks line beginnings as immediately following "\n", which should be enough to handle both LF and CRLF correctly. This is because LSP always refers to characters by (line, column), so if we get the line number correct it shouldn't matter that there is a CR there. -/ - let meta : DocumentMeta := ⟨doc.uri, doc.version, doc.text.toFileMap, extraPrintPathsFlags⟩ + let meta : DocumentMeta := ⟨doc.uri, doc.version, doc.text.toFileMap, param.dependencyBuildMode⟩ let e := e.withPrefix s!"[{param.textDocument.uri}] " let _ ← IO.setStderr e try diff --git a/src/Lean/Server/Utils.lean b/src/Lean/Server/Utils.lean index ee0fd9cc9cd8..f8d7e66a5736 100644 --- a/src/Lean/Server/Utils.lean +++ b/src/Lean/Server/Utils.lean @@ -65,10 +65,10 @@ end IO namespace Lean.Server structure DocumentMeta where - uri : Lsp.DocumentUri - version : Nat - text : FileMap - extraPrintPathsFlags : Array String + uri : Lsp.DocumentUri + version : Nat + text : FileMap + dependencyBuildMode : Lsp.DependencyBuildMode deriving Inhabited def DocumentMeta.mkInputContext (doc : DocumentMeta) : Parser.InputContext where diff --git a/src/Lean/Server/Watchdog.lean b/src/Lean/Server/Watchdog.lean index 278d6ea177af..d193917e1de8 100644 --- a/src/Lean/Server/Watchdog.lean +++ b/src/Lean/Server/Watchdog.lean @@ -248,9 +248,17 @@ section ServerM setsid := true } let pendingRequestsRef ← IO.mkRef (RBMap.empty : PendingRequestMap) + let initialDependencyBuildMode := m.dependencyBuildMode + let updatedDependencyBuildMode := + if initialDependencyBuildMode matches .once then + -- By sending the first `didOpen` notification, we build the dependencies once + -- => no future builds + .never + else + initialDependencyBuildMode -- The task will never access itself, so this is fine let fw : FileWorker := { - doc := m + doc := { m with dependencyBuildMode := updatedDependencyBuildMode} proc := workerProc commTask := Task.pure WorkerEvent.terminated state := WorkerState.running @@ -268,7 +276,7 @@ section ServerM version := m.version text := m.text.source } - extraPrintPathsFlags? := m.extraPrintPathsFlags + dependencyBuildMode := initialDependencyBuildMode : LeanDidOpenTextDocumentParams } } @@ -388,7 +396,7 @@ section NotificationHandling This is because LSP always refers to characters by (line, column), so if we get the line number correct it shouldn't matter that there is a CR there. -/ - startFileWorker ⟨doc.uri, doc.version, doc.text.toFileMap, p.extraPrintPathsFlags?.getD #[]⟩ + startFileWorker ⟨doc.uri, doc.version, doc.text.toFileMap, p.dependencyBuildMode⟩ def handleDidChange (p : DidChangeTextDocumentParams) : ServerM Unit := do let doc := p.textDocument @@ -399,7 +407,7 @@ section NotificationHandling if changes.isEmpty then return let newDocText := foldDocumentChanges changes oldDoc.text - let newDoc : DocumentMeta := ⟨doc.uri, newVersion, newDocText, oldDoc.extraPrintPathsFlags⟩ + let newDoc : DocumentMeta := ⟨doc.uri, newVersion, newDocText, oldDoc.dependencyBuildMode⟩ updateFileWorkers { fw with doc := newDoc } tryWriteMessage doc.uri (Notification.mk "textDocument/didChange" p) (restartCrashedWorker := true) From b5348786a6b791e4f37f629f5e1a06398ec0f640 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Thu, 12 Oct 2023 18:23:18 +0200 Subject: [PATCH 59/71] fix: pre-dependency-build-mode compatibility --- src/Lean/Data/Lsp/Extra.lean | 2 +- src/Lean/Server/FileWorker.lean | 2 +- src/Lean/Server/Watchdog.lean | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Lean/Data/Lsp/Extra.lean b/src/Lean/Data/Lsp/Extra.lean index 6f147b8424fe..8fb8f0d874c2 100644 --- a/src/Lean/Data/Lsp/Extra.lean +++ b/src/Lean/Data/Lsp/Extra.lean @@ -27,7 +27,7 @@ inductive DependencyBuildMode where deriving FromJson, ToJson, Inhabited structure LeanDidOpenTextDocumentParams extends DidOpenTextDocumentParams where - dependencyBuildMode : DependencyBuildMode := .always -- Compatibility with clients pre-build-mode + dependencyBuildMode? : Option DependencyBuildMode := none -- `none`: Compatibility with clients pre-build-mode deriving FromJson, ToJson /-- `textDocument/waitForDiagnostics` client->server request. diff --git a/src/Lean/Server/FileWorker.lean b/src/Lean/Server/FileWorker.lean index 22f934f42c5f..c8aee96da546 100644 --- a/src/Lean/Server/FileWorker.lean +++ b/src/Lean/Server/FileWorker.lean @@ -485,7 +485,7 @@ def initAndRunWorker (i o e : FS.Stream) (opts : Options) : IO UInt32 := do This is because LSP always refers to characters by (line, column), so if we get the line number correct it shouldn't matter that there is a CR there. -/ - let meta : DocumentMeta := ⟨doc.uri, doc.version, doc.text.toFileMap, param.dependencyBuildMode⟩ + let meta : DocumentMeta := ⟨doc.uri, doc.version, doc.text.toFileMap, param.dependencyBuildMode?.getD .always⟩ let e := e.withPrefix s!"[{param.textDocument.uri}] " let _ ← IO.setStderr e try diff --git a/src/Lean/Server/Watchdog.lean b/src/Lean/Server/Watchdog.lean index d193917e1de8..d517c46debea 100644 --- a/src/Lean/Server/Watchdog.lean +++ b/src/Lean/Server/Watchdog.lean @@ -276,7 +276,7 @@ section ServerM version := m.version text := m.text.source } - dependencyBuildMode := initialDependencyBuildMode + dependencyBuildMode? := initialDependencyBuildMode : LeanDidOpenTextDocumentParams } } @@ -396,7 +396,7 @@ section NotificationHandling This is because LSP always refers to characters by (line, column), so if we get the line number correct it shouldn't matter that there is a CR there. -/ - startFileWorker ⟨doc.uri, doc.version, doc.text.toFileMap, p.dependencyBuildMode⟩ + startFileWorker ⟨doc.uri, doc.version, doc.text.toFileMap, p.dependencyBuildMode?.getD .always⟩ def handleDidChange (p : DidChangeTextDocumentParams) : ServerM Unit := do let doc := p.textDocument From d0ae87d13f54c12fe225d957031f9f7dfa5a99f6 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Thu, 12 Oct 2023 18:24:08 +0200 Subject: [PATCH 60/71] chore: improve error --- src/Lean/Server/FileWorker.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Lean/Server/FileWorker.lean b/src/Lean/Server/FileWorker.lean index c8aee96da546..b7e7910b04ef 100644 --- a/src/Lean/Server/FileWorker.lean +++ b/src/Lean/Server/FileWorker.lean @@ -190,7 +190,7 @@ section Initialization paths.srcPath.mapM realPathNormalized | 2 => pure [] -- no lakefile.lean -- error from `--no-build` - | 3 => throwServerError s!"Imports are out of date and must be rebuilt; use the \"Refresh File Dependencies\" command in your editor\n\n{stdout}" + | 3 => throwServerError s!"Imports are out of date and must be rebuilt; use the \"Restart File\" command in your editor.\n\n{stdout}" | _ => throwServerError s!"`{cmdStr}` failed:\n{stdout}\nstderr:\n{stderr}" def compileHeader (m : DocumentMeta) (hOut : FS.Stream) (opts : Options) (hasWidgets : Bool) From ff20a14c6907c539e412c1d016ad1c443e539092 Mon Sep 17 00:00:00 2001 From: Arthur Adjedj Date: Sat, 14 Oct 2023 08:18:37 +0200 Subject: [PATCH 61/71] fix : make `mk_no_confusion_type` handle delta-reduction when generating telescope (#2501) * fix : make `mk_no_confusion_type` handle delta-reduction when checking the inductive type. * tests: extend `2500.lean` --- src/library/constructions/no_confusion.cpp | 2 +- tests/lean/run/2500.lean | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/lean/run/2500.lean diff --git a/src/library/constructions/no_confusion.cpp b/src/library/constructions/no_confusion.cpp index 963328e57b98..ca206f374b47 100644 --- a/src/library/constructions/no_confusion.cpp +++ b/src/library/constructions/no_confusion.cpp @@ -39,7 +39,7 @@ static optional mk_no_confusion_type(environment const & env, name expr ind_type = instantiate_type_lparams(ind_info, ilvls); /* All inductive datatype parameters and indices are arguments */ buffer args; - ind_type = to_telescope(lctx, ngen, ind_type, args, some(mk_implicit_binder_info())); + ind_type = to_telescope(env, lctx, ngen, ind_type, args, some(mk_implicit_binder_info())); ind_type = type_checker(env, lctx).whnf(ind_type); if (!is_sort(ind_type) || args.size() < nparams) throw_corrupted(n); diff --git a/tests/lean/run/2500.lean b/tests/lean/run/2500.lean new file mode 100644 index 000000000000..c53fbf559046 --- /dev/null +++ b/tests/lean/run/2500.lean @@ -0,0 +1,15 @@ +/-! +# Verify that the `noConfusion` lemma succeeds at being generated, despite the inductive type not being a syntactical telescope +Fixes https://github.com/leanprover/lean4/issues/2500 +Ensures the `to_telescope` call in `mk_no_confusion_type` (`src/library/constructions/no_confusion.cpp`) takes the global environment into account, +thus allowing for delta-reduction. +-/ + +def family := Type → Type + +inductive bad : family + +def Set (A : Type _) := A → Prop + +inductive Thing (s : Set V) : Set V +| basic : ∀ x, s x → Thing s x From 2253b788b416c2e46bbb1c5b69a50985ed6ecb2e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 9 Oct 2023 16:59:32 -0700 Subject: [PATCH 62/71] perf: fine grain isDefEq cache for terms not containing metavariables --- src/Lean/Meta/Basic.lean | 14 +++++--- src/Lean/Meta/ExprDefEq.lean | 62 ++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/Lean/Meta/Basic.lean b/src/Lean/Meta/Basic.lean index bfcce6d207a3..11c7adc3971e 100644 --- a/src/Lean/Meta/Basic.lean +++ b/src/Lean/Meta/Basic.lean @@ -216,7 +216,11 @@ structure Cache where synthInstance : SynthInstanceCache := {} whnfDefault : WhnfCache := {} -- cache for closed terms and `TransparencyMode.default` whnfAll : WhnfCache := {} -- cache for closed terms and `TransparencyMode.all` - defEq : DefEqCache := {} + defEq : DefEqCache := {} -- transient cache for terms containing mvars and nonstardard configuration options, it is frequently reset. + defEqReducible : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.reducible` + defEqInstances : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.instances` + defEqDefault : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.default` + defEqAll : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.all` deriving Inhabited /-- @@ -363,10 +367,10 @@ variable [MonadControlT MetaM n] [Monad n] modify fun ⟨mctx, cache, zetaFVarIds, postponed⟩ => ⟨mctx, f cache, zetaFVarIds, postponed⟩ @[inline] def modifyInferTypeCache (f : InferTypeCache → InferTypeCache) : MetaM Unit := - modifyCache fun ⟨ic, c1, c2, c3, c4, c5⟩ => ⟨f ic, c1, c2, c3, c4, c5⟩ + modifyCache fun ⟨ic, c1, c2, c3, c4, c5, c6, c7, c8, c9⟩ => ⟨f ic, c1, c2, c3, c4, c5, c6, c7, c8, c9⟩ -@[inline] def modifyDefEqCache (f : DefEqCache → DefEqCache) : MetaM Unit := - modifyCache fun ⟨c1, c2, c3, c4, c5, defeq⟩ => ⟨c1, c2, c3, c4, c5, f defeq⟩ +@[inline] def modifyDefEqTransientCache (f : DefEqCache → DefEqCache) : MetaM Unit := + modifyCache fun ⟨c1, c2, c3, c4, c5, defeq, c6, c7, c8, c9⟩ => ⟨c1, c2, c3, c4, c5, f defeq, c6, c7, c8, c9⟩ def getLocalInstances : MetaM LocalInstances := return (← read).localInstances @@ -1601,7 +1605,7 @@ partial def processPostponed (mayPostpone : Bool := true) (exceptionOnFailure := See issue #1102 for an example that triggers an exponential blowup if we don't use this more aggressive form of caching. -/ - modifyDefEqCache fun _ => {} + modifyDefEqTransientCache fun _ => {} let postponed ← getResetPostponed try if (← x) then diff --git a/src/Lean/Meta/ExprDefEq.lean b/src/Lean/Meta/ExprDefEq.lean index 44cdc5014150..2b5718fde182 100644 --- a/src/Lean/Meta/ExprDefEq.lean +++ b/src/Lean/Meta/ExprDefEq.lean @@ -1792,22 +1792,58 @@ private def isExprDefEqExpensive (t : Expr) (s : Expr) : MetaM Bool := do if (← isDefEqUnitLike t s) then return true else isDefEqOnFailure t s -private def mkCacheKey (t : Expr) (s : Expr) : Expr × Expr := - if Expr.quickLt t s then (t, s) else (s, t) +inductive DefEqCacheKind where + | transient -- problem has mvars or is using nonstardard configuration, we should use transient cache + | permReducible | permInst | permDefault | permAll -- problem does not have mvars and we are using stardard config, we can use one persistent cache. + +private def getDefEqCacheKind (t s : Expr) : MetaM DefEqCacheKind := do + if t.hasMVar || s.hasMVar || (← read).canUnfold?.isSome then + return .transient + else match (← getConfig).transparency with + | .default => return .permDefault + | .all => return .permAll + | .reducible => return .permDefault + | .instances => return .permInst -private def getCachedResult (key : Expr × Expr) : MetaM LBool := do - match (← get).cache.defEq.find? key with +/-- +Structure for storing defeq cache key information. +-/ +structure DefEqCacheKeyInfo where + kind : DefEqCacheKind + key : Expr × Expr + +private def mkCacheKey (t s : Expr) : MetaM DefEqCacheKeyInfo := do + let kind ← getDefEqCacheKind t s + let key := if Expr.quickLt t s then (t, s) else (s, t) + return { key, kind } + +private def getCachedResult (keyInfo : DefEqCacheKeyInfo) : MetaM LBool := do + let cache := (← get).cache + let cache := match keyInfo.kind with + | .transient => cache.defEq + | .permDefault => cache.defEqDefault + | .permAll => cache.defEqAll + | .permInst => cache.defEqInstances + | .permReducible => cache.defEqInstances + match cache.find? keyInfo.key with | some val => return val.toLBool | none => return .undef -private def cacheResult (key : Expr × Expr) (result : Bool) : MetaM Unit := do - /- - We must ensure that all assigned metavariables in the key are replaced by their current assignments. - Otherwise, the key is invalid after the assignment is "backtracked". - See issue #1870 for an example. - -/ - let key := (← instantiateMVars key.1, ← instantiateMVars key.2) - modifyDefEqCache fun c => c.insert key result +private def cacheResult (keyInfo : DefEqCacheKeyInfo) (result : Bool) : MetaM Unit := do + let key := keyInfo.key + match keyInfo.kind with + | .permDefault => modify fun s => { s with cache.defEqDefault := s.cache.defEqDefault.insert key result } + | .permAll => modify fun s => { s with cache.defEqAll := s.cache.defEqAll.insert key result } + | .permInst => modify fun s => { s with cache.defEqInstances := s.cache.defEqInstances.insert key result } + | .permReducible => modify fun s => { s with cache.defEqReducible := s.cache.defEqReducible.insert key result } + | .transient => + /- + We must ensure that all assigned metavariables in the key are replaced by their current assignments. + Otherwise, the key is invalid after the assignment is "backtracked". + See issue #1870 for an example. + -/ + let key := (← instantiateMVars key.1, ← instantiateMVars key.2) + modifyDefEqTransientCache fun c => c.insert key result @[export lean_is_expr_def_eq] partial def isExprDefEqAuxImpl (t : Expr) (s : Expr) : MetaM Bool := withIncRecDepth do @@ -1839,7 +1875,7 @@ partial def isExprDefEqAuxImpl (t : Expr) (s : Expr) : MetaM Bool := withIncRecD let t ← instantiateMVars t let s ← instantiateMVars s let numPostponed ← getNumPostponed - let k := mkCacheKey t s + let k ← mkCacheKey t s match (← getCachedResult k) with | .true => trace[Meta.isDefEq.cache] "cache hit 'true' for {t} =?= {s}" From e3b08060d064cba956a9122fde7fb3f1dd5d7723 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 9 Oct 2023 18:20:36 -0700 Subject: [PATCH 63/71] fix: chore add workaround for corrupted cache --- src/Lean/Meta/Basic.lean | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Lean/Meta/Basic.lean b/src/Lean/Meta/Basic.lean index 11c7adc3971e..d1787a192c7d 100644 --- a/src/Lean/Meta/Basic.lean +++ b/src/Lean/Meta/Basic.lean @@ -372,6 +372,9 @@ variable [MonadControlT MetaM n] [Monad n] @[inline] def modifyDefEqTransientCache (f : DefEqCache → DefEqCache) : MetaM Unit := modifyCache fun ⟨c1, c2, c3, c4, c5, defeq, c6, c7, c8, c9⟩ => ⟨c1, c2, c3, c4, c5, f defeq, c6, c7, c8, c9⟩ +@[inline] def resetDefEqPermCaches : MetaM Unit := + modifyCache fun ⟨c1, c2, c3, c4, c5, c6, _, _, _, _⟩ => ⟨c1, c2, c3, c4, c5, c6, {}, {}, {}, {}⟩ + def getLocalInstances : MetaM LocalInstances := return (← read).localInstances @@ -1632,6 +1635,26 @@ def isLevelDefEq (u v : Level) : MetaM Bool := /-- See `isDefEq`. -/ def isExprDefEq (t s : Expr) : MetaM Bool := withReader (fun ctx => { ctx with defEqCtx? := some { lhs := t, rhs := s, lctx := ctx.lctx, localInstances := ctx.localInstances } }) do + /- + The following `resetDefEqPermCaches` is a workaround. Without it the test suite fails, and we probably cannot compile complex libraries such as Mathlib. + TODO: investigate why we need this reset. + Some conjectures: + - It is not enough to check whether `t` and `s` do not contain metavariables. We would need to check the type + of all local variables `t` and `s` depend on. If the local variables contain metavariables, the result of `isDefEq` may change if these + variables are instantiated. + - Related to the previous one: the operation + ```lean + _root_.Lean.MVarId.replaceLocalDeclDefEq (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) + ``` + is probably being misused. We are probably using it to replace a `type` with `typeNew` where these two types + are definitionally equal IFF we can assign the metavariables in `type`. + + Possible fix: always generate new `FVarId`s when update the type of local variables. + Drawback: this operation can be quite expensive, and we must evaluate whether it is worth doing to remove the following `reset`. + + Remark: the kernel does *not* update the type of variables in the local context. + -/ + resetDefEqPermCaches checkpointDefEq (mayPostpone := true) <| Meta.isExprDefEqAux t s /-- From 6d0a3287e056fe02ed7030e12e0e302dcd495656 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Tue, 10 Oct 2023 09:32:47 +0200 Subject: [PATCH 64/71] fix: cache typos --- src/Lean/Meta/ExprDefEq.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lean/Meta/ExprDefEq.lean b/src/Lean/Meta/ExprDefEq.lean index 2b5718fde182..e650b26ad544 100644 --- a/src/Lean/Meta/ExprDefEq.lean +++ b/src/Lean/Meta/ExprDefEq.lean @@ -1802,7 +1802,7 @@ private def getDefEqCacheKind (t s : Expr) : MetaM DefEqCacheKind := do else match (← getConfig).transparency with | .default => return .permDefault | .all => return .permAll - | .reducible => return .permDefault + | .reducible => return .permReducible | .instances => return .permInst /-- @@ -1824,7 +1824,7 @@ private def getCachedResult (keyInfo : DefEqCacheKeyInfo) : MetaM LBool := do | .permDefault => cache.defEqDefault | .permAll => cache.defEqAll | .permInst => cache.defEqInstances - | .permReducible => cache.defEqInstances + | .permReducible => cache.defEqReducible match cache.find? keyInfo.key with | some val => return val.toLBool | none => return .undef From 3bc18797b0559d4f6f9070e94d857a2619aa579d Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 10 Oct 2023 21:05:06 -0700 Subject: [PATCH 65/71] fix: ensure transient cache results for different transparency modes don't mix up --- src/Lean/Meta/Basic.lean | 25 ++++++++++++++--------- src/Lean/Meta/ExprDefEq.lean | 39 +++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/Lean/Meta/Basic.lean b/src/Lean/Meta/Basic.lean index d1787a192c7d..aeecb2b9a147 100644 --- a/src/Lean/Meta/Basic.lean +++ b/src/Lean/Meta/Basic.lean @@ -202,10 +202,15 @@ abbrev FunInfoCache := PersistentHashMap InfoCacheKey FunInfo abbrev WhnfCache := PersistentExprStructMap Expr /-- - A mapping `(s, t) ↦ isDefEq s t`. + A mapping `(s, t) ↦ isDefEq s t` per transparency level. TODO: consider more efficient representations (e.g., a proper set) and caching policies (e.g., imperfect cache). We should also investigate the impact on memory consumption. -/ -abbrev DefEqCache := PersistentHashMap (Expr × Expr) Bool +structure DefEqCache where + reducible : PersistentHashMap (Expr × Expr) Bool := {} + instances : PersistentHashMap (Expr × Expr) Bool := {} + default : PersistentHashMap (Expr × Expr) Bool := {} + all : PersistentHashMap (Expr × Expr) Bool := {} + deriving Inhabited /-- Cache datastructures for type inference, type class resolution, whnf, and definitional equality. @@ -216,11 +221,8 @@ structure Cache where synthInstance : SynthInstanceCache := {} whnfDefault : WhnfCache := {} -- cache for closed terms and `TransparencyMode.default` whnfAll : WhnfCache := {} -- cache for closed terms and `TransparencyMode.all` - defEq : DefEqCache := {} -- transient cache for terms containing mvars and nonstardard configuration options, it is frequently reset. - defEqReducible : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.reducible` - defEqInstances : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.instances` - defEqDefault : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.default` - defEqAll : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.all` + defEqTrans : DefEqCache := {} -- transient cache for terms containing mvars and nonstardard configuration options, it is frequently reset. + defEqPerm : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.reducible` deriving Inhabited /-- @@ -367,13 +369,16 @@ variable [MonadControlT MetaM n] [Monad n] modify fun ⟨mctx, cache, zetaFVarIds, postponed⟩ => ⟨mctx, f cache, zetaFVarIds, postponed⟩ @[inline] def modifyInferTypeCache (f : InferTypeCache → InferTypeCache) : MetaM Unit := - modifyCache fun ⟨ic, c1, c2, c3, c4, c5, c6, c7, c8, c9⟩ => ⟨f ic, c1, c2, c3, c4, c5, c6, c7, c8, c9⟩ + modifyCache fun ⟨ic, c1, c2, c3, c4, c5, c6⟩ => ⟨f ic, c1, c2, c3, c4, c5, c6⟩ @[inline] def modifyDefEqTransientCache (f : DefEqCache → DefEqCache) : MetaM Unit := - modifyCache fun ⟨c1, c2, c3, c4, c5, defeq, c6, c7, c8, c9⟩ => ⟨c1, c2, c3, c4, c5, f defeq, c6, c7, c8, c9⟩ + modifyCache fun ⟨c1, c2, c3, c4, c5, defeqTrans, c6⟩ => ⟨c1, c2, c3, c4, c5, f defeqTrans, c6⟩ + +@[inline] def modifyDefEqPermCache (f : DefEqCache → DefEqCache) : MetaM Unit := + modifyCache fun ⟨c1, c2, c3, c4, c5, c6, defeqPerm⟩ => ⟨c1, c2, c3, c4, c5, c6, f defeqPerm⟩ @[inline] def resetDefEqPermCaches : MetaM Unit := - modifyCache fun ⟨c1, c2, c3, c4, c5, c6, _, _, _, _⟩ => ⟨c1, c2, c3, c4, c5, c6, {}, {}, {}, {}⟩ + modifyDefEqPermCache fun _ => {} def getLocalInstances : MetaM LocalInstances := return (← read).localInstances diff --git a/src/Lean/Meta/ExprDefEq.lean b/src/Lean/Meta/ExprDefEq.lean index e650b26ad544..7549b6aa69e7 100644 --- a/src/Lean/Meta/ExprDefEq.lean +++ b/src/Lean/Meta/ExprDefEq.lean @@ -1794,16 +1794,13 @@ private def isExprDefEqExpensive (t : Expr) (s : Expr) : MetaM Bool := do inductive DefEqCacheKind where | transient -- problem has mvars or is using nonstardard configuration, we should use transient cache - | permReducible | permInst | permDefault | permAll -- problem does not have mvars and we are using stardard config, we can use one persistent cache. + | permanent -- problem does not have mvars and we are using stardard config, we can use one persistent cache. private def getDefEqCacheKind (t s : Expr) : MetaM DefEqCacheKind := do if t.hasMVar || s.hasMVar || (← read).canUnfold?.isSome then return .transient - else match (← getConfig).transparency with - | .default => return .permDefault - | .all => return .permAll - | .reducible => return .permReducible - | .instances => return .permInst + else + return .permanent /-- Structure for storing defeq cache key information. @@ -1818,24 +1815,30 @@ private def mkCacheKey (t s : Expr) : MetaM DefEqCacheKeyInfo := do return { key, kind } private def getCachedResult (keyInfo : DefEqCacheKeyInfo) : MetaM LBool := do - let cache := (← get).cache - let cache := match keyInfo.kind with - | .transient => cache.defEq - | .permDefault => cache.defEqDefault - | .permAll => cache.defEqAll - | .permInst => cache.defEqInstances - | .permReducible => cache.defEqReducible + let cache ← match keyInfo.kind with + | .transient => pure (← get).cache.defEqTrans + | .permanent => pure (← get).cache.defEqPerm + let cache := match (← getTransparency) with + | .reducible => cache.reducible + | .instances => cache.instances + | .default => cache.default + | .all => cache.all match cache.find? keyInfo.key with | some val => return val.toLBool | none => return .undef +def DefEqCache.update (cache : DefEqCache) (mode : TransparencyMode) (key : Expr × Expr) (result : Bool) : DefEqCache := + match mode with + | .reducible => { cache with reducible := cache.reducible.insert key result } + | .instances => { cache with instances := cache.instances.insert key result } + | .default => { cache with default := cache.default.insert key result } + | .all => { cache with all := cache.all.insert key result } + private def cacheResult (keyInfo : DefEqCacheKeyInfo) (result : Bool) : MetaM Unit := do + let mode ← getTransparency let key := keyInfo.key match keyInfo.kind with - | .permDefault => modify fun s => { s with cache.defEqDefault := s.cache.defEqDefault.insert key result } - | .permAll => modify fun s => { s with cache.defEqAll := s.cache.defEqAll.insert key result } - | .permInst => modify fun s => { s with cache.defEqInstances := s.cache.defEqInstances.insert key result } - | .permReducible => modify fun s => { s with cache.defEqReducible := s.cache.defEqReducible.insert key result } + | .permanent => modifyDefEqPermCache fun c => c.update mode key result | .transient => /- We must ensure that all assigned metavariables in the key are replaced by their current assignments. @@ -1843,7 +1846,7 @@ private def cacheResult (keyInfo : DefEqCacheKeyInfo) (result : Bool) : MetaM Un See issue #1870 for an example. -/ let key := (← instantiateMVars key.1, ← instantiateMVars key.2) - modifyDefEqTransientCache fun c => c.insert key result + modifyDefEqTransientCache fun c => c.update mode key result @[export lean_is_expr_def_eq] partial def isExprDefEqAuxImpl (t : Expr) (s : Expr) : MetaM Bool := withIncRecDepth do From 29198371d9e75cdffb91b65ece9ec8ed250a2ba3 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 11 Oct 2023 15:51:11 -0700 Subject: [PATCH 66/71] chore: update comments at src/Lean/Meta/ExprDefEq.lean Co-authored-by: Timo --- src/Lean/Meta/ExprDefEq.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lean/Meta/ExprDefEq.lean b/src/Lean/Meta/ExprDefEq.lean index 7549b6aa69e7..4aa501b0bcf8 100644 --- a/src/Lean/Meta/ExprDefEq.lean +++ b/src/Lean/Meta/ExprDefEq.lean @@ -1793,8 +1793,8 @@ private def isExprDefEqExpensive (t : Expr) (s : Expr) : MetaM Bool := do isDefEqOnFailure t s inductive DefEqCacheKind where - | transient -- problem has mvars or is using nonstardard configuration, we should use transient cache - | permanent -- problem does not have mvars and we are using stardard config, we can use one persistent cache. + | transient -- problem has mvars or is using nonstandard configuration, we should use transient cache + | permanent -- problem does not have mvars and we are using standard config, we can use one persistent cache. private def getDefEqCacheKind (t s : Expr) : MetaM DefEqCacheKind := do if t.hasMVar || s.hasMVar || (← read).canUnfold?.isSome then From b8af36fba09ed866e0541083973a4f870a32fe0e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 11 Oct 2023 15:51:40 -0700 Subject: [PATCH 67/71] chore: update comments at src/Lean/Meta/Basic.lean Co-authored-by: Timo --- src/Lean/Meta/Basic.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lean/Meta/Basic.lean b/src/Lean/Meta/Basic.lean index aeecb2b9a147..84a759cfcc51 100644 --- a/src/Lean/Meta/Basic.lean +++ b/src/Lean/Meta/Basic.lean @@ -221,8 +221,8 @@ structure Cache where synthInstance : SynthInstanceCache := {} whnfDefault : WhnfCache := {} -- cache for closed terms and `TransparencyMode.default` whnfAll : WhnfCache := {} -- cache for closed terms and `TransparencyMode.all` - defEqTrans : DefEqCache := {} -- transient cache for terms containing mvars and nonstardard configuration options, it is frequently reset. - defEqPerm : DefEqCache := {} -- permanent cache for terms not containing mvars and `TransparencyMode.reducible` + defEqTrans : DefEqCache := {} -- transient cache for terms containing mvars or using nonstandard configuration options, it is frequently reset. + defEqPerm : DefEqCache := {} -- permanent cache for terms not containing mvars and using standard configuration options deriving Inhabited /-- From 6df09d16e5f04d1b4118437c56e0aa302a20b554 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 14 Oct 2023 17:20:54 +0000 Subject: [PATCH 68/71] doc: update changelog --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 84c95fd56db3..f1e7fccccf8e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,6 +10,8 @@ Please check the [releases](https://github.com/leanprover/lean4/releases) page f v4.3.0 (development in progress) --------- +* [isDefEq cache for terms not containing metavariables.](https://github.com/leanprover/lean4/pull/2644). + * [Cancel outstanding tasks on document edit in the language server](https://github.com/leanprover/lean4/pull/2648). * `IO.Process.output` no longer inherits the standard input of the caller. From 66ab016723adf233f0c511e2e82cd5884d740614 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Sun, 15 Oct 2023 12:12:10 +1100 Subject: [PATCH 69/71] =?UTF-8?q?chore:=20simp=20tracing=20reports=20?= =?UTF-8?q?=E2=86=90=20(#2621)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: simp tracing reports ← --------- Co-authored-by: Mario Carneiro --- src/Lean/Elab/Tactic/Simp.lean | 11 +++++++---- src/Lean/Meta/Tactic/Simp/SimpTheorems.lean | 10 +++++----- tests/lean/simp_trace.lean | 8 ++++++++ tests/lean/simp_trace.lean.expected.out | 5 +++++ 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/Lean/Elab/Tactic/Simp.lean b/src/Lean/Elab/Tactic/Simp.lean index 79c46e2ebc86..3529e1d5f923 100644 --- a/src/Lean/Elab/Tactic/Simp.lean +++ b/src/Lean/Elab/Tactic/Simp.lean @@ -138,7 +138,7 @@ def elabSimpArgs (stx : Syntax) (ctx : Simp.Context) (eraseLocal : Bool) (kind : /- syntax simpPre := "↓" syntax simpPost := "↑" - syntax simpLemma := (simpPre <|> simpPost)? term + syntax simpLemma := (simpPre <|> simpPost)? "← "? term syntax simpErase := "-" ident -/ @@ -259,9 +259,12 @@ def traceSimpCall (stx : Syntax) (usedSimps : UsedSimps) : MetaM Unit := do let env ← getEnv for (thm, _) in usedSimps.toArray.qsort (·.2 < ·.2) do match thm with - | .decl declName => -- global definitions in the environment - if env.contains declName && !simpOnlyBuiltins.contains declName then - args := args.push (← `(Parser.Tactic.simpLemma| $(mkIdent (← unresolveNameGlobal declName)):ident)) + | .decl declName inv => -- global definitions in the environment + if env.contains declName && (inv || !simpOnlyBuiltins.contains declName) then + args := args.push (if inv then + (← `(Parser.Tactic.simpLemma| ← $(mkIdent (← unresolveNameGlobal declName)):ident)) + else + (← `(Parser.Tactic.simpLemma| $(mkIdent (← unresolveNameGlobal declName)):ident))) | .fvar fvarId => -- local hypotheses in the context if let some ldecl := lctx.find? fvarId then localsOrStar := localsOrStar.bind fun locals => diff --git a/src/Lean/Meta/Tactic/Simp/SimpTheorems.lean b/src/Lean/Meta/Tactic/Simp/SimpTheorems.lean index 7921193c44e1..77444359e0d2 100644 --- a/src/Lean/Meta/Tactic/Simp/SimpTheorems.lean +++ b/src/Lean/Meta/Tactic/Simp/SimpTheorems.lean @@ -18,7 +18,7 @@ what action the user took which lead to this theorem existing in the simp set. -/ inductive Origin where /-- A global declaration in the environment. -/ - | decl (declName : Name) + | decl (declName : Name) (inv := false) /-- A local hypothesis. When `contextual := true` is enabled, this fvar may exist in an extension @@ -42,7 +42,7 @@ inductive Origin where /-- A unique identifier corresponding to the origin. -/ def Origin.key : Origin → Name - | .decl declName => declName + | .decl declName _ => declName | .fvar fvarId => fvarId.name | .stx id _ => id | .other name => name @@ -136,7 +136,7 @@ instance : ToFormat SimpTheorem where name ++ prio ++ perm def ppOrigin [Monad m] [MonadEnv m] [MonadError m] : Origin → m MessageData - | .decl n => mkConstWithLevelParams n + | .decl n inv => do let r ← mkConstWithLevelParams n; if inv then return m!"← {r}" else return r | .fvar n => return mkFVar n | .stx _ ref => return ref | .other n => return n @@ -318,7 +318,7 @@ private def mkSimpTheoremsFromConst (declName : Name) (post : Bool) (inv : Bool) let mut r := #[] for (val, type) in (← preprocess val type inv (isGlobal := true)) do let auxName ← mkAuxLemma cinfo.levelParams type val - r := r.push <| (← mkSimpTheoremCore (.decl declName) (mkConst auxName (cinfo.levelParams.map mkLevelParam)) #[] (mkConst auxName) post prio) + r := r.push <| (← mkSimpTheoremCore (.decl declName inv) (mkConst auxName (cinfo.levelParams.map mkLevelParam)) #[] (mkConst auxName) post prio) return r else return #[← mkSimpTheoremCore (.decl declName) (mkConst declName (cinfo.levelParams.map mkLevelParam)) #[] (mkConst declName) post prio] @@ -403,7 +403,7 @@ def getSimpTheorems : CoreM SimpTheorems := /-- Auxiliary method for adding a global declaration to a `SimpTheorems` datastructure. -/ def SimpTheorems.addConst (s : SimpTheorems) (declName : Name) (post := true) (inv := false) (prio : Nat := eval_prio default) : MetaM SimpTheorems := do - let s := { s with erased := s.erased.erase (.decl declName) } + let s := { s with erased := s.erased.erase (.decl declName inv) } let simpThms ← mkSimpTheoremsFromConst declName post inv prio return simpThms.foldl addSimpTheoremEntry s diff --git a/tests/lean/simp_trace.lean b/tests/lean/simp_trace.lean index d9a442be541c..54cb70de899c 100644 --- a/tests/lean/simp_trace.lean +++ b/tests/lean/simp_trace.lean @@ -126,3 +126,11 @@ instance : HasProp Nat where example : HasProp.toProp 0 := by simp [HasProp.toProp] + +example (P Q : Prop) (h : P ↔ Q) (p : P) : Q := by + simp [← h] + exact p + +theorem my_thm' : a ↔ a ∧ a := my_thm.symm + +example (P : Prop) : P ∧ P ↔ P := by simp only [← my_thm'] diff --git a/tests/lean/simp_trace.lean.expected.out b/tests/lean/simp_trace.lean.expected.out index 2c33d3740a92..4e66a9dad0f3 100644 --- a/tests/lean/simp_trace.lean.expected.out +++ b/tests/lean/simp_trace.lean.expected.out @@ -115,3 +115,8 @@ Try this: simp only [bla, h] at * | Sum.inr val => 0 [Meta.Tactic.simp.rewrite] unfold h, h x ==> Sum.inl (x, x) Try this: simp only [HasProp.toProp] +Try this: simp only [← h] +[Meta.Tactic.simp.rewrite] ← h:1000, Q ==> P +Try this: simp only [← my_thm'] +[Meta.Tactic.simp.rewrite] ← @my_thm':1000, P ∧ P ==> P +[Meta.Tactic.simp.rewrite] iff_self:1000, P ↔ P ==> True From 1e74c6a348416677987cd71a59a451db0aef9e26 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Sun, 15 Oct 2023 13:49:41 +1100 Subject: [PATCH 70/71] feat: use nat_gcd in the kernel (#2533) * feat: use nat_gcd in the kernel --------- Co-authored-by: Sebastian Ullrich --- src/Lean/Meta/WHNF.lean | 2 + src/kernel/type_checker.cpp | 5 +++ src/runtime/object.h | 1 + tests/lean/run/lean_nat_gcd.lean | 67 ++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 tests/lean/run/lean_nat_gcd.lean diff --git a/src/Lean/Meta/WHNF.lean b/src/Lean/Meta/WHNF.lean index 5ae44c8acec9..baab85120347 100644 --- a/src/Lean/Meta/WHNF.lean +++ b/src/Lean/Meta/WHNF.lean @@ -823,6 +823,8 @@ def reduceNat? (e : Expr) : MetaM (Option Expr) := else if fn == ``Nat.mul then reduceBinNatOp Nat.mul a1 a2 else if fn == ``Nat.div then reduceBinNatOp Nat.div a1 a2 else if fn == ``Nat.mod then reduceBinNatOp Nat.mod a1 a2 + else if fn == ``Nat.pow then reduceBinNatOp Nat.pow a1 a2 + else if fn == ``Nat.gcd then reduceBinNatOp Nat.gcd a1 a2 else if fn == ``Nat.beq then reduceBinNatPred Nat.beq a1 a2 else if fn == ``Nat.ble then reduceBinNatPred Nat.ble a1 a2 else return none diff --git a/src/kernel/type_checker.cpp b/src/kernel/type_checker.cpp index 6ba0b00dbf40..4c8d8f2d60f7 100644 --- a/src/kernel/type_checker.cpp +++ b/src/kernel/type_checker.cpp @@ -30,6 +30,7 @@ static expr * g_nat_add = nullptr; static expr * g_nat_sub = nullptr; static expr * g_nat_mul = nullptr; static expr * g_nat_pow = nullptr; +static expr * g_nat_gcd = nullptr; static expr * g_nat_mod = nullptr; static expr * g_nat_div = nullptr; static expr * g_nat_beq = nullptr; @@ -603,6 +604,7 @@ optional type_checker::reduce_nat(expr const & e) { if (f == *g_nat_sub) return reduce_bin_nat_op(nat_sub, e); if (f == *g_nat_mul) return reduce_bin_nat_op(nat_mul, e); if (f == *g_nat_pow) return reduce_bin_nat_op(nat_pow, e); + if (f == *g_nat_gcd) return reduce_bin_nat_op(nat_gcd, e); if (f == *g_nat_mod) return reduce_bin_nat_op(nat_mod, e); if (f == *g_nat_div) return reduce_bin_nat_op(nat_div, e); if (f == *g_nat_beq) return reduce_bin_nat_pred(nat_eq, e); @@ -1151,6 +1153,8 @@ void initialize_type_checker() { mark_persistent(g_nat_mul->raw()); g_nat_pow = new expr(mk_constant(name{"Nat", "pow"})); mark_persistent(g_nat_pow->raw()); + g_nat_gcd = new expr(mk_constant(name{"Nat", "gcd"})); + mark_persistent(g_nat_gcd->raw()); g_nat_div = new expr(mk_constant(name{"Nat", "div"})); mark_persistent(g_nat_div->raw()); g_nat_mod = new expr(mk_constant(name{"Nat", "mod"})); @@ -1177,6 +1181,7 @@ void finalize_type_checker() { delete g_nat_sub; delete g_nat_mul; delete g_nat_pow; + delete g_nat_gcd; delete g_nat_div; delete g_nat_mod; delete g_nat_beq; diff --git a/src/runtime/object.h b/src/runtime/object.h index 83e19e21034b..9a057383e3dd 100644 --- a/src/runtime/object.h +++ b/src/runtime/object.h @@ -325,6 +325,7 @@ inline obj_res nat_add(b_obj_arg a1, b_obj_arg a2) { return lean_nat_add(a1, a2) inline obj_res nat_sub(b_obj_arg a1, b_obj_arg a2) { return lean_nat_sub(a1, a2); } inline obj_res nat_mul(b_obj_arg a1, b_obj_arg a2) { return lean_nat_mul(a1, a2); } inline obj_res nat_pow(b_obj_arg a1, b_obj_arg a2) { return lean_nat_pow(a1, a2); } +inline obj_res nat_gcd(b_obj_arg a1, b_obj_arg a2) { return lean_nat_gcd(a1, a2); } inline obj_res nat_div(b_obj_arg a1, b_obj_arg a2) { return lean_nat_div(a1, a2); } inline obj_res nat_mod(b_obj_arg a1, b_obj_arg a2) { return lean_nat_mod(a1, a2); } inline bool nat_eq(b_obj_arg a1, b_obj_arg a2) { return lean_nat_eq(a1, a2); } diff --git a/tests/lean/run/lean_nat_gcd.lean b/tests/lean/run/lean_nat_gcd.lean new file mode 100644 index 000000000000..cb91e6e53cb7 --- /dev/null +++ b/tests/lean/run/lean_nat_gcd.lean @@ -0,0 +1,67 @@ +import Lean + +/-! Basic tests, including edge cases. -/ +example : Nat.gcd 0 0 = 0 := rfl +example : Nat.gcd 0 1 = 1 := rfl +example : Nat.gcd 0 17 = 17 := rfl +example : Nat.gcd 1 0 = 1 := rfl +example : Nat.gcd 17 0 = 17 := rfl +example : Nat.gcd 1 1 = 1 := rfl +example : Nat.gcd 1 17 = 1 := rfl +example : Nat.gcd 17 1 = 1 := rfl +example : Nat.gcd 2 2 = 2 := rfl +example : Nat.gcd 2 3 = 1 := rfl +example : Nat.gcd 2 4 = 2 := rfl +example : Nat.gcd 9 6 = 3 := rfl + +/-! +We check that `Nat.gcd` is evaluated using bignum functions in the kernel. + +Because of variations in run time on different operating systems during CI, +for the larger calculations we don't attempt to do any timing. + +All of the "large" calculations below used to fail with +``` +maximum recursion depth has been reached (use `set_option maxRecDepth ` to increase limit) +``` +prior to lean4#2533. +-/ + +open Lean Elab Command in +elab "#fast" c:command : command => do + let start ← IO.monoMsNow + elabCommand c + let elapsed := (← IO.monoMsNow) - start + if elapsed > 1000 then throwError m!"Too slow! {elapsed}ms" + +-- Used to take ~1500ms, now takes ~3ms. +#fast example : Nat.gcd 45 (Nat.gcd 15 85) = 5 := rfl + +example : Nat.gcd (115249 * 180811) (115249*181081) = 115249 := rfl + +/-- Mersenne primes. -/ +def m (p : Nat) := 2^p - 1 + +/-- Largish primes, targeting <100ms GCD calculations. -/ +def p_29 := 110503 +def p_30 := 132049 +def p_31 := 216091 +def p_32 := 756839 +def p_33 := 859433 + +/- GCD with large prime factors on one side, and small primes on the other. -/ +example : Nat.gcd (p_29 * p_30 * p_31 * p_32 * p_33) 2^(2^20) = 1 := rfl +/- GCD with two prime factors on both sides, including one in common. -/ +example : Nat.gcd (m p_31 * m p_33) (m p_32 * m p_33) - m p_33 = 0 := rfl +/- GCD with many small prime factors. -/ +example : + Nat.gcd (2^1 * 3^1 * 5^2 * 7^3 * 11^5 * 13^8) (2^8 * 3^5 * 5^3 * 7^2 * 11^1 * 13^1) = + 2 * 3 * 5^2 * 7^2 * 11 * 13 := rfl + +-- #eval Lean.maxSmallNat -- 9223372036854775807 +def maxSmallNat := 9223372036854775807 + +example : maxSmallNat = 7^2 * 73 * 127 * 337 * 92737 * 649657 := rfl +-- Calculate GCDs of numbers on either side of `maxSmallNat`. +example : Nat.gcd (maxSmallNat - 92737) (maxSmallNat + 92737) = 185474 := rfl +example : Nat.gcd (maxSmallNat / 649657) (maxSmallNat * 649657) = 14197294936951 := rfl From 3e79ddda27c299a0e66fc996d52fa15fcf4421d8 Mon Sep 17 00:00:00 2001 From: Scott Morrison Date: Sun, 15 Oct 2023 13:51:58 +1100 Subject: [PATCH 71/71] chore: add items to RELEASES.md (#2687) --- RELEASES.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index f1e7fccccf8e..d9de53dbd545 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -11,10 +11,11 @@ v4.3.0 (development in progress) --------- * [isDefEq cache for terms not containing metavariables.](https://github.com/leanprover/lean4/pull/2644). - * [Cancel outstanding tasks on document edit in the language server](https://github.com/leanprover/lean4/pull/2648). - +* Make [`Environment.mk`](https://github.com/leanprover/lean4/pull/2604) and [`Environment.add`](https://github.com/leanprover/lean4/pull/2642) private, and add [`replay`](https://github.com/leanprover/lean4/pull/2617) as a safer alternative. * `IO.Process.output` no longer inherits the standard input of the caller. +* [Do not inhibit caching](https://github.com/leanprover/lean4/pull/2612) of default-level `match` reduction. +* [List the valid case tags](https://github.com/leanprover/lean4/pull/2629) when the user writes an invalid one. * The derive handler for `DecidableEq` [now handles](https://github.com/leanprover/lean4/pull/2591) mutual inductive types. * [Show path of failed import in Lake](https://github.com/leanprover/lean4/pull/2616). * [Fix linker warnings on macOS](https://github.com/leanprover/lean4/pull/2598).