Skip to content

Commit 54c12df

Browse files
authored
refactor: environment extension state splitting (#8653)
Replaces the previous `export/saveEntriesFn` split with a stricly more general function such that `exportEntriesFn` could be deprecated at a later point. Also gives the new function access to the `Environment` while we're at it. Also gives `getModuleEntries` access to more olean levels in preparation for `meta import`.
1 parent 01a0524 commit 54c12df

File tree

6 files changed

+84
-59
lines changed

6 files changed

+84
-59
lines changed

src/Lean/DeclarationRange.lean

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ namespace Lean
1515

1616
builtin_initialize builtinDeclRanges : IO.Ref (NameMap DeclarationRanges) ← IO.mkRef {}
1717
builtin_initialize declRangeExt : MapDeclarationExtension DeclarationRanges ←
18-
mkMapDeclarationExtension (exportEntriesFn := fun _ => #[])
18+
mkMapDeclarationExtension (exportEntriesFn := fun _ s level =>
19+
if level < .server then
20+
#[]
21+
else s.toArray)
1922

2023
def addBuiltinDeclarationRanges (declName : Name) (declRanges : DeclarationRanges) : IO Unit :=
2124
builtinDeclRanges.modify (·.insert declName declRanges)
@@ -24,7 +27,7 @@ def addDeclarationRanges [Monad m] [MonadEnv m] (declName : Name) (declRanges :
2427
modifyEnv fun env => declRangeExt.insert env declName declRanges
2528

2629
def findDeclarationRangesCore? [Monad m] [MonadEnv m] (declName : Name) : m (Option DeclarationRanges) :=
27-
return declRangeExt.find? (includeServer := true) (← getEnv) declName
30+
return declRangeExt.find? (level := .server) (← getEnv) declName
2831

2932
def findDeclarationRanges? [Monad m] [MonadEnv m] [MonadLiftT BaseIO m] (declName : Name) : m (Option DeclarationRanges) := do
3033
let env ← getEnv

src/Lean/DocString/Extension.lean

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ structure ModuleDoc where
5858
private builtin_initialize moduleDocExt : SimplePersistentEnvExtension ModuleDoc (PersistentArray ModuleDoc) ← registerSimplePersistentEnvExtension {
5959
addImportedFn := fun _ => {}
6060
addEntryFn := fun s e => s.push e
61-
toArrayFn := fun es => es.toArray
62-
exported := false
61+
exportEntriesFnEx? := some fun _ _ es => fun
62+
| .exported => #[]
63+
| _ => es.toArray
6364
}
6465

6566
def addMainModuleDoc (env : Environment) (doc : ModuleDoc) : Environment :=
@@ -70,7 +71,7 @@ def getMainModuleDoc (env : Environment) : PersistentArray ModuleDoc :=
7071

7172
def getModuleDoc? (env : Environment) (moduleName : Name) : Option (Array ModuleDoc) :=
7273
env.getModuleIdx? moduleName |>.map fun modIdx =>
73-
moduleDocExt.getModuleEntries (includeServer := true) env modIdx
74+
moduleDocExt.getModuleEntries (level := .server) env modIdx
7475

7576
def getDocStringText [Monad m] [MonadError m] (stx : TSyntax `Lean.Parser.Command.docComment) : m String :=
7677
match stx.raw[1] with

src/Lean/Elab/RecommendedSpelling.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ open Lean.Parser.Command
2828
def allRecommendedSpellings : MetaM (Array RecommendedSpelling) := do
2929
let all := recommendedSpellingExt.toEnvExtension.getState (← getEnv)
3030
|>.importedEntries
31-
|>.push (recommendedSpellingExt.exportEntriesFn (recommendedSpellingExt.getState (← getEnv)))
31+
|>.push (recommendedSpellingExt.exportEntriesFn (← getEnv) (recommendedSpellingExt.getState (← getEnv)) .exported)
3232
return all.flatMap id
3333

3434
end Lean.Elab.Term.Doc

src/Lean/Elab/Tactic/Doc.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ Displays all available tactic tags, with documentation.
9898
@[builtin_command_elab printTacTags] def elabPrintTacTags : CommandElab := fun _stx => do
9999
let all :=
100100
tacticTagExt.toEnvExtension.getState (← getEnv)
101-
|>.importedEntries |>.push (tacticTagExt.exportEntriesFn (tacticTagExt.getState (← getEnv)))
101+
|>.importedEntries |>.push (tacticTagExt.exportEntriesFn (← getEnv) (tacticTagExt.getState (← getEnv)) .exported)
102102
let mut mapping : NameMap NameSet := {}
103103
for arr in all do
104104
for (tac, tag) in arr do
@@ -148,7 +148,7 @@ def allTacticDocs : MetaM (Array TacticDoc) := do
148148
let env ← getEnv
149149
let all :=
150150
tacticTagExt.toEnvExtension.getState (← getEnv)
151-
|>.importedEntries |>.push (tacticTagExt.exportEntriesFn (tacticTagExt.getState (← getEnv)))
151+
|>.importedEntries |>.push (tacticTagExt.exportEntriesFn (← getEnv) (tacticTagExt.getState (← getEnv)) .exported)
152152
let mut tacTags : NameMap NameSet := {}
153153
for arr in all do
154154
for (tac, tag) in arr do

src/Lean/EnvExtension.lean

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,10 @@ structure SimplePersistentEnvExtensionDescr (α σ : Type) where
2121
addEntryFn : σ → α → σ
2222
addImportedFn : Array (Array α) → σ
2323
toArrayFn : List α → Array α := fun es => es.toArray
24+
exportEntriesFnEx? :
25+
Option (Environment → σ → List α → OLeanLevel → Array α) := none
2426
asyncMode : EnvExtension.AsyncMode := .mainOnly
2527
replay? : Option ((newEntries : List α) → (newState : σ) → σ → List α × σ) := none
26-
/--
27-
Whether entries should be imported into other modules. Entries are always accessible in the
28-
language server via `getModuleEntries (includeServer := true)`.
29-
-/
30-
exported : Bool := true
3128

3229
/--
3330
Returns a function suitable for `SimplePersistentEnvExtensionDescr.replay?` that replays all new
@@ -47,8 +44,9 @@ def registerSimplePersistentEnvExtension {α σ : Type} [Inhabited σ] (descr :
4744
addImportedFn := fun as => pure ([], descr.addImportedFn as),
4845
addEntryFn := fun s e => match s with
4946
| (entries, s) => (e::entries, descr.addEntryFn s e),
50-
exportEntriesFn := fun s => if descr.exported then descr.toArrayFn s.1.reverse else #[],
51-
saveEntriesFn := fun s => descr.toArrayFn s.1.reverse,
47+
exportEntriesFnEx env s level := match descr.exportEntriesFnEx? with
48+
| some fn => fn env s.2 s.1.reverse level
49+
| none => descr.toArrayFn s.1.reverse
5250
statsFn := fun s => format "number of local entries: " ++ format s.1.length
5351
asyncMode := descr.asyncMode
5452
replay? := descr.replay?.map fun replay oldState newState _ (entries, s) =>
@@ -129,14 +127,15 @@ structure MapDeclarationExtension (α : Type) extends PersistentEnvExtension (Na
129127
deriving Inhabited
130128

131129
def mkMapDeclarationExtension (name : Name := by exact decl_name%)
132-
(exportEntriesFn : NameMap α → Array (Name × α) := (·.toArray)) : IO (MapDeclarationExtension α) :=
130+
(exportEntriesFn : Environment → NameMap α → OLeanLevel → Array (Name × α) :=
131+
fun _ s _ => s.toArray) :
132+
IO (MapDeclarationExtension α) :=
133133
.mk <$> registerPersistentEnvExtension {
134134
name := name,
135135
mkInitial := pure {}
136136
addImportedFn := fun _ => pure {}
137137
addEntryFn := fun s (n, v) => s.insert n v
138-
saveEntriesFn := fun s => s.toArray
139-
exportEntriesFn
138+
exportEntriesFnEx env s level := exportEntriesFn env s level
140139
asyncMode := .async
141140
replay? := some fun _ newState newConsts s =>
142141
newConsts.foldl (init := s) fun s c =>
@@ -156,10 +155,10 @@ def insert (ext : MapDeclarationExtension α) (env : Environment) (declName : Na
156155
ext.addEntry env (declName, val)
157156

158157
def find? [Inhabited α] (ext : MapDeclarationExtension α) (env : Environment) (declName : Name)
159-
(includeServer := false) : Option α :=
158+
(level := OLeanLevel.exported) : Option α :=
160159
match env.getModuleIdxFor? declName with
161160
| some modIdx =>
162-
match (ext.getModuleEntries (includeServer := includeServer) env modIdx).binSearch (declName, default) (fun a b => Name.quickLt a.1 b.1) with
161+
match (ext.getModuleEntries (level := level) env modIdx).binSearch (declName, default) (fun a b => Name.quickLt a.1 b.1) with
163162
| some e => some e.2
164163
| none => none
165164
| none => (ext.findStateAsync env declName).find? declName

src/Lean/Environment.lean

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ structure Environment where
528528
/--
529529
Additional imported environment extension state for use in the language server. This field is
530530
identical to `base.extensions` in other contexts. Access via
531-
`getModuleEntries (includeServer := true)`.
531+
`getModuleEntries (level := .server)`.
532532
-/
533533
private serverBaseExts : Array EnvExtensionState := base.private.extensions
534534
/--
@@ -1457,6 +1457,19 @@ structure ImportM.Context where
14571457

14581458
abbrev ImportM := ReaderT Lean.ImportM.Context IO
14591459

1460+
/-- The level of information to save/load. Each level includes all previous ones. -/
1461+
inductive OLeanLevel where
1462+
/-- Information from exported contexts. -/
1463+
| exported
1464+
/-- Environment extension state for the language server. -/
1465+
| server
1466+
/-- Private module data. -/
1467+
| «private»
1468+
deriving DecidableEq, Ord, Repr
1469+
1470+
instance : LE OLeanLevel := leOfOrd
1471+
instance : LT OLeanLevel := ltOfOrd
1472+
14601473
/--
14611474
An environment extension with support for storing/retrieving entries from a .olean file.
14621475
- α is the type of the entries that are stored in .olean files.
@@ -1507,15 +1520,17 @@ structure PersistentEnvExtension (α : Type) (β : Type) (σ : Type) where
15071520
name : Name
15081521
addImportedFn : Array (Array α) → ImportM σ
15091522
addEntryFn : σ → β → σ
1510-
/-- Function to transform state into data that should always be imported into other modules. -/
1511-
exportEntriesFn : σ → Array α
15121523
/--
1513-
Function to transform state into data that should be imported into other modules when the module
1514-
system is disabled. When it is enabled, the data is loaded only in the language server and
1515-
accessible via `getModuleEntries (includeServer := true)`. Conventionally, this is a superset of
1516-
the data returned by `exportEntriesFn`.
1524+
Function to transform state into data that should be imported into other modules. When using the
1525+
module system without `import all`, `OLeanLevel.exported` is imported, else `OLeanLevel.private`.
1526+
Additionally, when using the module system in the language server, the `OLeanLevel.server` data is
1527+
accessible via `getModuleEntries (level := .server)`. By convention, each level should include all
1528+
data of previous levels.
1529+
1530+
This function is run after elaborating the file and joining all asynchronous threads. It is run
1531+
once for each level when the module system is enabled, otherwise once for `private`.
15171532
-/
1518-
saveEntriesFn : σ → Array α
1533+
exportEntriesFn : Environment → σ → OLeanLevel → Array α
15191534
statsFn : σ → Format
15201535

15211536
instance {α σ} [Inhabited σ] : Inhabited (PersistentEnvExtensionState α σ) :=
@@ -1527,20 +1542,21 @@ instance {α β σ} [Inhabited σ] : Inhabited (PersistentEnvExtension α β σ)
15271542
name := default,
15281543
addImportedFn := fun _ => default,
15291544
addEntryFn := fun s _ => s,
1530-
exportEntriesFn := fun _ => #[],
1531-
saveEntriesFn := fun _ => #[],
1545+
exportEntriesFn := fun _ _ _ => #[],
15321546
statsFn := fun _ => Format.nil
15331547
}
15341548

15351549
namespace PersistentEnvExtension
15361550

15371551
/--
1538-
Returns the data saved by `ext.exportEntriesFn/saveEntriesFn` when `m` was elaborated. See docs on
1539-
the functions for details.
1552+
Returns the data saved by `ext.exportEntriesFn` when `m` was elaborated. See docs on the function for
1553+
details. When using the module system, `level` can be used to select the level of data to retrieve,
1554+
but is limited to the maximum level actually imported: `exported` on the cmdline and `server` in the
1555+
language server. Higher levels will return the data of the maximum imported level.
15401556
-/
15411557
def getModuleEntries {α β σ : Type} [Inhabited σ] (ext : PersistentEnvExtension α β σ)
1542-
(env : Environment) (m : ModuleIdx) (includeServer := false) : Array α :=
1543-
let exts := if includeServer then env.serverBaseExts else env.base.private.extensions
1558+
(env : Environment) (m : ModuleIdx) (level := OLeanLevel.exported) : Array α :=
1559+
let exts := if level = .exported then env.base.private.extensions else env.serverBaseExts
15441560
-- safety: as in `getStateUnsafe`
15451561
unsafe (ext.toEnvExtension.getStateImpl exts).importedEntries[m]!
15461562

@@ -1573,19 +1589,36 @@ end PersistentEnvExtension
15731589

15741590
builtin_initialize persistentEnvExtensionsRef : IO.Ref (Array (PersistentEnvExtension EnvExtensionEntry EnvExtensionEntry EnvExtensionState)) ← IO.mkRef #[]
15751591

1576-
structure PersistentEnvExtensionDescr (α β σ : Type) where
1577-
name : Name := by exact decl_name%
1578-
mkInitial : IO σ
1579-
addImportedFn : Array (Array α) → ImportM σ
1580-
addEntryFn : σ → β → σ
1581-
exportEntriesFn : σ → Array α
1582-
saveEntriesFn : σ → Array α := exportEntriesFn
1583-
statsFn : σ → Format := fun _ => Format.nil
1584-
asyncMode : EnvExtension.AsyncMode := .mainOnly
1585-
replay? : Option (ReplayFn σ) := none
1592+
-- Helper structure to enable cyclic default values of `exportEntriesFn` and `exportEntriesFnEx`.
1593+
structure PersistentEnvExtensionDescrCore (α β σ : Type) where
1594+
name : Name := by exact decl_name%
1595+
mkInitial : IO σ
1596+
addImportedFn : Array (Array α) → ImportM σ
1597+
addEntryFn : σ → β → σ
1598+
exportEntriesFnEx : Environment → σ → OLeanLevel → Array α
1599+
statsFn : σ → Format := fun _ => Format.nil
1600+
asyncMode : EnvExtension.AsyncMode := .mainOnly
1601+
replay? : Option (ReplayFn σ) := none
15861602

1587-
attribute [inherit_doc PersistentEnvExtension.exportEntriesFn] PersistentEnvExtensionDescr.exportEntriesFn
1588-
attribute [inherit_doc PersistentEnvExtension.saveEntriesFn] PersistentEnvExtensionDescr.saveEntriesFn
1603+
attribute [inherit_doc PersistentEnvExtension.exportEntriesFn]
1604+
PersistentEnvExtensionDescrCore.exportEntriesFnEx
1605+
1606+
/--
1607+
Auxiliary function to signal to the structure instance elaborator that `default` should be used as
1608+
the default value for a field but only if `_otherField` has been given, which is added as an
1609+
artifical dependency.
1610+
-/
1611+
def useDefaultIfOtherFieldGiven (default : α) (_otherField : β) : α :=
1612+
default
1613+
1614+
structure PersistentEnvExtensionDescr (α β σ : Type) extends PersistentEnvExtensionDescrCore α β σ where
1615+
-- The cyclic default values force the user to specify at least one of the two following fields.
1616+
/--
1617+
Obsolete simpler version of `exportEntriesFnEx`. Its value is ignored if the latter is also
1618+
specified.
1619+
-/
1620+
exportEntriesFn : σ → Array α := useDefaultIfOtherFieldGiven (fun _ => #[]) exportEntriesFnEx
1621+
exportEntriesFnEx := fun _ s _ => exportEntriesFn s
15891622

15901623
unsafe def registerPersistentEnvExtensionUnsafe {α β σ : Type} [Inhabited σ] (descr : PersistentEnvExtensionDescr α β σ) : IO (PersistentEnvExtension α β σ) := do
15911624
let pExts ← persistentEnvExtensionsRef.get
@@ -1604,8 +1637,7 @@ unsafe def registerPersistentEnvExtensionUnsafe {α β σ : Type} [Inhabited σ]
16041637
name := descr.name,
16051638
addImportedFn := descr.addImportedFn,
16061639
addEntryFn := descr.addEntryFn,
1607-
exportEntriesFn := descr.exportEntriesFn,
1608-
saveEntriesFn := descr.saveEntriesFn,
1640+
exportEntriesFn := descr.exportEntriesFnEx,
16091641
statsFn := descr.statsFn
16101642
}
16111643
persistentEnvExtensionsRef.modify fun pExts => pExts.push (unsafeCast pExt)
@@ -1661,16 +1693,6 @@ unsafe def Environment.freeRegions (env : Environment) : IO Unit :=
16611693
TODO: statically check for this. -/
16621694
env.header.regions.forM CompactedRegion.free
16631695

1664-
/-- The level of information to save/load. Each level includes all previous ones. -/
1665-
inductive OLeanLevel where
1666-
/-- Information from exported contexts. -/
1667-
| exported
1668-
/-- Environment extension state for the language server. -/
1669-
| server
1670-
/-- Private module data. -/
1671-
| «private»
1672-
deriving DecidableEq
1673-
16741696
def OLeanLevel.adjustFileName (base : System.FilePath) : OLeanLevel → System.FilePath
16751697
| .exported => base
16761698
| .server => base.addExtension "server"
@@ -1688,7 +1710,7 @@ def mkModuleData (env : Environment) (level : OLeanLevel := .private) : IO Modul
16881710
if asyncMode matches .async then
16891711
asyncMode := .sync
16901712
let state := pExt.getState (asyncMode := asyncMode) env
1691-
(pExt.name, if level = .exported then pExt.exportEntriesFn state else pExt.saveEntriesFn state)
1713+
(pExt.name, pExt.exportEntriesFn env state level)
16921714
let kenv := env.toKernelEnv
16931715
let env := env.setExporting (level != .private)
16941716
let constNames := kenv.constants.foldStage2 (fun names name _ => names.push name) #[]

0 commit comments

Comments
 (0)