/
DefaultAlt.lean
66 lines (63 loc) · 1.92 KB
/
DefaultAlt.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/-
Copyright (c) 2022 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Lean.Compiler.LCNF.Simp.SimpM
namespace Lean.Compiler.LCNF
namespace Simp
/--
Return the alternative in `alts` whose body appears in most arms,
and the number of occurrences.
We use this function to decide whether to create a `.default` case
or not.
-/
private def getMaxOccs (alts : Array Alt) : Alt × Nat := Id.run do
let mut maxAlt := alts[0]!
let mut max := getNumOccsOf alts 0
for i in [1:alts.size] do
let curr := getNumOccsOf alts i
if curr > max then
maxAlt := alts[i]!
max := curr
return (maxAlt, max)
where
/--
Return the number of occurrences of `alts[i]` in `alts`.
We use alpha equivalence.
Note that the number of occurrences can be greater than 1 only when
the alternative does not depend on field parameters
-/
getNumOccsOf (alts : Array Alt) (i : Nat) : Nat := Id.run do
let code := alts[i]!.getCode
let mut n := 1
for j in [i+1:alts.size] do
if Code.alphaEqv alts[j]!.getCode code then
n := n+1
return n
/--
Add a default case to the given `cases` alternatives if there
are alternatives with equivalent (aka alpha equivalent) right hand sides.
-/
def addDefaultAlt (alts : Array Alt) : SimpM (Array Alt) := do
if alts.size <= 1 || alts.any (· matches .default ..) then
return alts
else
let (max, noccs) := getMaxOccs alts
if noccs == 1 then
return alts
else
let mut altsNew := #[]
let mut first := true
markSimplified
for alt in alts do
if Code.alphaEqv alt.getCode max.getCode then
let .alt _ ps k := alt | unreachable!
eraseParams ps
unless first do
eraseCode k
first := false
else
altsNew := altsNew.push alt
return altsNew.push (.default max.getCode)