@@ -35,25 +35,44 @@ inductive Value where
3535 A set of values are possible.
3636 -/
3737 | choice (vs : List Value)
38- deriving Inhabited, Repr
38+ deriving Inhabited
3939
4040namespace Value
4141
4242-- TODO: parameterize
4343def maxValueDepth := 8
4444
4545protected partial def beq : Value → Value → Bool
46- | bot, bot => true
47- | top, top => true
48- | ctor i1 vs1 , ctor i2 vs2 =>
49- i1 == i2 && Array.isEqv vs1 vs2 Value.beq
50- | choice vs1 , choice vs2 =>
51- let isSubset as bs := as.all (fun a => bs.any fun b => Value.beq a b)
52- isSubset vs1 vs2 && isSubset vs2 vs1
53- | _, _ => false
46+ | bot, bot => true
47+ | top, top => true
48+ | ctor i1 vs1 , ctor i2 vs2 =>
49+ i1 == i2 && Array.isEqv vs1 vs2 Value.beq
50+ | choice vs1 , choice vs2 =>
51+ let isSubset as bs := as.all (fun a => bs.any fun b => Value.beq a b)
52+ isSubset vs1 vs2 && isSubset vs2 vs1
53+ | _, _ => false
5454
5555instance : BEq Value := ⟨Value.beq⟩
5656
57+ protected partial def toFormat : Value → Format
58+ | bot => "⊥"
59+ | top => "⊤"
60+ | ctor i vs =>
61+ if vs.isEmpty then
62+ format i
63+ else
64+ .paren <| format i ++ .join (vs.toList.map fun v => " " ++ Value.toFormat v)
65+ | choice vs =>
66+ .paren <| .joinSep (vs.map Value.toFormat) " | "
67+
68+ instance : Repr Value where
69+ reprPrec v _ := Value.toFormat v
70+
71+ def inductValOfCtor (ctorName : Name) (env : Environment) : InductiveVal := Id.run do
72+ let some (.ctorInfo info) ← env.find? ctorName | unreachable!
73+ let some (.inductInfo info) ← env.find? info.induct | unreachable!
74+ return info
75+
5776mutual
5877
5978/--
@@ -62,32 +81,60 @@ is a constructor that is already contained within `vs` try to detect
6281the difference between these values and merge them accordingly into a
6382choice node further down the tree.
6483-/
65- partial def addChoice (vs : List Value) (v : Value) : List Value :=
84+ partial def addChoice (env : Environment) ( vs : List Value) (v : Value) : List Value :=
6685 match vs, v with
6786 | [], v => [v]
6887 | v1@(ctor i1 _ ) :: cs, ctor i2 _ =>
6988 if i1 == i2 then
70- (merge v1 v) :: cs
89+ (merge env v1 v) :: cs
7190 else
72- v1 :: addChoice cs v
91+ v1 :: addChoice env cs v
7392 | _, _ => panic! "invalid addChoice"
7493
7594/--
7695Merge two values into one. `bot` is the neutral element, `top` the annihilator.
7796-/
78- partial def merge (v1 v2 : Value) : Value :=
79- match v1, v2 with
80- | bot, v | v, bot => v
81- | top, _ | _, top => top
82- | ctor i1 vs1, ctor i2 vs2 =>
83- if i1 == i2 then
84- ctor i1 (Array.zipWith merge vs1 vs2)
97+ partial def merge (env : Environment) (v1 v2 : Value) : Value :=
98+ let newValue :=
99+ match v1, v2 with
100+ | bot, v | v, bot => v
101+ | top, _ | _, top => top
102+ | ctor i1 vs1, ctor i2 vs2 =>
103+ if i1 == i2 then
104+ ctor i1 (Array.zipWith (merge env) vs1 vs2)
105+ else
106+ choice [v1, v2]
107+ | choice vs1, choice vs2 =>
108+ choice (vs1.foldl (addChoice env) vs2)
109+ | choice vs, v | v, choice vs =>
110+ choice (addChoice env vs v)
111+ match newValue with
112+ | .top | .bot => newValue
113+ | .choice vs => cleanup vs
114+ | .ctor ctorName .. =>
115+ if eligible newValue && inductHasNumCtors ctorName env 1 then
116+ top
85117 else
86- choice [v1, v2]
87- | choice vs1, choice vs2 =>
88- choice (vs1.foldl addChoice vs2)
89- | choice vs, v | v, choice vs =>
90- choice (addChoice vs v)
118+ newValue
119+ where
120+ cleanup (vs : List Value) : Value := Id.run do
121+ if vs.all eligible then
122+ let .ctor ctorName .. := vs.head! | unreachable!
123+ if inductHasNumCtors ctorName env vs.length then
124+ top
125+ else
126+ choice vs
127+ else
128+ choice vs
129+
130+ inductHasNumCtors (ctorName : Name) (env : Environment) (n : Nat) : Bool := Id.run do
131+ let induct := inductValOfCtor ctorName env
132+ n == induct.numCtors
133+
134+ @[inline]
135+ eligible (value : Value) : Bool := Id.run do
136+ let .ctor _ args := value | return false
137+ args.all (· == .top)
91138
92139end
93140
@@ -106,19 +153,16 @@ where
106153 | remainingDepth + 1 =>
107154 match v with
108155 | ctor i vs =>
109- let typeName := i.getPrefix
110- if forbiddenTypes.contains typeName then
156+ let induct := inductValOfCtor i env
157+ if forbiddenTypes.contains induct.name then
111158 top
112159 else
113160 let cont forbiddenTypes' :=
114161 ctor i (vs.map (go · forbiddenTypes' remainingDepth))
115- match env.find? typeName with
116- | some (.inductInfo type) =>
117- if type.isRec then
118- cont <| forbiddenTypes.insert typeName
119- else
120- cont forbiddenTypes
121- | _ => cont forbiddenTypes
162+ if induct.isRec then
163+ cont <| forbiddenTypes.insert induct.name
164+ else
165+ cont forbiddenTypes
122166 | choice vs =>
123167 let vs := vs.map (go · forbiddenTypes remainingDepth)
124168 if vs.elem top then
@@ -129,7 +173,7 @@ where
129173
130174/-- Widening operator that guarantees termination in our abstract interpreter. -/
131175def widening (env : Environment) (v1 v2 : Value) : Value :=
132- truncate env (merge v1 v2)
176+ truncate env (merge env v1 v2)
133177
134178/--
135179Check whether a certain constructor is part of a `Value` by name.
0 commit comments