Skip to content

Commit 42d3fdf

Browse files
authored
Merge branch 'master' into decidable-as-bool
2 parents 23d879d + 12750d2 commit 42d3fdf

File tree

187 files changed

+7992
-3042
lines changed

Some content is hidden

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

187 files changed

+7992
-3042
lines changed

script/Shake.lean

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,11 @@ structure State where
131131
`transDeps[i]` is the (non-reflexive) transitive closure of `mods[i].imports`. More specifically,
132132
* `j ∈ transDeps[i].pub` if `i -(public import)->+ j`
133133
* `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
134-
* `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
135-
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
136-
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
137-
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
134+
* `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
135+
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
136+
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
137+
* `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
138+
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
138139
-/
139140
transDeps : Array Needs := #[]
140141
/--
@@ -162,21 +163,24 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
162163
-- `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
163164
transImps := transImps.union .priv {j} |>.union .priv (impTransImps.get .pub)
164165
if imp.importAll then
165-
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
166-
transImps := transImps.union .priv (impTransImps.get .pub)
166+
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
167+
transImps := transImps.union .priv (impTransImps.get .pub ∪ impTransImps.get .priv)
167168

168-
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
169+
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
169170
if imp.isExported then
170171
transImps := transImps.union .metaPub (impTransImps.get .metaPub)
171172
if imp.isMeta then
172173
transImps := transImps.union .metaPub {j} |>.union .metaPub (impTransImps.get .pub ∪ impTransImps.get .metaPub)
173174

174175
if !imp.isExported then
175176
if imp.isMeta then
176-
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
177+
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
177178
transImps := transImps.union .metaPriv {j} |>.union .metaPriv (impTransImps.get .pub ∪ impTransImps.get .metaPub)
178179
if imp.importAll then
179-
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
180+
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
181+
transImps := transImps.union .metaPriv (impTransImps.get .metaPub ∪ impTransImps.get .metaPriv)
182+
else
183+
-- `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
180184
transImps := transImps.union .metaPriv (impTransImps.get .metaPub)
181185

182186
transImps
@@ -185,7 +189,8 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
185189
def calcNeeds (env : Environment) (i : ModuleIdx) : Needs := Id.run do
186190
let mut needs := default
187191
for ci in env.header.moduleData[i]!.constants do
188-
let pubCI? := env.setExporting true |>.find? ci.name
192+
-- Added guard for cases like `structure` that are still exported even if private
193+
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
189194
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
190195
needs := visitExpr k ci.type needs
191196
if let some e := ci.value? (allowOpaque := true) then
@@ -216,7 +221,8 @@ def getExplanations (env : Environment) (i : ModuleIdx) :
216221
Std.HashMap (ModuleIdx × NeedsKind) (Option (Name × Name)) := Id.run do
217222
let mut deps := default
218223
for ci in env.header.moduleData[i]!.constants do
219-
let pubCI? := env.setExporting true |>.find? ci.name
224+
-- Added guard for cases like `structure` that are still exported even if private
225+
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
220226
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
221227
deps := visitExpr k ci.name ci.type deps
222228
if let some e := ci.value? (allowOpaque := true) then
@@ -286,16 +292,16 @@ and `endPos` is the position of the end of the header.
286292
-/
287293
def parseHeaderFromString (text path : String) :
288294
IO (System.FilePath × Parser.InputContext ×
289-
TSyntaxArray ``Parser.Module.import × String.Pos) := do
295+
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
290296
let inputCtx := Parser.mkInputContext text path
291297
let (header, parserState, msgs) ← Parser.parseHeader inputCtx
292298
if !msgs.toList.isEmpty then -- skip this file if there are parse errors
293299
msgs.forM fun msg => msg.toString >>= IO.println
294300
throw <| .userError "parse errors in file"
295301
-- the insertion point for `add` is the first newline after the imports
296302
let insertion := header.raw.getTailPos?.getD parserState.pos
297-
let insertion := text.findAux (· == '\n') text.endPos insertion + 1
298-
pure (path, inputCtx, .mk header.raw[2].getArgs, insertion)
303+
let insertion := text.findAux (· == '\n') text.endPos insertion + '\n'
304+
pure (path, inputCtx, header, insertion)
299305

300306
/-- Parse a source file to extract the location of the import lines, for edits and error messages.
301307
@@ -304,13 +310,18 @@ and `endPos` is the position of the end of the header.
304310
-/
305311
def parseHeader (srcSearchPath : SearchPath) (mod : Name) :
306312
IO (System.FilePath × Parser.InputContext ×
307-
TSyntaxArray ``Parser.Module.import × String.Pos) := do
313+
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
308314
-- Parse the input file
309315
let some path ← srcSearchPath.findModuleWithExt "lean" mod
310316
| throw <| .userError s!"error: failed to find source file for {mod}"
311317
let text ← IO.FS.readFile path
312318
parseHeaderFromString text path.toString
313319

320+
def decodeHeader : TSyntax ``Parser.Module.header → Option (TSyntax `module) × Option (TSyntax `prelude) × TSyntaxArray ``Parser.Module.import
321+
| `(Parser.Module.header| $[module%$moduleTk?]? $[prelude%$preludeTk?]? $imports*) =>
322+
(moduleTk?.map .mk, preludeTk?.map .mk, imports)
323+
| _ => unreachable!
324+
314325
def decodeImport : TSyntax ``Parser.Module.import → Import
315326
| `(Parser.Module.import| $[public%$pubTk?]? $[meta%$metaTk?]? import $[all%$allTk?]? $id) =>
316327
{ module := id.getId, isExported := pubTk?.isSome, isMeta := metaTk?.isSome, importAll := allTk?.isSome }
@@ -326,11 +337,20 @@ def decodeImport : TSyntax ``Parser.Module.import → Import
326337
* `addOnly`: if true, only add missing imports, do not remove unused ones
327338
-/
328339
def visitModule (srcSearchPath : SearchPath)
329-
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits)
340+
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits) (headerStx : TSyntax ``Parser.Module.header)
330341
(addOnly := false) (githubStyle := false) (explain := false) : StateT State IO Edits := do
331342
let s ← get
332343
-- Do transitive reduction of `needs` in `deps`.
333344
let mut deps := needs
345+
let (_, prelude?, imports) := decodeHeader headerStx
346+
if prelude?.isNone then
347+
deps := deps.union .pub {s.env.getModuleIdx? `Init |>.get!}
348+
for imp in imports do
349+
if addOnly || imp.raw.getTrailing?.any (·.toString.toSlice.contains "shake: keep") then
350+
let imp := decodeImport imp
351+
let j := s.env.getModuleIdx? imp.module |>.get!
352+
let k := NeedsKind.ofImport imp
353+
deps := deps.union k {j}
334354
for j in [0:s.mods.size] do
335355
let transDeps := s.transDeps[j]!
336356
for k in NeedsKind.all do
@@ -354,7 +374,8 @@ def visitModule (srcSearchPath : SearchPath)
354374
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
355375
else
356376
let k := NeedsKind.ofImport imp
357-
if !addOnly && !deps.has k j && !deps.has { k with isExported := false } j then
377+
-- A private import should also be removed if the public version is needed
378+
if !deps.has k j || !k.isExported && deps.has { k with isExported := true } j then
358379
toRemove := toRemove.push imp
359380
else
360381
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
@@ -385,7 +406,8 @@ def visitModule (srcSearchPath : SearchPath)
385406

386407
if githubStyle then
387408
try
388-
let (path, inputCtx, imports, endHeader) ← parseHeader srcSearchPath s.modNames[i]!
409+
let (path, inputCtx, stx, endHeader) ← parseHeader srcSearchPath s.modNames[i]!
410+
let (_, _, imports) := decodeHeader stx
389411
for stx in imports do
390412
if toRemove.any fun imp => imp == decodeImport stx then
391413
let pos := inputCtx.fileMap.toPosition stx.raw.getPos?.get!
@@ -529,41 +551,51 @@ def main (args : List String) : IO UInt32 := do
529551
let needs := s.mods.mapIdx fun i _ =>
530552
Task.spawn fun _ => calcNeeds s.env i
531553

554+
-- Parse headers in parallel
555+
let headers ← s.mods.mapIdxM fun i _ =>
556+
BaseIO.asTask (parseHeader srcSearchPath s.modNames[i]! |>.toBaseIO)
557+
532558
if args.fix then
533559
println! "The following changes will be made automatically:"
534560

535561
-- Check all selected modules
536562
let mut edits : Edits := ∅
537563
let mut revNeeds : Needs := default
538-
for i in [0:s.mods.size], t in needs do
539-
edits ← visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!) srcSearchPath i t.get revNeeds edits args.githubStyle args.explain
540-
if isExtraRevModUse s.env i then
541-
revNeeds := revNeeds.union .priv {i}
564+
for i in [0:s.mods.size], t in needs, header in headers do
565+
match header.get with
566+
| .ok (_, _, stx, _) =>
567+
edits ← visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!)
568+
srcSearchPath i t.get revNeeds edits stx args.githubStyle args.explain
569+
if isExtraRevModUse s.env i then
570+
revNeeds := revNeeds.union .priv {i}
571+
| .error e =>
572+
println! e.toString
542573

543574
if !args.fix then
544575
-- return error if any issues were found
545576
return if edits.isEmpty then 0 else 1
546577

547578
-- Apply the edits to existing files
548-
let count ← edits.foldM (init := 0) fun count mod (remove, add) => do
579+
let mut count := 0
580+
for mod in s.modNames, header? in headers do
581+
let some (remove, add) := edits[mod]? | continue
549582
let add : Array Import := add.qsortOrd
550583

551584
-- Parse the input file
552-
let (path, inputCtx, imports, insertion) ←
553-
try parseHeader srcSearchPath mod
554-
catch e => println! e.toString; return count
585+
let .ok (path, inputCtx, stx, insertion) := header?.get | continue
586+
let (_, _, imports) := decodeHeader stx
555587
let text := inputCtx.fileMap.source
556588

557589
-- Calculate the edit result
558-
let mut pos : String.Pos := 0
590+
let mut pos : String.Pos.Raw := 0
559591
let mut out : String := ""
560592
let mut seen : Std.HashSet Import := {}
561593
for stx in imports do
562594
let mod := decodeImport stx
563595
if remove.contains mod || seen.contains mod then
564596
out := out ++ text.extract pos stx.raw.getPos?.get!
565597
-- We use the end position of the syntax, but include whitespace up to the first newline
566-
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + 1
598+
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + '\n'
567599
seen := seen.insert mod
568600
out := out ++ text.extract pos insertion
569601
for mod in add do
@@ -573,7 +605,7 @@ def main (args : List String) : IO UInt32 := do
573605
out := out ++ text.extract insertion text.rawEndPos
574606

575607
IO.FS.writeFile path out
576-
return count + 1
608+
count := count + 1
577609

578610
-- Since we throw an error upon encountering issues, we can be sure that everything worked
579611
-- if we reach this point of the script.

src/Init/Classical.lean

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,6 @@ theorem not_imp_iff_and_not : ¬(a → b) ↔ a ∧ ¬b := Decidable.not_imp_iff
182182

183183
theorem not_and_iff_not_or_not : ¬(a ∧ b) ↔ ¬a ∨ ¬b := Decidable.not_and_iff_not_or_not
184184

185-
@[deprecated not_and_iff_not_or_not (since := "2025-03-18")]
186-
abbrev not_and_iff_or_not_not := @not_and_iff_not_or_not
187-
188185
theorem not_iff : ¬(a ↔ b) ↔ (¬a ↔ b) := Decidable.not_iff
189186

190187
@[simp] theorem imp_iff_left_iff : (b ↔ a → b) ↔ a ∨ b := Decidable.imp_iff_left_iff

src/Init/Control/Basic.lean

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α
4545
forIn x b f = forIn' x b (fun x h => binderNameHint x f <| binderNameHint h () <| f x) := by
4646
rfl
4747

48-
@[deprecated forIn_eq_forIn' (since := "2025-04-04")]
49-
abbrev forIn_eq_forin' := @forIn_eq_forIn'
50-
5148
/--
5249
Extracts the value from a `ForInStep`, ignoring whether it is `ForInStep.done` or `ForInStep.yield`.
5350
-/

src/Init/Control/Lawful/Basic.lean

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,11 +255,6 @@ instance : LawfulMonad Id := by
255255
@[simp] theorem run_seqLeft (x y : Id α) : (x <* y).run = x.run := rfl
256256
@[simp] theorem run_seq (f : Id (α → β)) (x : Id α) : (f <*> x).run = f.run x.run := rfl
257257

258-
-- These lemmas are bad as they abuse the defeq of `Id α` and `α`
259-
@[deprecated run_map (since := "2025-03-05")] theorem map_eq (x : Id α) (f : α → β) : f <$> x = f x := rfl
260-
@[deprecated run_bind (since := "2025-03-05")] theorem bind_eq (x : Id α) (f : α → id β) : x >>= f = f x := rfl
261-
@[deprecated run_pure (since := "2025-03-05")] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
262-
263258
end Id
264259

265260
/-! # Option -/

src/Init/Core.lean

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -600,17 +600,6 @@ export LawfulSingleton (insert_empty_eq)
600600

601601
attribute [simp] insert_empty_eq
602602

603-
@[deprecated insert_empty_eq (since := "2025-03-12")]
604-
theorem insert_emptyc_eq [EmptyCollection β] [Insert α β] [Singleton α β]
605-
[LawfulSingleton α β] (x : α) : (insert x ∅ : β) = singleton x :=
606-
insert_empty_eq _
607-
608-
@[deprecated insert_empty_eq (since := "2025-03-12")]
609-
theorem LawfulSingleton.insert_emptyc_eq [EmptyCollection β] [Insert α β] [Singleton α β]
610-
[LawfulSingleton α β] (x : α) : (insert x ∅ : β) = singleton x :=
611-
insert_empty_eq _
612-
613-
614603
/-- Type class used to implement the notation `{ a ∈ c | p a }` -/
615604
class Sep (α : outParam <| Type u) (γ : Type v) where
616605
/-- Computes `{ a ∈ c | p a }`. -/
@@ -1096,14 +1085,6 @@ theorem of_toBoolUsing_eq_true {p : Prop} {d : Decidable p} (h : toBoolUsing d =
10961085
theorem of_toBoolUsing_eq_false {p : Prop} {d : Decidable p} (h : toBoolUsing d = false) : ¬p :=
10971086
of_decide_eq_false h
10981087

1099-
set_option linter.missingDocs false in
1100-
@[deprecated of_toBoolUsing_eq_true (since := "2025-04-04")]
1101-
abbrev ofBoolUsing_eq_true := @of_toBoolUsing_eq_true
1102-
1103-
set_option linter.missingDocs false in
1104-
@[deprecated of_toBoolUsing_eq_false (since := "2025-04-04")]
1105-
abbrev ofBoolUsing_eq_false := @of_toBoolUsing_eq_false
1106-
11071088
instance : Decidable True :=
11081089
isTrue trivial
11091090

@@ -1213,11 +1194,13 @@ theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) :
12131194
| isTrue _ => rfl
12141195
| isFalse _ => rfl
12151196

1197+
@[macro_inline]
12161198
instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e) :=
12171199
match dC with
12181200
| isTrue _ => dT
12191201
| isFalse _ => dE
12201202

1203+
@[inline]
12211204
instance {c : Prop} {t : c → Prop} {e : ¬c → Prop} [dC : Decidable c] [dT : ∀ h, Decidable (t h)] [dE : ∀ h, Decidable (e h)] : Decidable (if h : c then t h else e h) :=
12221205
match dC with
12231206
| isTrue hc => dT hc
@@ -1366,10 +1349,6 @@ namespace Subtype
13661349
theorem exists_of_subtype {α : Type u} {p : α → Prop} : { x // p x } → Exists (fun x => p x)
13671350
| ⟨a, h⟩ => ⟨a, h⟩
13681351

1369-
set_option linter.missingDocs false in
1370-
@[deprecated exists_of_subtype (since := "2025-04-04")]
1371-
abbrev existsOfSubtype := @exists_of_subtype
1372-
13731352
variable {α : Type u} {p : α → Prop}
13741353

13751354
protected theorem eq : ∀ {a1 a2 : {x // p x}}, val a1 = val a2 → a1 = a2

src/Init/Data/Array/Attach.lean

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -749,9 +749,6 @@ and simplifies these to the function directly taking the value.
749749
(Array.replicate n x).unattach = Array.replicate n x.1 := by
750750
simp [unattach]
751751

752-
@[deprecated unattach_replicate (since := "2025-03-18")]
753-
abbrev unattach_mkArray := @unattach_replicate
754-
755752
/-! ### Well-founded recursion preprocessing setup -/
756753

757754
@[wf_preprocess] theorem map_wfParam {xs : Array α} {f : α → β} :

src/Init/Data/Array/Basic.lean

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -209,20 +209,6 @@ Examples:
209209
def replicate {α : Type u} (n : Nat) (v : α) : Array α where
210210
toList := List.replicate n v
211211

212-
/--
213-
Creates an array that contains `n` repetitions of `v`.
214-
215-
The corresponding `List` function is `List.replicate`.
216-
217-
Examples:
218-
* `Array.mkArray 2 true = #[true, true]`
219-
* `Array.mkArray 3 () = #[(), (), ()]`
220-
* `Array.mkArray 0 "anything" = #[]`
221-
-/
222-
@[extern "lean_mk_array", deprecated replicate (since := "2025-03-18")]
223-
def mkArray {α : Type u} (n : Nat) (v : α) : Array α where
224-
toList := List.replicate n v
225-
226212
/--
227213
Swaps two elements of an array. The modification is performed in-place when the reference to the
228214
array is unique.
@@ -2147,5 +2133,3 @@ instance [ToString α] : ToString (Array α) where
21472133
toString xs := String.Internal.append "#" (toString xs.toList)
21482134

21492135
end Array
2150-
2151-
export Array (mkArray)

src/Init/Data/Array/Count.lean

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,6 @@ theorem countP_le_size : countP p xs ≤ xs.size := by
9999
theorem countP_replicate {a : α} {n : Nat} : countP p (replicate n a) = if p a then n else 0 := by
100100
simp [← List.toArray_replicate, List.countP_replicate]
101101

102-
@[deprecated countP_replicate (since := "2025-03-18")]
103-
abbrev countP_mkArray := @countP_replicate
104-
105102
theorem boole_getElem_le_countP {xs : Array α} {i : Nat} (h : i < xs.size) :
106103
(if p xs[i] then 1 else 0) ≤ xs.countP p := by
107104
rcases xs with ⟨xs⟩
@@ -262,15 +259,9 @@ theorem count_eq_size {xs : Array α} : count a xs = xs.size ↔ ∀ b ∈ xs, a
262259
@[simp] theorem count_replicate_self {a : α} {n : Nat} : count a (replicate n a) = n := by
263260
simp [← List.toArray_replicate]
264261

265-
@[deprecated count_replicate_self (since := "2025-03-18")]
266-
abbrev count_mkArray_self := @count_replicate_self
267-
268262
theorem count_replicate {a b : α} {n : Nat} : count a (replicate n b) = if b == a then n else 0 := by
269263
simp [← List.toArray_replicate, List.count_replicate]
270264

271-
@[deprecated count_replicate (since := "2025-03-18")]
272-
abbrev count_mkArray := @count_replicate
273-
274265
theorem filter_beq {xs : Array α} (a : α) : xs.filter (· == a) = replicate (count a xs) a := by
275266
rcases xs with ⟨xs⟩
276267
simp [List.filter_beq]
@@ -284,9 +275,6 @@ theorem replicate_count_eq_of_count_eq_size {xs : Array α} (h : count a xs = xs
284275
rw [← toList_inj]
285276
simp [List.replicate_count_eq_of_count_eq_length (by simpa using h)]
286277

287-
@[deprecated replicate_count_eq_of_count_eq_size (since := "2025-03-18")]
288-
abbrev mkArray_count_eq_of_count_eq_size := @replicate_count_eq_of_count_eq_size
289-
290278
@[simp] theorem count_filter {xs : Array α} (h : p a) : count a (filter p xs) = count a xs := by
291279
rcases xs with ⟨xs⟩
292280
simp [List.count_filter, h]

0 commit comments

Comments
 (0)