Skip to content

Commit ec73f82

Browse files
authored
Merge pull request #1453 from GaloisInc/primitive-parameter
Opaque constants
2 parents c91d7b1 + f1c596b commit ec73f82

File tree

17 files changed

+202
-69
lines changed

17 files changed

+202
-69
lines changed

cryptol-saw-core/src/Verifier/SAW/Cryptol.hs

+59-26
Original file line numberDiff line numberDiff line change
@@ -653,17 +653,31 @@ proveProp sc env prop =
653653

654654
_ -> do panic "proveProp" [pretty prop]
655655

656-
importPrimitive :: SharedContext -> Env -> C.Name -> C.Schema -> IO Term
657-
importPrimitive sc env n sch
656+
importPrimitive :: SharedContext -> ImportPrimitiveOptions -> Env -> C.Name -> C.Schema -> IO Term
657+
importPrimitive sc primOpts env n sch
658+
-- lookup primitive in the main primitive lookup table
658659
| Just nm <- C.asPrim n, Just term <- Map.lookup nm allPrims = term sc
660+
661+
-- lookup primitive in the main reference implementation lookup table
659662
| Just nm <- C.asPrim n, Just expr <- Map.lookup nm (envRefPrims env) =
660663
do t <- importSchema sc env sch
661664
e <- importExpr sc env expr
662665
nmi <- importName n
663666
scConstant' sc nmi e t
667+
668+
-- Optionally, create an opaque constant representing the primitive
669+
-- if it doesn't match one of the ones we know about.
670+
| Just _ <- C.asPrim n, allowUnknownPrimitives primOpts =
671+
do t <- importSchema sc env sch
672+
nmi <- importName n
673+
scOpaqueConstant sc nmi t
674+
675+
-- Panic if we don't know the given primitive (TODO? probably shouldn't be a panic)
664676
| Just nm <- C.asPrim n = panic "Unknown Cryptol primitive name" [show nm]
677+
665678
| otherwise = panic "Improper Cryptol primitive name" [show n]
666679

680+
667681
allPrims :: Map C.PrimIdent (SharedContext -> IO Term)
668682
allPrims = prelPrims <> arrayPrims <> floatPrims <> suiteBPrims <> primeECPrims
669683

@@ -1245,9 +1259,9 @@ importName cnm =
12451259
-- definitions. (With subterm sharing, this is not as bad as it might
12461260
-- seem.) We might want to think about generating let or where
12471261
-- expressions instead.
1248-
importDeclGroup :: Bool -> SharedContext -> Env -> C.DeclGroup -> IO Env
1262+
importDeclGroup :: DeclGroupOptions -> SharedContext -> Env -> C.DeclGroup -> IO Env
12491263

1250-
importDeclGroup isTopLevel sc env (C.Recursive [decl]) =
1264+
importDeclGroup declOpts sc env (C.Recursive [decl]) =
12511265
case C.dDefinition decl of
12521266
C.DPrim ->
12531267
panic "importDeclGroup" ["Primitive declarations cannot be recursive:", show (C.dName decl)]
@@ -1258,11 +1272,11 @@ importDeclGroup isTopLevel sc env (C.Recursive [decl]) =
12581272
let x = nameToLocalName (C.dName decl)
12591273
f' <- scLambda sc x t' e'
12601274
rhs <- scGlobalApply sc "Prelude.fix" [t', f']
1261-
rhs' <- if isTopLevel then
1262-
do nmi <- importName (C.dName decl)
1263-
scConstant' sc nmi rhs t'
1264-
else
1265-
return rhs
1275+
rhs' <- case declOpts of
1276+
TopLevelDeclGroup _ ->
1277+
do nmi <- importName (C.dName decl)
1278+
scConstant' sc nmi rhs t'
1279+
NestedDeclGroup -> return rhs
12661280
let env' = env { envE = Map.insert (C.dName decl) (rhs', 0) (envE env)
12671281
, envC = Map.insert (C.dName decl) (C.dSignature decl) (envC env) }
12681282
return env'
@@ -1272,7 +1286,7 @@ importDeclGroup isTopLevel sc env (C.Recursive [decl]) =
12721286
-- We handle this by "tupling up" all the declarations using a record and
12731287
-- taking the fixpoint at this record type. The desired declarations are then
12741288
-- achieved by projecting the field names from this record.
1275-
importDeclGroup isTopLevel sc env (C.Recursive decls) =
1289+
importDeclGroup declOpts sc env (C.Recursive decls) =
12761290
do -- build the environment for the declaration bodies
12771291
let dm = Map.fromList [ (C.dName d, d) | d <- decls ]
12781292

@@ -1319,44 +1333,63 @@ importDeclGroup isTopLevel sc env (C.Recursive decls) =
13191333
let mkRhs d t =
13201334
do let s = nameToFieldName (C.dName d)
13211335
r <- scRecordSelect sc rhs s
1322-
if isTopLevel then
1323-
do nmi <- importName (C.dName d)
1324-
scConstant' sc nmi r t
1325-
else
1326-
return r
1336+
case declOpts of
1337+
TopLevelDeclGroup _ ->
1338+
do nmi <- importName (C.dName d)
1339+
scConstant' sc nmi r t
1340+
NestedDeclGroup -> return r
13271341
rhss <- sequence (Map.intersectionWith mkRhs dm tm)
13281342

13291343
let env' = env { envE = Map.union (fmap (\v -> (v, 0)) rhss) (envE env)
13301344
, envC = Map.union (fmap C.dSignature dm) (envC env)
13311345
}
13321346
return env'
13331347

1334-
importDeclGroup isTopLevel sc env (C.NonRecursive decl) =
1348+
importDeclGroup declOpts sc env (C.NonRecursive decl) =
13351349
case C.dDefinition decl of
13361350
C.DPrim
1337-
| isTopLevel -> do
1338-
rhs <- importPrimitive sc env (C.dName decl) (C.dSignature decl)
1351+
| TopLevelDeclGroup primOpts <- declOpts -> do
1352+
rhs <- importPrimitive sc primOpts env (C.dName decl) (C.dSignature decl)
13391353
let env' = env { envE = Map.insert (C.dName decl) (rhs, 0) (envE env)
1340-
, envC = Map.insert (C.dName decl) (C.dSignature decl) (envC env) }
1354+
, envC = Map.insert (C.dName decl) (C.dSignature decl) (envC env)
1355+
}
13411356
return env'
13421357
| otherwise -> do
13431358
panic "importDeclGroup" ["Primitive declarations only allowed at top-level:", show (C.dName decl)]
13441359

13451360
C.DExpr expr -> do
13461361
rhs <- importExpr' sc env (C.dSignature decl) expr
1347-
rhs' <- if not isTopLevel then return rhs else do
1348-
nmi <- importName (C.dName decl)
1349-
t <- importSchema sc env (C.dSignature decl)
1350-
scConstant' sc nmi rhs t
1362+
rhs' <- case declOpts of
1363+
TopLevelDeclGroup _ ->
1364+
do nmi <- importName (C.dName decl)
1365+
t <- importSchema sc env (C.dSignature decl)
1366+
scConstant' sc nmi rhs t
1367+
NestedDeclGroup -> return rhs
13511368
let env' = env { envE = Map.insert (C.dName decl) (rhs', 0) (envE env)
13521369
, envC = Map.insert (C.dName decl) (C.dSignature decl) (envC env) }
13531370
return env'
13541371

1372+
data ImportPrimitiveOptions =
1373+
ImportPrimitiveOptions
1374+
{ allowUnknownPrimitives :: Bool
1375+
-- ^ Should unknown primitives be translated as fresh external constants?
1376+
}
1377+
1378+
defaultPrimitiveOptions :: ImportPrimitiveOptions
1379+
defaultPrimitiveOptions =
1380+
ImportPrimitiveOptions
1381+
{ allowUnknownPrimitives = False
1382+
}
1383+
1384+
data DeclGroupOptions
1385+
= TopLevelDeclGroup ImportPrimitiveOptions
1386+
| NestedDeclGroup
1387+
13551388
importDeclGroups :: SharedContext -> Env -> [C.DeclGroup] -> IO Env
1356-
importDeclGroups sc = foldM (importDeclGroup False sc)
1389+
importDeclGroups sc = foldM (importDeclGroup NestedDeclGroup sc)
13571390

1358-
importTopLevelDeclGroups :: SharedContext -> Env -> [C.DeclGroup] -> IO Env
1359-
importTopLevelDeclGroups sc = foldM (importDeclGroup True sc)
1391+
importTopLevelDeclGroups :: SharedContext -> ImportPrimitiveOptions -> Env -> [C.DeclGroup] -> IO Env
1392+
importTopLevelDeclGroups sc primOpts = foldM (importDeclGroup (TopLevelDeclGroup primOpts) sc)
13601393

13611394
coerceTerm :: SharedContext -> Env -> C.Type -> C.Type -> Term -> IO Term
13621395
coerceTerm sc env t1 t2 e

cryptol-saw-core/src/Verifier/SAW/CryptolEnv.hs

+11-6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ module Verifier.SAW.CryptolEnv
3333
, lookupIn
3434
, resolveIdentifier
3535
, meSolverConfig
36+
, C.ImportPrimitiveOptions(..)
37+
, C.defaultPrimitiveOptions
3638
)
3739
where
3840

@@ -309,7 +311,7 @@ translateDeclGroups ::
309311
SharedContext -> CryptolEnv -> [T.DeclGroup] -> IO CryptolEnv
310312
translateDeclGroups sc env dgs =
311313
do cryEnv <- mkCryEnv env
312-
cryEnv' <- C.importTopLevelDeclGroups sc cryEnv dgs
314+
cryEnv' <- C.importTopLevelDeclGroups sc C.defaultPrimitiveOptions cryEnv dgs
313315
termEnv' <- traverse (\(t, j) -> incVars sc 0 j t) (C.envE cryEnv')
314316

315317
let decls = concatMap T.groupDecls dgs
@@ -328,7 +330,7 @@ genTermEnv sc modEnv cryEnv0 = do
328330
let declGroups = concatMap T.mDecls
329331
$ filter (not . T.isParametrizedModule)
330332
$ ME.loadedModules modEnv
331-
cryEnv <- C.importTopLevelDeclGroups sc cryEnv0 declGroups
333+
cryEnv <- C.importTopLevelDeclGroups sc C.defaultPrimitiveOptions cryEnv0 declGroups
332334
traverse (\(t, j) -> incVars sc 0 j t) (C.envE cryEnv)
333335

334336
--------------------------------------------------------------------------------
@@ -343,9 +345,12 @@ checkNotParameterized m =
343345

344346
loadCryptolModule ::
345347
(?fileReader :: FilePath -> IO ByteString) =>
346-
SharedContext -> CryptolEnv -> FilePath ->
348+
SharedContext ->
349+
C.ImportPrimitiveOptions ->
350+
CryptolEnv ->
351+
FilePath ->
347352
IO (CryptolModule, CryptolEnv)
348-
loadCryptolModule sc env path = do
353+
loadCryptolModule sc primOpts env path = do
349354
let modEnv = eModuleEnv env
350355
(m, modEnv') <- liftModuleM modEnv (MB.loadModuleByPath path)
351356
checkNotParameterized m
@@ -361,7 +366,7 @@ loadCryptolModule sc env path = do
361366
let isNew m' = T.mName m' `notElem` oldModNames
362367
let newModules = filter isNew $ map ME.lmModule $ ME.lmLoadedModules $ ME.meLoadedModules modEnv''
363368
let newDeclGroups = concatMap T.mDecls newModules
364-
newCryEnv <- C.importTopLevelDeclGroups sc oldCryEnv newDeclGroups
369+
newCryEnv <- C.importTopLevelDeclGroups sc primOpts oldCryEnv newDeclGroups
365370
newTermEnv <- traverse (\(t, j) -> incVars sc 0 j t) (C.envE newCryEnv)
366371

367372
let names = MEx.exported C.NSValue (T.mExports m) -- :: Set T.Name
@@ -422,7 +427,7 @@ importModule sc env src as vis imps = do
422427
let isNew m' = T.mName m' `notElem` oldModNames
423428
let newModules = filter isNew $ map ME.lmModule $ ME.lmLoadedModules $ ME.meLoadedModules modEnv'
424429
let newDeclGroups = concatMap T.mDecls newModules
425-
newCryEnv <- C.importTopLevelDeclGroups sc oldCryEnv newDeclGroups
430+
newCryEnv <- C.importTopLevelDeclGroups sc C.defaultPrimitiveOptions oldCryEnv newDeclGroups
426431
newTermEnv <- traverse (\(t, j) -> incVars sc 0 j t) (C.envE newCryEnv)
427432

428433
return env { eImports = (vis, P.Import (T.mName m) as imps) : eImports env

saw-core-coq/src/Language/Coq/AST.hs

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ data Decl
7070
= Axiom Ident Type
7171
| Comment String
7272
| Definition Ident [Binder] (Maybe Type) Term
73+
| Parameter Ident Type
74+
| Variable Ident Type
7375
| InductiveDecl Inductive
7476
| Snippet String
7577
deriving (Show)

saw-core-coq/src/Language/Coq/Pretty.hs

+6
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ ppDecl decl = case decl of
146146
Axiom nm ty ->
147147
(nest 2 $
148148
hsep ([text "Axiom", text nm, text ":", ppTerm PrecNone ty, period])) <> hardline
149+
Parameter nm ty ->
150+
(nest 2 $
151+
hsep ([text "Parameter", text nm, text ":", ppTerm PrecNone ty, period])) <> hardline
152+
Variable nm ty ->
153+
(nest 2 $
154+
hsep ([text "Variable", text nm, text ":", ppTerm PrecNone ty, period])) <> hardline
149155
Comment s ->
150156
text "(*" <+> text s <+> text "*)" <> hardline
151157
Definition nm bs mty body ->

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

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import Verifier.SAW.Translation.Coq.Monad
1616
import qualified Verifier.SAW.Translation.Coq.Term as TermTranslation
1717
import Verifier.SAW.TypedTerm
1818

19+
20+
1921
translateTypedTermMap ::
2022
TermTranslation.TermTranslationMonad m => Map.Map Name TypedTerm -> m [Coq.Decl]
2123
translateTypedTermMap tm = forM (Map.assocs tm) translateAndRegisterEntry

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

+60-10
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ namedDecls = concatMap filterNamed
130130
where
131131
filterNamed :: Coq.Decl -> [String]
132132
filterNamed (Coq.Axiom n _) = [n]
133+
filterNamed (Coq.Parameter n _) = [n]
134+
filterNamed (Coq.Variable n _) = [n]
133135
filterNamed (Coq.Comment _) = []
134136
filterNamed (Coq.Definition n _ _ _) = [n]
135137
filterNamed (Coq.InductiveDecl (Coq.Inductive n _ _ _ _)) = [n]
@@ -292,7 +294,25 @@ flatTermFToExpr tf = -- traceFTermF "flatTermFToExpr" tf $
292294
in
293295
foldM addElement (Coq.App (Coq.Var "Vector.nil") [Coq.Var "_"]) (Vector.reverse vec)
294296
StringLit s -> pure (Coq.Scope (Coq.StringLit (Text.unpack s)) "string")
295-
ExtCns (EC _ _ _) -> errorTermM "External constants not supported"
297+
298+
ExtCns ec ->
299+
do configuration <- asks translationConfiguration
300+
let renamed = translateConstant (notations configuration) ec
301+
alreadyTranslatedDecls <- getNamesOfAllDeclarations
302+
let definitionsToSkip = skipDefinitions configuration
303+
if elem renamed alreadyTranslatedDecls || elem renamed definitionsToSkip
304+
then Coq.Var <$> pure renamed
305+
else do
306+
tp <-
307+
-- Translate type in a top-level name scope
308+
withLocalTranslationState $
309+
do modify $ set localEnvironment []
310+
modify $ set unavailableIdents reservedIdents
311+
modify $ set sharedNames IntMap.empty
312+
modify $ set nextSharedName "var__0"
313+
translateTermLet (ecType ec)
314+
modify $ over topLevelDeclarations $ (Coq.Variable renamed tp :)
315+
Coq.Var <$> pure renamed
296316

297317
-- The translation of a record type {fld1:tp1, ..., fldn:tpn} is
298318
-- RecordTypeCons fld1 tp1 (... (RecordTypeCons fldn tpn RecordTypeNil)...).
@@ -579,8 +599,28 @@ translateTermUnshared t = withLocalTranslationState $ do
579599
| n < length env -> Coq.Var <$> pure (env !! n)
580600
| otherwise -> Except.throwError $ LocalVarOutOfBounds t
581601

582-
-- Constants come with a body
583-
Constant n body -> do
602+
-- Constants with no body
603+
Constant n Nothing -> do
604+
configuration <- asks translationConfiguration
605+
let renamed = translateConstant (notations configuration) n
606+
alreadyTranslatedDecls <- getNamesOfAllDeclarations
607+
let definitionsToSkip = skipDefinitions configuration
608+
if elem renamed alreadyTranslatedDecls || elem renamed definitionsToSkip
609+
then Coq.Var <$> pure renamed
610+
else do
611+
tp <-
612+
-- Translate type in a top-level name scope
613+
withLocalTranslationState $
614+
do modify $ set localEnvironment []
615+
modify $ set unavailableIdents reservedIdents
616+
modify $ set sharedNames IntMap.empty
617+
modify $ set nextSharedName "var__0"
618+
translateTermLet (ecType n)
619+
modify $ over topLevelDeclarations $ (Coq.Parameter renamed tp :)
620+
Coq.Var <$> pure renamed
621+
622+
-- Constants with a body
623+
Constant n (Just body) -> do
584624
configuration <- asks translationConfiguration
585625
let renamed = translateConstant (notations configuration) n
586626
alreadyTranslatedDecls <- getNamesOfAllDeclarations
@@ -603,13 +643,17 @@ translateTermUnshared t = withLocalTranslationState $ do
603643
badTerm = Except.throwError $ BadTerm t
604644

605645
-- | In order to turn fixpoint computations into iterative computations, we need
606-
-- to be able to create "dummy" values at the type of the computation. For now,
607-
-- we will support arbitrary nesting of vectors of boolean values.
646+
-- to be able to create "dummy" values at the type of the computation.
608647
defaultTermForType ::
609648
TermTranslationMonad m =>
610649
Term -> m Coq.Term
611650
defaultTermForType typ = do
612651
case typ of
652+
(asBoolType -> Just ()) -> translateIdent (mkIdent preludeName "False")
653+
654+
(isGlobalDef "Prelude.Nat" -> Just ()) -> return $ Coq.NatLit 0
655+
656+
(asIntegerType -> Just ()) -> return $ Coq.ZLit 0
613657

614658
(asSeq -> Just (n, typ')) -> do
615659
seqConst <- translateIdent (mkIdent (mkModuleName ["Cryptol"]) "seqConst")
@@ -618,13 +662,19 @@ defaultTermForType typ = do
618662
defaultT <- defaultTermForType typ'
619663
return $ Coq.App seqConst [ nT, typ'T, defaultT ]
620664

621-
(asBoolType -> Just ()) -> translateIdent (mkIdent preludeName "False")
665+
(asPairType -> Just (x,y)) -> do
666+
x' <- defaultTermForType x
667+
y' <- defaultTermForType y
668+
return $ Coq.App (Coq.Var "pair") [x',y']
622669

623-
_ ->
624-
return $ Coq.App (Coq.Var "error")
625-
[Coq.StringLit ("Could not generate default value of type " ++ showTerm typ)]
670+
(asPiList -> (bs,body))
671+
| not (null bs)
672+
, looseVars body == emptyBitSet ->
673+
do bs' <- forM bs $ \ (_nm, ty) -> Coq.Binder "_" . Just <$> translateTerm ty
674+
body' <- defaultTermForType body
675+
return $ Coq.Lambda bs' body'
626676

627-
-- _ -> Except.throwError $ CannotCreateDefaultValue typ
677+
_ -> Except.throwError $ CannotCreateDefaultValue typ
628678

629679
translateTermToDocWith ::
630680
TranslationConfiguration ->

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,12 @@ scWriteExternal t0 =
134134
Lambda s t e -> pure $ unwords ["Lam", Text.unpack s, show t, show e]
135135
Pi s t e -> pure $ unwords ["Pi", Text.unpack s, show t, show e]
136136
LocalVar i -> pure $ unwords ["Var", show i]
137-
Constant ec e ->
137+
Constant ec (Just e) ->
138138
do stashName ec
139139
pure $ unwords ["Constant", show (ecVarIndex ec), show (ecType ec), show e]
140+
Constant ec Nothing ->
141+
do stashName ec
142+
pure $ unwords ["ConstantOpaque", show (ecVarIndex ec), show (ecType ec)]
140143
FTermF ftf ->
141144
case ftf of
142145
Primitive ec ->
@@ -295,7 +298,8 @@ scReadExternal sc input =
295298
["Lam", x, t, e] -> Lambda (Text.pack x) <$> readIdx t <*> readIdx e
296299
["Pi", s, t, e] -> Pi (Text.pack s) <$> readIdx t <*> readIdx e
297300
["Var", i] -> pure $ LocalVar (read i)
298-
["Constant",i,t,e] -> Constant <$> readEC i t <*> readIdx e
301+
["Constant",i,t,e] -> Constant <$> readEC i t <*> (Just <$> readIdx e)
302+
["ConstantOpaque",i,t] -> Constant <$> readEC i t <*> pure Nothing
299303
["Primitive", i, t] -> FTermF <$> (Primitive <$> readPrimName i t)
300304
["Unit"] -> pure $ FTermF UnitValue
301305
["UnitT"] -> pure $ FTermF UnitType

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ asLocalVar :: Recognizer Term DeBruijnIndex
313313
asLocalVar (unwrapTermF -> LocalVar i) = return i
314314
asLocalVar _ = Nothing
315315

316-
asConstant :: Recognizer Term (ExtCns Term, Term)
317-
asConstant (unwrapTermF -> Constant ec t) = return (ec, t)
316+
asConstant :: Recognizer Term (ExtCns Term, Maybe Term)
317+
asConstant (unwrapTermF -> Constant ec mt) = return (ec, mt)
318318
asConstant _ = Nothing
319319

320320
asExtCns :: Recognizer Term (ExtCns Term)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ ruleOfProp (R.asApplyAll -> (R.isGlobalDef intEqIdent -> Just (), [x, y])) ann =
360360
Just $ mkRewriteRule [] x y ann
361361
ruleOfProp (R.asApplyAll -> (R.isGlobalDef intModEqIdent -> Just (), [_, x, y])) ann =
362362
Just $ mkRewriteRule [] x y ann
363-
ruleOfProp (unwrapTermF -> Constant _ body) ann = ruleOfProp body ann
363+
ruleOfProp (unwrapTermF -> Constant _ (Just body)) ann = ruleOfProp body ann
364364
ruleOfProp (R.asEq -> Just (_, x, y)) ann =
365365
Just $ mkRewriteRule [] x y ann
366366
ruleOfProp (R.asEqTrue -> Just body) ann = ruleOfProp body ann

0 commit comments

Comments
 (0)