@@ -17,6 +17,7 @@ module EchidnaABI.AxiomTracker
1717
1818import EchidnaABI . Types -- ProverKind, Platform, etc.
1919import Data.List
20+ import Data.List.Elem
2021import Data.So
2122import Decidable.Equality
2223
@@ -44,7 +45,7 @@ Eq DangerLevel where
4445 _ == _ = False
4546
4647public export
47- DecidableEq DangerLevel where
48+ DecEq DangerLevel where
4849 decEq Safe Safe = Yes Refl
4950 decEq Noted Noted = Yes Refl
5051 decEq Warning Warning = Yes Refl
@@ -117,6 +118,15 @@ isAcceptable _ = True
117118-- (These are what SPARK GNATprove formally verifies on the Ada side.)
118119-- ════════════════════════════════════════════════════════════════════════════
119120
121+ ||| Structural existential over a danger level. Unlike the Foldable `any`
122+ ||| (which folds via `foldl`, so it does NOT reduce on cons), this recurses
123+ ||| structurally — letting the soundness/precision proofs below go through by
124+ ||| induction with definitional reduction of the head test `x == d`.
125+ public export
126+ hasDanger : DangerLevel -> List DangerLevel -> Bool
127+ hasDanger _ [] = False
128+ hasDanger d (x :: xs) = (x == d) || hasDanger d xs
129+
120130||| Specification of enforcePolicySpec: the reference function that the
121131||| SPARK implementation must replicate.
122132|||
@@ -125,9 +135,9 @@ isAcceptable _ = True
125135public export
126136enforcePolicySpec : List DangerLevel -> AxiomPolicy
127137enforcePolicySpec usages =
128- if any ( == Reject ) usages then PolicyRejected
129- else if any ( == Warning ) usages then PolicyIncomplete
130- else if any ( == Noted ) usages then PolicyClassical
138+ if hasDanger Reject usages then PolicyRejected
139+ else if hasDanger Warning usages then PolicyIncomplete
140+ else if hasDanger Noted usages then PolicyClassical
131141 else PolicyClean
132142
133143-- ────────────────────────────────────────────────────────────────────────────
@@ -141,25 +151,21 @@ soundness
141151 -> Elem Reject usages
142152 -> enforcePolicySpec usages = PolicyRejected
143153soundness usages prf =
144- rewrite anyRejectIsTrue usages prf in Refl
154+ rewrite hasRejectIsTrue usages prf in Refl
145155 where
146- -- Prove any (== Reject) us = True given Reject ∈ us.
147- -- We case -split on the head constructor so that 'x == Reject' reduces
156+ -- Prove hasDanger Reject us = True given Reject ∈ us.
157+ -- Case -split on the head constructor so that 'x == Reject' reduces
148158 -- definitionally before applying the induction hypothesis via rewrite.
149- anyRejectIsTrue
159+ hasRejectIsTrue
150160 : (us : List DangerLevel)
151161 -> Elem Reject us
152- -> any (== Reject ) us = True
153- anyRejectIsTrue [] p = absurd p
154- anyRejectIsTrue (Reject :: _ ) Here = Refl
155- anyRejectIsTrue (Safe :: xs) (There p) =
156- let ih : = anyRejectIsTrue xs p in rewrite ih in Refl
157- anyRejectIsTrue (Noted :: xs) (There p) =
158- let ih : = anyRejectIsTrue xs p in rewrite ih in Refl
159- anyRejectIsTrue (Warning :: xs) (There p) =
160- let ih : = anyRejectIsTrue xs p in rewrite ih in Refl
161- anyRejectIsTrue (Reject :: xs) (There p) =
162- let ih : = anyRejectIsTrue xs p in rewrite ih in Refl
162+ -> hasDanger Reject us = True
163+ hasRejectIsTrue [] p = absurd p
164+ hasRejectIsTrue (Reject :: _ ) Here = Refl
165+ hasRejectIsTrue (Safe :: xs) (There p) = rewrite hasRejectIsTrue xs p in Refl
166+ hasRejectIsTrue (Noted :: xs) (There p) = rewrite hasRejectIsTrue xs p in Refl
167+ hasRejectIsTrue (Warning :: xs) (There p) = rewrite hasRejectIsTrue xs p in Refl
168+ hasRejectIsTrue (Reject :: xs) (There _ ) = Refl
163169
164170-- ────────────────────────────────────────────────────────────────────────────
165171-- Invariant 2 (Precision): no Reject-in → not PolicyRejected-out
@@ -172,35 +178,38 @@ precision
172178 -> ((e : DangerLevel) -> Elem e usages -> Not (e = Reject))
173179 -> Not (enforcePolicySpec usages = PolicyRejected )
174180precision usages noReject prf =
175- -- Derive any (== Reject) usages = False from the no-Reject hypothesis.
176- -- Then case-split on all three 'any' booleans so enforcePolicySpec usages
177- -- reduces definitionally in each branch; each non-Rejected result gives a
178- -- constructor mismatch with prf : ... = PolicyRejected.
179- let anyFalse : = noRejectMeansAnyFalse usages noReject
180- in case any (== Reject ) usages of
181- True => absurd anyFalse -- anyFalse : True = False
182- False =>
183- case any (== Warning ) usages of
184- True => case prf of { Refl impossible } -- PolicyIncomplete ≠ PolicyRejected
185- False =>
186- case any (== Noted ) usages of
187- True => case prf of { Refl impossible } -- PolicyClassical ≠ PolicyRejected
188- False => case prf of { Refl impossible } -- PolicyClean ≠ PolicyRejected
181+ -- A PolicyRejected verdict forces the Reject flag True (rejTrue); the
182+ -- no-Reject hypothesis forces it False — contradiction.
183+ absurd (trans (sym (rejTrue usages prf)) (noRejectMeansFalse usages noReject))
189184 where
190- -- Case-split on each constructor so 'x == Reject' reduces definitionally,
191- -- making 'False || any (== Reject) xs = any (== Reject) xs' automatic.
192- noRejectMeansAnyFalse
185+ -- enforcePolicySpec us = PolicyRejected can only arise via the Reject
186+ -- guard. `with` on each flag lets the spec reduce per branch, so every
187+ -- non-Reject branch contradicts `p` and the Reject branch returns Refl.
188+ rejTrue : (us : List DangerLevel) ->
189+ enforcePolicySpec us = PolicyRejected -> hasDanger Reject us = True
190+ rejTrue us p with (hasDanger Reject us)
191+ rejTrue us p | True = Refl
192+ rejTrue us p | False with (hasDanger Warning us)
193+ rejTrue us p | False | True = case p of { Refl impossible }
194+ rejTrue us p | False | False with (hasDanger Noted us)
195+ rejTrue us p | False | False | True = case p of { Refl impossible }
196+ rejTrue us p | False | False | False = case p of { Refl impossible }
197+
198+ -- No Reject in the list ⇒ the structural Reject check is False.
199+ -- 'x == Reject' reduces definitionally, so 'False || hasDanger Reject xs'
200+ -- collapses to the inductive hypothesis.
201+ noRejectMeansFalse
193202 : (us : List DangerLevel)
194203 -> ((e : DangerLevel) -> Elem e us -> Not (e = Reject))
195- -> any ( == Reject ) us = False
196- noRejectMeansAnyFalse [] _ = Refl
197- noRejectMeansAnyFalse (Safe :: xs) noR =
198- noRejectMeansAnyFalse xs (\ e p => noR e (There p))
199- noRejectMeansAnyFalse (Noted :: xs) noR =
200- noRejectMeansAnyFalse xs (\ e p => noR e (There p))
201- noRejectMeansAnyFalse (Warning :: xs) noR =
202- noRejectMeansAnyFalse xs (\ e p => noR e (There p))
203- noRejectMeansAnyFalse (Reject :: xs) noR =
204+ -> hasDanger Reject us = False
205+ noRejectMeansFalse [] _ = Refl
206+ noRejectMeansFalse (Safe :: xs) noR =
207+ rewrite noRejectMeansFalse xs (\ e, p => noR e (There p)) in Refl
208+ noRejectMeansFalse (Noted :: xs) noR =
209+ rewrite noRejectMeansFalse xs (\ e, p => noR e (There p)) in Refl
210+ noRejectMeansFalse (Warning :: xs) noR =
211+ rewrite noRejectMeansFalse xs (\ e, p => noR e (There p)) in Refl
212+ noRejectMeansFalse (Reject :: xs) noR =
204213 void (noR Reject Here Refl )
205214
206215-- ════════════════════════════════════════════════════════════════════════════
0 commit comments