Skip to content

Commit 9ad2cec

Browse files
committed
Draft: Support GHC 9.2
This contains a variety of minor changes needed to make `saw` and its supporting libraries compile with GHC 9.2: * One place in `heapster-saw` matches on a GADT using a `let` binding, which no longer typechecks in GHC 9.2. While somewhat mysterious, using `let` bindings to match on GADTs is fragile anyway, so I opted to simply replace this with a monadic `do` match, which does not exhibit the same fragility. * GHC now includes `-Wincomplete-uni-patterns` in `-Wall` as of 9.2, so much of this patch is dedicated to silencing these sorts of warnings, usually by adding explicit fall-through cases for partial pattern matches. * GHC now inclues `-Wnoncanonical-monad-instances` in `-Wall` as of 9.2, so I had to refactor some `Applicative`/`Monad` instances to fix these warnings. * GHC 9.2 now defines `readBin` in `Numeric`, which clashes with a function of the same name in `SAWScript.Lexer`. Using explicit imports avoids this. * GHC's pattern-match coverage checker is smarter in 9.2 (see [here](https://gitlab.haskell.org/ghc/ghc/-/wikis/migration/9.2?version_id=63085dd8a5b56370571bda428848e7098765f7f8#improved-pattern-match-coverage-checker)), so I had to use `EmptyCase` to silence some of the new `-Wincomplete-patterns` warnings that were uncovered in `heapster-saw`. This is still a draft because: * [ ] There are various `-Wincomplete-uni-patterns` warnings in `saw` and `heapster-saw` that I have not yet had time to address. (See also a `TODO RGS` in `exe:saw` that should be fixed.) * [ ] I am temporarily including an `allow-newer` section in the `cabal.project` file to allow `graphviz` (a `verif-viewer` dependency) to build with GHC 9.2. See ivan-m/graphviz#53. Once that is merged upstream, we can remove this hack.
1 parent f71a795 commit 9ad2cec

File tree

23 files changed

+145
-71
lines changed

23 files changed

+145
-71
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ To build SAWScript and related utilities from source:
4242
* Ensure that you have the `cabal` and `ghc` executables in your
4343
`PATH`. If you don't already have them, we recommend using `ghcup`
4444
to install them: <https://www.haskell.org/ghcup/>. We recommend
45-
Cabal 3.4 or newer, and GHC 8.8, 8.10, or 9.0.
45+
Cabal 3.4 or newer, and GHC 8.8, 8.10, 9.0, or 9.2.
4646

4747
* Ensure that you have the C libraries and header files for
4848
`terminfo`, which generally comes as part of `ncurses` on most

cabal.project

+4
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,7 @@ source-repository-package
4343
type: git
4444
location: https://github.com/eddywestbrook/hobbits.git
4545
tag: e49911ce987c4e0fea8c63608d16638b243b051f
46+
47+
-- TODO: Remove this once https://github.com/ivan-m/graphviz/pull/53 lands
48+
allow-newer:
49+
graphviz:bytestring

heapster-saw/src/Verifier/SAW/Heapster/CruUtil.hs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE EmptyCase #-}
12
{-# LANGUAGE GADTs #-}
23
{-# LANGUAGE TemplateHaskell #-}
34
{-# LANGUAGE QuasiQuotes #-}
@@ -737,6 +738,7 @@ cruCtxLen (CruCtxCons ctx _) = 1 + cruCtxLen ctx
737738

738739
-- | Look up a type in a 'CruCtx'
739740
cruCtxLookup :: CruCtx ctx -> Member ctx a -> TypeRepr a
741+
cruCtxLookup CruCtxNil m = case m of {}
740742
cruCtxLookup (CruCtxCons _ tp) Member_Base = tp
741743
cruCtxLookup (CruCtxCons ctx _) (Member_Step memb) = cruCtxLookup ctx memb
742744

heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs

+5-1
Original file line numberDiff line numberDiff line change
@@ -2206,7 +2206,7 @@ mbRangeFTDelete
22062206
bvRangeDelete rng1 rng2
22072207
mbRangeFTDelete mb_rng _ = [mb_rng]
22082208

2209-
-- | Delete all ranges in any of a list of ranges from
2209+
-- | Delete all ranges in any of a list of ranges from
22102210
mbRangeFTsDelete :: [MbRangeForType a] -> [MbRangeForType a] ->
22112211
[MbRangeForType a]
22122212
mbRangeFTsDelete rngs_l rngs_r =
@@ -3053,13 +3053,16 @@ addPermOffsets (LLVMPermOffset off1) (LLVMPermOffset off2) =
30533053

30543054
-- | Get the @n@th expression in a 'PermExprs' list
30553055
nthPermExpr :: PermExprs args -> Member args a -> PermExpr a
3056+
nthPermExpr PExprs_Nil m = case m of {}
30563057
nthPermExpr (PExprs_Cons _ arg) Member_Base = arg
30573058
nthPermExpr (PExprs_Cons args _) (Member_Step memb) =
30583059
nthPermExpr args memb
30593060

30603061
-- | Set the @n@th expression in a 'PermExprs' list
30613062
setNthPermExpr :: PermExprs args -> Member args a -> PermExpr a ->
30623063
PermExprs args
3064+
setNthPermExpr PExprs_Nil m _ =
3065+
case m of {}
30633066
setNthPermExpr (PExprs_Cons args _) Member_Base a =
30643067
PExprs_Cons args a
30653068
setNthPermExpr (PExprs_Cons args arg) (Member_Step memb) a =
@@ -7088,6 +7091,7 @@ permVarSubstToNames PermVarSubst_Nil = MNil
70887091
permVarSubstToNames (PermVarSubst_Cons s n) = permVarSubstToNames s :>: n
70897092

70907093
varSubstLookup :: PermVarSubst ctx -> Member ctx a -> ExprVar a
7094+
varSubstLookup PermVarSubst_Nil m = case m of {}
70917095
varSubstLookup (PermVarSubst_Cons _ x) Member_Base = x
70927096
varSubstLookup (PermVarSubst_Cons s _) (Member_Step memb) =
70937097
varSubstLookup s memb

heapster-saw/src/Verifier/SAW/Heapster/SAWTranslation.hs

+4-4
Original file line numberDiff line numberDiff line change
@@ -2941,7 +2941,7 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of
29412941
let prxs2 = mbRAssignProxies ps2
29422942
let prxs_in = RL.append prxs1 prxs2 :>: Proxy
29432943
pctx <- itiPermStack <$> ask
2944-
let (pctx_ps, pctx12 :>: ptrans_l) = RL.split ps0 prxs_in pctx
2944+
(pctx_ps, pctx12 :>: ptrans_l) <- pure $ RL.split ps0 prxs_in pctx
29452945
let (pctx1, pctx2) = RL.split prxs1 prxs2 pctx12
29462946

29472947
-- Also split out the input variables and replace them with the ps_out vars
@@ -2955,10 +2955,10 @@ translateSimplImpl (ps0 :: Proxy ps0) mb_simpl m = case mbMatch mb_simpl of
29552955
let fromJustOrError (Just x) = x
29562956
fromJustOrError Nothing = error "translateSimplImpl: SImpl_MapLifetime"
29572957
ps_in'_vars =
2958-
RL.map (translateVar . getCompose) $ mbRAssign $
2958+
RL.map (translateVar . getCompose) $ mbRAssign $
29592959
fmap (fromJustOrError . exprPermsVars) ps_in'
29602960
ps_out_vars =
2961-
RL.map (translateVar . getCompose) $ mbRAssign $
2961+
RL.map (translateVar . getCompose) $ mbRAssign $
29622962
fmap (fromJustOrError . exprPermsVars) ps_out
29632963
impl_in_tm <-
29642964
translateCurryLocalPermImpl "Error mapping lifetime input perms:" impl_in
@@ -4946,7 +4946,7 @@ tcTranslateAddCFGs sc mod_name env checks endianness dlevel cfgs_and_perms =
49464946
applyOpenTerm (globalOpenTerm "Prelude.lrtTupleType") lrts
49474947
tup_fun_tm <- completeNormOpenTerm sc $
49484948
applyOpenTermMulti (globalOpenTerm "Prelude.multiFixM") [lrts, tup_fun]
4949-
scInsertDef sc mod_name tup_fun_ident tup_fun_tp tup_fun_tm
4949+
scInsertDef sc mod_name tup_fun_ident tup_fun_tp tup_fun_tm
49504950
new_entries <-
49514951
zipWithM
49524952
(\cfg_and_perm i ->

heapster-saw/src/Verifier/SAW/Heapster/Widening.hs

+3-3
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ instance Functor (PolyContT r m) where
117117
fmap f m = m >>= return . f
118118

119119
instance Applicative (PolyContT r m) where
120-
pure = return
120+
pure x = PolyContT $ \k -> k x
121121
(<*>) = ap
122122

123123
instance Monad (PolyContT r m) where
124-
return x = PolyContT $ \k -> k x
124+
return = pure
125125
(PolyContT m) >>= f =
126126
PolyContT $ \k -> m $ \a -> runPolyContT (f a) k
127127

@@ -454,7 +454,7 @@ widenExprs (CruCtxCons tps tp) (es1 :>: e1) (es2 :>: e2) =
454454

455455

456456
-- | Widen two bitvector offsets by trying to widen them additively
457-
-- ('widenBVsAddy'), or if that is not possible, by widening them
457+
-- ('widenBVsAddy'), or if that is not possible, by widening them
458458
-- multiplicatively ('widenBVsMulty')
459459
widenOffsets :: (1 <= w, KnownNat w) => TypeRepr (BVType w) ->
460460
PermOffset (LLVMPointerType w) ->

saw-core-coq/src/Verifier/SAW/Translation/Coq/SAWModule.hs

+14-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,20 @@ translateDataType (DataType {..}) =
9696
liftTermTranslationMonad $ do
9797
ps <- TermTranslation.translateParams dtParams
9898
ixs <- TermTranslation.translateParams dtIndices
99-
return (ps, map (\(Coq.Binder s (Just t)) -> Coq.PiBinder (Just s) t) ixs)
99+
-- Translating the indices of a data type should never yield
100+
-- Inhabited constraints, so the result of calling
101+
-- `translateParams dtIndices` above should only return Binders and not
102+
-- any ImplicitBinders. Moreover, `translateParams` always returns
103+
-- Binders where the second field is `Just t`, where `t` is the type.
104+
let errorBecause msg = error $ "translateDataType.translateNamed: " ++ msg
105+
let bs = map (\case Coq.Binder s (Just t) ->
106+
Coq.PiBinder (Just s) t
107+
Coq.Binder _ Nothing ->
108+
errorBecause "encountered a Binder without a Type"
109+
Coq.ImplicitBinder{} ->
110+
errorBecause "encountered an implicit binder")
111+
ixs
112+
return (ps, bs)
100113
let inductiveSort = TermTranslation.translateSort dtSort
101114
inductiveConstructors <- mapM (translateCtor inductiveParameters) dtCtors
102115
return $ Coq.InductiveDecl $ Coq.Inductive

saw-core-sbv/saw-core-sbv.cabal

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ library
2020
lens,
2121
mtl,
2222
saw-core,
23-
sbv >= 8.10 && < 8.16,
23+
sbv >= 8.10 && < 9.1,
2424
text,
2525
transformers,
2626
vector

saw-core/saw-core.cabal

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ library
2424
happy >= 1.9.6
2525

2626
build-depends:
27-
base == 4.*,
27+
base >= 4.8,
2828
array,
2929
bytestring,
3030
containers,

saw-core/src/Verifier/SAW/Change.hs

+9-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
{-# LANGUAGE CPP #-}
21
{-# LANGUAGE DeriveFunctor #-}
32
{-# LANGUAGE FlexibleInstances #-}
43
{-# LANGUAGE MultiParamTypeClasses #-}
@@ -25,10 +24,8 @@ module Verifier.SAW.Change
2524
, flatten
2625
) where
2726

28-
#if !MIN_VERSION_base(4,8,0)
29-
import Control.Applicative
30-
#endif
31-
import Control.Monad (liftM, liftM2)
27+
import Control.Applicative (liftA2)
28+
import Control.Monad (liftM)
3229
import Control.Monad.Trans
3330

3431
----------------------------------------------------------------------
@@ -84,7 +81,7 @@ instance Applicative Change where
8481
Modified f <*> Modified x = Modified (f x)
8582

8683
instance Monad Change where
87-
return x = Original x
84+
return = pure
8885
Original x >>= k = k x
8986
Modified x >>= k = taint (k x)
9087

@@ -108,15 +105,15 @@ commitChange (Modified x) = x
108105

109106
newtype ChangeT m a = ChangeT { runChangeT :: m (Change a) }
110107

111-
instance Monad m => Functor (ChangeT m) where
112-
fmap f (ChangeT m) = ChangeT (liftM (fmap f) m)
108+
instance Functor m => Functor (ChangeT m) where
109+
fmap f (ChangeT m) = ChangeT (fmap (fmap f) m)
113110

114-
instance Monad m => Applicative (ChangeT m) where
115-
pure x = ChangeT (return (Original x))
116-
ChangeT m1 <*> ChangeT m2 = ChangeT (liftM2 (<*>) m1 m2)
111+
instance Applicative m => Applicative (ChangeT m) where
112+
pure x = ChangeT (pure (Original x))
113+
ChangeT m1 <*> ChangeT m2 = ChangeT (liftA2 (<*>) m1 m2)
117114

118115
instance Monad m => Monad (ChangeT m) where
119-
return x = ChangeT (return (Original x))
116+
return = pure
120117
ChangeT m >>= k = ChangeT (m >>= f)
121118
where f (Original x) = runChangeT (k x)
122119
f (Modified x) = runChangeT (k x) >>= (return . taint)

saw-core/src/Verifier/SAW/Conversion.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -361,13 +361,13 @@ instance Monad TermBuilder where
361361
m >>= h = TermBuilder $ \mg mk -> do
362362
r <- runTermBuilder m mg mk
363363
runTermBuilder (h r) mg mk
364-
return v = TermBuilder $ \_ _ -> return v
364+
return = pure
365365

366366
instance Functor TermBuilder where
367367
fmap = liftM
368368

369369
instance Applicative TermBuilder where
370-
pure = return
370+
pure v = TermBuilder $ \_ _ -> pure v
371371
(<*>) = ap
372372

373373
mkTermF :: TermF Term -> TermBuilder Term

saw-core/src/Verifier/SAW/Rewriter.hs

+12-5
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,11 @@ scMatch sc pat term =
240240
guard (fvy `unionBitSets` fvj == fvj)
241241
let fixVar t (nm, ty) =
242242
do v <- scFreshGlobal sc nm ty
243-
let Just ec = R.asExtCns v
243+
-- asExtCns should always return Just here because
244+
-- scFreshGlobal always returns an ExtCns.
245+
ec <- case R.asExtCns v of
246+
Just ec -> pure ec
247+
Nothing -> error "scMatch.match: impossible"
244248
t' <- instantiateVar sc 0 v t
245249
return (t', ec)
246250
let fixVars t [] = return (t, [])
@@ -934,10 +938,13 @@ doHoistIfs sc ss hoistCache itePat = go
934938
top :: Term -> TermF Term -> IO (HoistIfs s)
935939
top t tf
936940
| Just inst <- first_order_match itePat t = do
937-
let Just branch_tp = Map.lookup 0 inst
938-
let Just cond = Map.lookup 1 inst
939-
let Just then_branch = Map.lookup 2 inst
940-
let Just else_branch = Map.lookup 3 inst
941+
-- All of these Map lookups should be safe due to the term
942+
-- structure of an if-then-else expression.
943+
let err = error "doHoistIfs.top: impossible"
944+
let branch_tp = Map.findWithDefault err 0 inst
945+
let cond = Map.findWithDefault err 1 inst
946+
let then_branch = Map.findWithDefault err 2 inst
947+
let else_branch = Map.findWithDefault err 3 inst
941948

942949
(then_branch',conds1) <- go then_branch
943950
(else_branch',conds2) <- go else_branch

saw-core/src/Verifier/SAW/TermNet.hs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE LambdaCase #-}
12
{-# LANGUAGE NamedFieldPuns #-}
23
{-# LANGUAGE ScopedTypeVariables #-}
34
{-# LANGUAGE RecordWildCards #-}
@@ -250,8 +251,11 @@ matching unif = match
250251
Var -> nets
251252
App t1 t2 -> foldr (match t2) nets (rands t1 comb [])
252253

254+
{- Invariant: Each list entry must be a Leaf. -}
253255
extract_leaves :: [Net a] -> [a]
254-
extract_leaves = concatMap (\(Leaf xs) -> xs)
256+
extract_leaves = concatMap $ \case
257+
Leaf xs -> xs
258+
Net{} -> error "extract_leaves: Unexpected Net node"
255259

256260
{-return items whose key could match t, WHICH MUST BE BETA-ETA NORMAL-}
257261
match_term :: Pattern t => Net a -> t -> [a]

saw-core/src/Verifier/SAW/UnionFind.hs

+37-18
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,26 @@ classRep (Class r) = UF $ do
8585
return (Class i)
8686
impl r []
8787

88+
-- | Look up an equivalence class in a union find structure's map. This checks
89+
-- the invariant that the index of the class exists in the map and is associated
90+
-- with a 'Rep', not a 'NonRep'. If this invariant is violated, this function
91+
-- will throw an error.
92+
lookupClassRep :: Class d -> UnionFind d -> ([ClassIndex], Int, d)
93+
lookupClassRep (Class rC) uf =
94+
case Map.lookup rC (ufsMap uf) of
95+
Just (Rep ne sz d) ->
96+
(ne, sz, d)
97+
Just (NonRep i) ->
98+
errorBecause $ unlines
99+
[ "not associated with a class representative,"
100+
, "but rather an element with index " ++ show i
101+
]
102+
Nothing ->
103+
errorBecause "not found in map"
104+
where
105+
errorBecause msg = error $
106+
"lookupClassRep: Equivalence class index " ++ show rC ++ " " ++ msg
107+
88108
-- | Creates a new class with the given descriptor.
89109
freshClass :: d -> Action d (Class d)
90110
freshClass d = UF $ do
@@ -118,14 +138,14 @@ setEqual :: Class d
118138
-> d -- ^ Descriptor for union class.
119139
-> Action d AssertResult
120140
setEqual x y d = do
121-
Class xr <- classRep x
122-
Class yr <- classRep y
141+
xc@(Class xr) <- classRep x
142+
yc@(Class yr) <- classRep y
123143
if xr == yr
124144
then return AssertRedundant
125145
else do
126-
m <- UF $ gets ufsMap
127-
let Rep xne xsz _xd = m Map.! xr
128-
let Rep yne ysz _yd = m Map.! yr
146+
uf <- UF get
147+
let (xne, xsz, _xd) = lookupClassRep xc uf
148+
let (yne, ysz, _yd) = lookupClassRep yc uf
129149
xElts <- fmap (map toClassIdx) $ mapM classRep (map Class xne)
130150
yElts <- fmap (map toClassIdx) $ mapM classRep (map Class yne)
131151
if xr `elem` yElts || yr `elem` xElts
@@ -151,14 +171,14 @@ setEqual x y d = do
151171
-- previously set equal.
152172
setUnequal :: Class d -> Class d -> Action d AssertResult
153173
setUnequal x y = do
154-
Class xr <- classRep x
155-
Class yr <- classRep y
174+
xc@(Class xr) <- classRep x
175+
yc@(Class yr) <- classRep y
156176
if xr == yr
157177
then return AssertFailed
158178
else do
159-
m <- UF $ gets ufsMap
160-
let Rep xne xsz xd = m Map.! xr
161-
let Rep yne _ _ = m Map.! yr
179+
uf <- UF get
180+
let (xne, xsz, xd) = lookupClassRep xc uf
181+
let (yne, _, _) = lookupClassRep yc uf
162182
xElts <- fmap (map toClassIdx) $ mapM classRep (map Class xne)
163183
yElts <- fmap (map toClassIdx) $ mapM classRep (map Class yne)
164184
if xr `elem` yElts || yr `elem` xElts
@@ -172,24 +192,23 @@ setUnequal x y = do
172192
-- | Get a class description
173193
readClassDesc :: Class d -> Action d d
174194
readClassDesc c = do
175-
Class rC <- classRep c
176-
m <- UF $ gets ufsMap
177-
let Rep _ _ desc = m Map.! rC
195+
rCls <- classRep c
196+
s <- UF get
197+
let (_, _, desc) = lookupClassRep rCls s
178198
return desc
179199

180200
-- | Set a class description
181201
writeClassDesc :: Class d -> d -> Action d ()
182202
writeClassDesc c d = do
183-
Class rC <- classRep c
203+
rCls@(Class rC) <- classRep c
184204
UF $ modify $ \s ->
185-
let Rep dis sz _ = (ufsMap s) Map.! rC
205+
let (dis, sz, _) = lookupClassRep rCls s
186206
in s { ufsMap = Map.insert rC (Rep dis sz d) (ufsMap s) }
187207

188208
-- | Modify a class description
189209
modifyClassDesc :: Class d -> (d -> d) -> Action d ()
190210
modifyClassDesc c fn = do
191-
Class rC <- classRep c
211+
rCls@(Class rC) <- classRep c
192212
UF $ modify $ \s ->
193-
let Rep dis sz desc = (ufsMap s) Map.! rC
213+
let (dis, sz, desc) = lookupClassRep rCls s
194214
in s { ufsMap = Map.insert rC (Rep dis sz (fn desc)) (ufsMap s) }
195-

saw-remote-api/saw-remote-api.cabal

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ common errors
3434
-Werror=overlapping-patterns
3535

3636
common deps
37-
build-depends: base >=4.11.1.0 && <4.16,
38-
aeson >= 1.4.2 && < 2.0,
37+
build-depends: base >=4.11.1.0 && <4.17,
38+
aeson >= 1.4.2 && < 2.1,
3939
aig,
4040
argo,
4141
base64-bytestring,

0 commit comments

Comments
 (0)