Skip to content

Commit 96461a4

Browse files
authored
feat: recordIndirectModUse (#11437)
This PR adds recording functionality such that `shake` can more precisely track whether an import should be preserved solely for its `attribute` commands.
1 parent 310abce commit 96461a4

File tree

5 files changed

+52
-10
lines changed

5 files changed

+52
-10
lines changed

src/Lean/Elab/Declaration.lean

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,11 +330,11 @@ def elabMutual : CommandElab := fun stx => do
330330
Term.applyAttributes declName attrs
331331
for attrName in toErase do
332332
Attribute.erase declName attrName
333-
if (← getEnv).isImportedConst declName && attrs.any (·.kind == .global) then
334-
-- If an imported declaration is marked with a global attribute, there is no good way to track
335-
-- its use generally and so Shake should conservatively preserve imports of the current
336-
-- module.
337-
recordExtraRevUseOfCurrentModule
333+
if (← getEnv).isImportedConst declName then
334+
if let some attr := attrs.find? (·.kind == .global) then
335+
-- If an imported declaration is marked with a global attribute, Shake must be informed
336+
-- about this indirect reference
337+
recordIndirectModUse attr.name.toString declName
338338

339339
@[builtin_command_elab Lean.Parser.Command.«initialize»] def elabInitialize : CommandElab
340340
| stx@`($declModifiers:declModifiers $kw:initializeKeyword $[$id? : $type? ←]? $doSeq) => do

src/Lean/Environment.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ deriving Inhabited, BEq, Repr
154154
structure EffectiveImport extends Import where
155155
/-- Phases for which the import's IR is available. -/
156156
irPhases : IRPhases
157+
deriving Inhabited
157158

158159
/-- Environment fields that are not used often. -/
159160
structure EnvironmentHeader where

src/Lean/ExtraModUses.lean

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module
88
prelude
99
public import Lean.CoreM
1010
public import Lean.Compiler.MetaAttr -- TODO: public because of specializations
11+
import Init.Data.Range.Polymorphic.Stream
1112

1213
/-!
1314
Infrastructure for recording extra import dependencies not implied by the environment constants for
@@ -16,6 +17,41 @@ the benefit of `shake`.
1617

1718
namespace Lean
1819

20+
public structure IndirectModUse where
21+
kind : String
22+
declName : Name
23+
deriving BEq
24+
25+
public builtin_initialize indirectModUseExt : SimplePersistentEnvExtension IndirectModUse (Std.HashMap Name (Array ModuleIdx)) ←
26+
registerSimplePersistentEnvExtension {
27+
addEntryFn s _ := s
28+
addImportedFn es := Id.run do
29+
let mut s := {}
30+
for es in es, modIdx in 0...* do
31+
for e in es do
32+
s := s.alter e.declName (·.getD #[] |>.push modIdx)
33+
return s
34+
asyncMode := .sync
35+
}
36+
37+
public def getIndirectModUses (env : Environment) (modIdx : ModuleIdx) : Array IndirectModUse :=
38+
indirectModUseExt.getModuleEntries env modIdx
39+
40+
variable [Monad m] [MonadEnv m] [MonadTrace m] [MonadOptions m] [MonadRef m] [AddMessageContext m]
41+
42+
/--
43+
Lets `shake` know that references to `declName` may also require importing the current module due to
44+
some additional metaprogramming dependency expressed by `kind`. Currently this is always the name of
45+
an attribute applied to `declName`, which is not from the current module, in the current module.
46+
`kind` is not currently used to further filter what references to `declName` require importing the
47+
current module but may in the future.
48+
-/
49+
public def recordIndirectModUse (kind : String) (declName : Name) : m Unit := do
50+
-- We can assume this is called from the main thread only and that the list of entries is short
51+
if !(indirectModUseExt.getEntries (asyncMode := .mainOnly) (← getEnv) |>.contains { kind, declName }) then
52+
trace[extraModUses] "recording indirect mod use of `{declName}` ({kind})"
53+
modifyEnv (indirectModUseExt.addEntry · { kind, declName })
54+
1955
/-- Additional import dependency for elaboration. -/
2056
public structure ExtraModUse where
2157
/-- Dependency's module name. -/
@@ -49,8 +85,6 @@ public def copyExtraModUses (src dest : Environment) : Environment := Id.run do
4985
env := extraModUses.addEntry env entry
5086
env
5187

52-
variable [Monad m] [MonadEnv m] [MonadTrace m] [MonadOptions m] [MonadRef m] [AddMessageContext m]
53-
5488
def recordExtraModUseCore (mod : Name) (isMeta : Bool) (hint : Name := .anonymous) : m Unit := do
5589
let entry := { module := mod, isExported := (← getEnv).isExporting, isMeta }
5690
if !(extraModUses.getState (asyncMode := .local) (← getEnv)).contains entry then
@@ -62,6 +96,9 @@ def recordExtraModUseCore (mod : Name) (isMeta : Bool) (hint : Name := .anonymou
6296
/--
6397
Records an additional import dependency for the current module, using `Environment.isExporting` as
6498
the visibility level.
99+
100+
NOTE: Directly recording a module name does not trigger including indirect dependencies recorded via
101+
`recordIndirectModUse`, prefer `recordExtraModUseFromDecl` instead.
65102
-/
66103
public def recordExtraModUse (modName : Name) (isMeta : Bool) : m Unit := do
67104
if modName != (← getEnv).mainModule then
@@ -78,6 +115,8 @@ public def recordExtraModUseFromDecl (declName : Name) (isMeta : Bool) : m Unit
78115
-- If the declaration itself is already `meta`, no need to mark the import.
79116
let isMeta := isMeta && !isMarkedMeta (← getEnv) declName
80117
recordExtraModUseCore mod.module isMeta (hint := declName)
118+
for modIdx in (indirectModUseExt.getState (asyncMode := .local) env)[declName]?.getD #[] do
119+
recordExtraModUseCore env.header.modules[modIdx]!.module (isMeta := false) (hint := declName)
81120

82121
builtin_initialize isExtraRevModUseExt : SimplePersistentEnvExtension Unit Unit ←
83122
registerSimplePersistentEnvExtension {

stage0/src/stdlib_flags.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "util/options.h"
22

3+
// Dear CI, please update stage 0
4+
35
namespace lean {
46
options get_default_options() {
57
options opts;

tests/lean/run/extraModUses.lean

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ Is rev mod use: false
6969
recommended_spelling "id" for "id" in [id]
7070

7171
/--
72-
info: Entries: [import Init.Prelude]
72+
info: Entries: [import Init.Core, import Init.Prelude]
7373
Is rev mod use: false
7474
-/
7575
#guard_msgs in #eval showExtraModUses
@@ -174,7 +174,7 @@ attribute [grind =] List.append
174174

175175
/--
176176
info: Entries: [import Init.Grind.Attr, public import Init.Prelude]
177-
Is rev mod use: true
177+
Is rev mod use: false
178178
-/
179179
#guard_msgs in #eval showExtraModUses
180180

@@ -201,7 +201,7 @@ Simp theorems (especially defeq ones) are tracked (here `Nat.pow_succ` from Init
201201
def test7 : 2 ^ 8 = 256 := by simp [Nat.pow_succ]
202202

203203
/--
204-
info: Entries: [import Init.Tactics, import Init.Data.Nat.Basic, import Init.SimpLemmas, import Init.Notation]
204+
info: Entries: [import Init.Tactics, import Init.Data.Nat.Lemmas, import Init.Data.Nat.Basic, import Init.SimpLemmas, import Init.Notation]
205205
Is rev mod use: false
206206
-/
207207
#guard_msgs in #eval showExtraModUses

0 commit comments

Comments
 (0)