summaryrefslogtreecommitdiff
path: root/source/Test/Unit/Module.hs
diff options
context:
space:
mode:
Diffstat (limited to 'source/Test/Unit/Module.hs')
-rw-r--r--source/Test/Unit/Module.hs2665
1 files changed, 1873 insertions, 792 deletions
diff --git a/source/Test/Unit/Module.hs b/source/Test/Unit/Module.hs
index 1cf62e5..fbc6c0d 100644
--- a/source/Test/Unit/Module.hs
+++ b/source/Test/Unit/Module.hs
@@ -21,7 +21,6 @@ import Checking.Typed.Inductive qualified as TypedInductive
import CommandLine qualified
import Felix.Module
import Felix.Math.Codec
-import Felix.Migration qualified as Migration
import Felix.Parse qualified as Parse
import Felix.Prelude qualified as Prelude
import Felix.Source
@@ -33,21 +32,45 @@ import Paths_felix qualified as Paths
import Syntax.Abstract qualified as Raw
import Syntax.Internal qualified as Internal
import Syntax.Interface qualified as Syntax
-
-import Bound.Scope (fromScope)
-import Bound.Var (Var(..))
+import Syntax.Pragma qualified as Pragma
+
+import Control.Concurrent (threadDelay)
+import Control.Concurrent.STM
+ ( atomically
+ , check
+ , newEmptyTMVarIO
+ , newTQueueIO
+ , newTVarIO
+ , putTMVar
+ , readTQueue
+ , readTVar
+ , takeTMVar
+ , tryReadTMVar
+ , tryReadTQueue
+ , writeTQueue
+ , writeTVar
+ )
import Control.Exception (bracket)
-import Control.Monad (foldM)
+import Control.Monad (foldM, when)
import Data.ByteString qualified as ByteString
import Data.Text qualified as StrictText
import Data.Text.Encoding qualified as Text
import Control.Monad.Logger (runNoLoggingT)
-import Data.IORef (IORef, modifyIORef', newIORef, readIORef)
+import Data.IORef
+ ( IORef
+ , atomicModifyIORef'
+ , modifyIORef'
+ , newIORef
+ , readIORef
+ )
+import Data.List (sort)
+import Data.List.NonEmpty qualified as NonEmpty
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Data.Vector qualified as Vector
import System.Directory
( createDirectoryIfMissing
+ , doesFileExist
, getCurrentDirectory
, getPermissions
, setOwnerExecutable
@@ -55,8 +78,10 @@ import System.Directory
)
import System.FilePath.Posix qualified as Posix
import System.IO.Temp qualified as Temp
+import System.Timeout qualified as Timeout
import Test.Tasty
import Test.Tasty.HUnit
+import UnliftIO.Async (withAsync, wait)
unitTests :: TestTree
@@ -68,26 +93,28 @@ unitTests =
identifiesCommentOnlyInput
, testCase "loads and parses the packaged final prelude"
parsesPackagedFinalPrelude
+ , testCase "renders packaged final-prelude failures"
+ rendersPackagedPreludeFailures
, testCase "confines exact foundation-leaf completion"
confinesFoundationLeafCompletion
, testCase "builds the confined final prelude"
buildsConfinedFinalPrelude
, testCase "publishes the final prelude as an ordinary sealed root"
publishesFinalPreludeRoot
- , testCase "checks the protected nat closure with the final prelude"
- checksProtectedNatClosure
- , testCase "checks Phase 5.3 library closures with the final prelude"
- checksPhase53LibraryClosures
, testCase "retains exact omitted-proof locations"
retainsExactOmittedProofLocation
, testCase "coalesces syntax without collapsing semantic imports"
coalescesSharedDirectSyntax
- , testCase "resets gloss state between modules"
- resetsGlossStatePerModule
, testCase "makes selected source errors terminal"
rejectsUnsupportedTypedSource
, testCase "compiles exact declarations across an import"
compilesExactDeclarationGraph
+ , testCase "compiles and imports exact structures"
+ compilesExactStructures
+ , testCase "compiles and caches contextual abbreviations"
+ compilesContextualAbbreviations
+ , testCase "rejects an unknown exact structure parent atomically"
+ rejectsUnknownExactStructureParent
, testCase "compiles exact relation expressions"
compilesExactRelationExpressions
, testCase "resolves source-owned set application"
@@ -98,6 +125,8 @@ unitTests =
compilesExactOrdinaryProofs
, testCase "compiles and reuses proof-local set definitions"
compilesAndReusesProofLocalSetDefinitions
+ , testCase "compiles and reuses proof-local function graphs"
+ compilesAndReusesProofLocalFunctionGraphs
, testCase "confines terminal exact contradiction"
confinesTerminalExactContradiction
, testCase "compiles exact separation comprehensions"
@@ -146,9 +175,21 @@ unitTests =
keepsExactSemanticsIndependentOfFixity
, testCase "loads a cached exact producer for a fresh importer"
loadsCachedExactProducerForFreshImporter
+ , testCase "reports admitted source escapes on fresh, warm, and failure paths"
+ reportsAdmittedSourceEscapes
+ , testCase "selects concurrent module failures by source order"
+ selectsConcurrentModuleFailureDeterministically
+ , testCase "batches independent structure obligations atomically"
+ batchesStructureObligationsAtomically
+ , testCase "keeps dependent proof obligations sequential"
+ keepsDependentProofObligationsSequential
+ , testCase "starts diamond consumers after sealed acknowledgements"
+ schedulesDiamondAfterSealedImports
+ , testCase "classifies typed Vampire failures conservatively"
+ classifiesTypedVampireFailures
, testCase "retains the exact prefix before a later failure"
retainsExactPrefixBeforeFailure
- , testCase "routes production verification by complete graph"
+ , testCase "routes every production root through exact checking"
routesProductionVerification
, testCase "installs nonempty implicit prelude evidence"
installsNonemptyImplicitPreludeEvidence
@@ -285,6 +326,30 @@ parsesPackagedFinalPrelude = do
(Syntax.moduleSyntaxAssertedId
(Parse.identifiedParsedModuleSyntaxInterface secondParsed))
+rendersPackagedPreludeFailures :: Assertion
+rendersPackagedPreludeFailures = do
+ assertEqual "load failure"
+ "/missing/felix-prelude.tex: unable to read packaged final prelude: not found"
+ (Prelude.renderPreludeLoadError
+ (Prelude.PreludeSourceReadFailed
+ "/missing/felix-prelude.tex"
+ "not found"))
+ assertEqual "located syntax failure"
+ "<felix-prelude>: syntax pragma location is out of range at 7:3"
+ (Prelude.renderPreludeParseError parseFailure)
+ assertEqual "authority-free API presentation"
+ ("packaged final prelude parsing failed: "
+ <> "<felix-prelude>: syntax pragma location is out of range at 7:3")
+ (Api.renderAuthorityFreeParseError
+ (Api.AuthorityFreePreludeParseFailed parseFailure))
+ where
+ parseFailure =
+ Prelude.PreludeSyntaxPragmaFailed
+ (Pragma.SyntaxPragmaLocationOutOfRange
+ Prelude.preludeDiagnosticLabel
+ 7
+ 3)
+
confinesFoundationLeafCompletion :: Assertion
confinesFoundationLeafCompletion = do
foundation <- expectRight Foundation.checkedFoundation
@@ -387,6 +452,54 @@ buildsConfinedFinalPrelude = do
[]
(Semantic.semanticInterfaceDirectInputs
(FinalPrelude.finalPreludeSemantic candidate))
+ let baseDeltas =
+ [ delta
+ | delta <- Semantic.semanticInterfaceDeclarations
+ (FinalPrelude.finalPreludeSemantic candidate)
+ , not
+ (null
+ (Semantic.semanticEnvironmentStructures
+ (Semantic.declarationDeltaEnvironment delta)))
+ ]
+ case baseDeltas of
+ [delta] -> do
+ assertEqual "base structure has no facts"
+ []
+ (Semantic.declarationDeltaFacts delta)
+ assertEqual "base structure has no propositions"
+ []
+ (Semantic.declarationDeltaPropositions delta)
+ case Semantic.semanticEnvironmentStructures
+ (Semantic.declarationDeltaEnvironment delta) of
+ [descriptor] -> do
+ assertEqual "base structure is metadata-only"
+ Nothing
+ (Semantic.semanticStructureDescriptorPredicate
+ descriptor)
+ case Semantic.semanticStructureDescriptorOperations
+ descriptor of
+ [operation] ->
+ case Identity.lookupCheckedObjectContent
+ (Semantic.semanticStructureOperationObject
+ operation)
+ (FinalPrelude.finalPreludeObjects candidate) of
+ Just Identity.OpaqueObjectContent{} -> pure ()
+ content ->
+ assertFailure
+ ("expected opaque carrier, got "
+ <> show content)
+ operations ->
+ assertFailure
+ ("expected one base operation, got "
+ <> show operations)
+ descriptors ->
+ assertFailure
+ ("expected one base descriptor, got "
+ <> show descriptors)
+ deltas ->
+ assertFailure
+ ("expected one base structure delta, got "
+ <> show (length deltas))
let role roleName =
maybe
(assertFailure
@@ -395,13 +508,13 @@ buildsConfinedFinalPrelude = do
pure
(FinalPrelude.finalPreludePublicRole
candidate roleName)
- omega <- role Migration.PreludeOmegaObject
- naturals <- role Migration.PreludeNaturalsAlias
+ omega <- role FinalPrelude.PreludeOmegaObject
+ naturals <- role FinalPrelude.PreludeNaturalsAlias
assertEqual "naturals expands to Omega"
omega naturals
traverse_
(void . role)
- (Set.toList Migration.expectedFinalPreludePublicRoles)
+ (Set.toList FinalPrelude.expectedFinalPreludePublicRoles)
let foundationTags = Set.fromList
[ tag
| batch <-
@@ -459,518 +572,61 @@ publishesFinalPreludeRoot = do
Store.openStore path theory >>= expectRight
pure store
bracket open Store.closeStore \store -> do
+ freshMemo <- Store.newStoreMemo store
session <-
expectRight
- =<< Module.buildFinalPreludeSession
- store foundation finalPreludeResolver
- let input = Module.migrationPreludeInput session
- sealed = Module.migrationPreludeModule session
+ =<< Module.acquireFinalPreludeSession
+ freshMemo store foundation finalPreludeResolver
+ let input = Module.finalPreludeInput session
+ sealed = Module.finalPreludeModule session
syntax = Module.sealedTypedModuleSyntax sealed
semantic = Module.sealedTypedModuleSemantic sealed
+ assertEqual "empty store constructs the final-prelude root"
+ Module.ModuleRootMiss
+ (Module.finalPreludeAcquisition session)
assertEqual "final prelude owner"
preludeModuleName
(Module.identifiedModuleOwner input)
assertEqual "final prelude has no semantic parents"
[]
(Semantic.semanticInterfaceDirectInputs semantic)
- key <- expectRight
- (Semantic.moduleArtifactKey
- preludeModuleName
- (Parse.identifiedParsedModuleId
- (Module.identifiedModuleParsed input))
- []
- theory)
- memo <- Store.newStoreMemo store
- loaded <- expectRight
- =<< Store.loadCachedModuleInstallation
- memo
- store
- key
- (Syntax.moduleSyntaxAssertedId syntax)
- installation <- maybe
- (assertFailure "final prelude root was not installed"
- >> fail "unreachable")
- pure
- loaded
- cached <- expectRight
- (Module.cachedSealedTypedModule
- foundation [] installation)
+ warmMemo <- Store.newStoreMemo store
+ warmSession <- expectRight
+ =<< Module.acquireFinalPreludeSession
+ warmMemo store foundation unusedResolver
+ let cached = Module.finalPreludeModule warmSession
+ assertEqual "persisted final-prelude root is a cache hit"
+ Module.ModuleRootHit
+ (Module.finalPreludeAcquisition warmSession)
assertEqual "generic root syntax"
syntax
(Module.sealedTypedModuleSyntax cached)
assertEqual "generic root semantics"
semantic
(Module.sealedTypedModuleSemantic cached)
+ assertEqual "cached base structure descriptor"
+ (semanticStructureDescriptors semantic)
+ (semanticStructureDescriptors
+ (Module.sealedTypedModuleSemantic cached))
assertEqual "generic root final prefix"
(Declaration.pendingModulePrefixCurrent
(Module.sealedTypedModulePrefix sealed))
(Declaration.pendingModulePrefixCurrent
(Module.sealedTypedModulePrefix cached))
-
-checksProtectedNatClosure :: Assertion
-checksProtectedNatClosure = do
- foundation <- expectRight Foundation.checkedFoundation
- repository <- getCurrentDirectory
- Temp.withSystemTempDirectory "felix-protected-nat" \directory -> do
- let storePath = directory Posix.</> "store.sqlite"
- executable = directory Posix.</> "vampire"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for protected-core'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- runs <- newIORef (0 :: Int)
- let resolver = countingAcceptedResolver executable runs
- open = do
- (_startup, store) <-
- Store.openStore
- storePath
- (Identity.theoryId foundation)
- >>= expectRight
- pure store
- bracket open Store.closeStore \store -> do
- prelude <-
- expectRight
- =<< Module.buildFinalPreludeSession
- store foundation resolver
- mounts <- exactFixtureMounts repository
- workspace <- parseFinalExactWorkspace prelude mounts "nat.tex"
- sealed <- compileFinalParsedWorkspaceWithResolver
- foundation prelude resolver workspace
- let parsed = toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace)
- modules = Map.fromList
- [ ( safeRelativePathFilePath
- (resolvedSourceRelativePath
- (Parse.parsedModuleResolved source))
- , checked
- )
- | (source, checked) <- zip parsed sealed
- ]
- moduleAt path = maybe
- (assertFailure ("missing typed module " <> path)
- >> fail "unreachable")
- pure
- (Map.lookup path modules)
- assertEqual "protected module count"
- 5
- (length sealed)
- let preludeSyntaxId =
- Syntax.moduleSyntaxAssertedId
- (Module.sealedTypedModuleSyntax
- (Module.migrationPreludeModule prelude))
- preludeSemanticId =
- Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic
- (Module.migrationPreludeModule prelude))
- forM_
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- \parsedModule ->
- assertEqual "final prelude is the first syntax input"
- (Just preludeSyntaxId)
- (listToMaybe
- (Syntax.moduleSyntaxDirectInputs
- (Parse.parsedModuleSyntaxInterface
- parsedModule)))
- forM_ sealed \sealedModule ->
- assertEqual "final prelude is the first semantic input"
- (Just preludeSemanticId)
- (listToMaybe
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic sealedModule)))
- setModule <- moduleAt "set.tex"
- sucModule <- moduleAt "set/suc.tex"
- natModule <- moduleAt "nat.tex"
- assertLocalAliasesAbsent
- setModule
- [ "setext"
- , "emptyset"
- , "unions"
- , "unions_iff"
- ]
- assertLocalAliasesAbsent
- natModule
- [ "num_naturals_inductive_set"
- , "num_naturals_smallest_inductive_set"
- ]
- assertTransparentObjectAlias setModule "cons"
- assertTransparentObjectAlias setModule "union"
- pairIdentity <- localObjectKeyTarget
- setModule
- (Semantic.SemanticExpressionFunction
- (Raw.mixfixPattern Raw.PairSymbol))
- consBody <- localTransparentObjectBody setModule "cons"
- let expectedConsBody =
- Core.CLam Core.TySet
- (Core.CLam Core.TySet
- (Core.canonicalSetInsert
- (Core.CBound 1)
- (Core.CBound 0)))
- assertEqual "cons uses canonical set insertion"
- expectedConsBody consBody
- assertBool "cons does not use ordered pairing"
- ( pairIdentity
- `Set.notMember` Core.canonicalTermGlobals consBody
- )
- let preludeModule = Module.migrationPreludeModule prelude
- preludeSuccessor <-
- localObjectAliasTarget preludeModule "prelude_successor"
- sourceSuccessor <- localObjectAliasTarget sucModule "suc"
- assertEqual "source successor reuses packaged successor content"
- preludeSuccessor sourceSuccessor
- preludeSuccessorBody <-
- localTransparentObjectBody preludeModule "prelude_successor"
- assertEqual "packaged successor uses canonical set insertion"
- (Core.CLam Core.TySet
- (Core.canonicalSetInsert
- (Core.CBound 0)
- (Core.CBound 0)))
- preludeSuccessorBody
- assertBool "successor does not use ordered pairing"
- ( pairIdentity
- `Set.notMember`
- Core.canonicalTermGlobals preludeSuccessorBody
- )
- assertOpaqueObjectKey
- setModule
- "pair"
- (Semantic.SemanticExpressionFunction
- (Raw.mixfixPattern Raw.PairSymbol))
- assertCleanFactAlias setModule "cons_iff"
- assertCleanFactAlias setModule "union_iff"
- traverse_
- (assertSourceAxiomAlias setModule)
- [ "pair_eq_iff"
- , "fst_eq"
- , "snd_eq"
- ]
- assertBool "protected checking exercised Vampire"
- . (> 0)
- =<< readIORef runs
-
-checksPhase53LibraryClosures :: Assertion
-checksPhase53LibraryClosures = do
- foundation <- expectRight Foundation.checkedFoundation
- repository <- getCurrentDirectory
- Temp.withSystemTempDirectory "felix-phase53-library" \directory -> do
- let storePath = directory Posix.</> "store.sqlite"
- executable = directory Posix.</> "vampire"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for phase53-library'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- runs <- newIORef (0 :: Int)
- let resolver = countingAcceptedResolver executable runs
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- prelude <-
- expectRight
- =<< Module.buildFinalPreludeSession
- store foundation resolver
- mounts <- exactFixtureMounts repository
- selection <- expectRight
- (Migration.resolveMigrationSelection
- mounts Migration.typedMigrationModules)
- let preludeSyntaxId = Syntax.moduleSyntaxAssertedId
- (Module.sealedTypedModuleSyntax
- (Module.migrationPreludeModule prelude))
- preludeSemanticId =
- Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic
- (Module.migrationPreludeModule prelude))
- checkRoot path inspect = do
- workspace <- parseFinalExactWorkspace
- prelude mounts path
- assertEqual (path <> " graph route")
- Migration.TypedMigrationGraph
- (Migration.classifyMigrationGraph
- selection workspace)
- sealed <- compileFinalParsedWorkspaceWithResolver
- foundation prelude resolver workspace
- let parsed = toList
- (Parse.parsedWorkspaceImportedBeforeImporter
- workspace)
- modules = Map.fromList
- [ ( safeRelativePathFilePath
- (resolvedSourceRelativePath
- (Parse.parsedModuleResolved source))
- , (source, checked)
- )
- | (source, checked) <- zip parsed sealed
- ]
- moduleAt modulePath = maybe
- (assertFailure
- ("missing typed module " <> modulePath)
- >> fail "unreachable")
- pure
- (Map.lookup modulePath modules)
- assertEqual (path <> " module count")
- (length parsed)
- (length sealed)
- forM_ parsed \source ->
- assertEqual
- (path <> " final-prelude syntax input")
- (Just preludeSyntaxId)
- (listToMaybe
- (Syntax.moduleSyntaxDirectInputs
- (Parse.parsedModuleSyntaxInterface
- source)))
- forM_ sealed \checked ->
- assertEqual
- (path <> " final-prelude semantic input")
- (Just preludeSemanticId)
- (listToMaybe
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic
- checked)))
- inspect moduleAt
- unselectedImporter <- parseFinalExactWorkspace
- prelude mounts "set/equinumerosity.tex"
- assertEqual "unselected function importer graph route"
- Migration.LegacyMigrationGraph
- (Migration.classifyMigrationGraph
- selection unselectedImporter)
- checkRoot "set/bipartition.tex"
- \moduleAt -> do
- (_setParsed, setModule) <- moduleAt "set.tex"
- (_consParsed, consModule) <-
- moduleAt "set/cons.tex"
- (_powersetParsed, powersetModule) <-
- moduleAt "set/powerset.tex"
- (_bipartitionParsed, bipartitionModule) <-
- moduleAt "set/bipartition.tex"
- assertLocalAliasesAbsent powersetModule ["pow_iff"]
- assertEqual "bipartition semantic imports"
- [ preludeSemanticId
- , semanticId setModule
- , semanticId consModule
- , semanticId powersetModule
- ]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic
- bipartitionModule))
- assertFactAliasEscapeKind
- bipartitionModule
- "bipartition_elim"
- Authority.SourceAxiom
- checkRoot "set/product.tex"
- \moduleAt -> do
- (_setParsed, setModule) <- moduleAt "set.tex"
- (_productParsed, productModule) <-
- moduleAt "set/product.tex"
- assertEqual "product semantic imports"
- [preludeSemanticId, semanticId setModule]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic
- productModule))
- assertFactAliasEscapeKind
- productModule
- "inter_times_intro"
- Authority.SourceAxiom
- checkRoot "set/filter.tex"
- \moduleAt -> do
- (_setParsed, setModule) <- moduleAt "set.tex"
- (_powersetParsed, powersetModule) <-
- moduleAt "set/powerset.tex"
- (_filterParsed, filterModule) <-
- moduleAt "set/filter.tex"
- assertEqual "filter semantic imports"
- [ preludeSemanticId
- , semanticId setModule
- , semanticId powersetModule
- ]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic filterModule))
- assertAllLocalFactsClean filterModule
- checkRoot "relation.tex"
- \moduleAt -> do
- (_setParsed, setModule) <- moduleAt "set.tex"
- (_powersetParsed, powersetModule) <-
- moduleAt "set/powerset.tex"
- (_productParsed, productModule) <-
- moduleAt "set/product.tex"
- (_relationParsed, relationModule) <-
- moduleAt "relation.tex"
- assertEqual "relation semantic imports"
- [ preludeSemanticId
- , semanticId setModule
- , semanticId powersetModule
- , semanticId productModule
- ]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic
- relationModule))
- assertCleanFactAlias
- relationModule
- "union_relations_is_relation"
- assertFactAliasEscapeKind
- relationModule
- "id_iff"
- Authority.SourceAxiom
- assertNoLocalFactEscapeKind
- relationModule
- Authority.Omitted
- checkRoot "relation/properties.tex"
- \moduleAt -> do
- (_setParsed, setModule) <- moduleAt "set.tex"
- (_relationParsed, relationModule) <-
- moduleAt "relation.tex"
- (_propertiesParsed, propertiesModule) <-
- moduleAt "relation/properties.tex"
- assertEqual "relation properties semantic imports"
- [ preludeSemanticId
- , semanticId setModule
- , semanticId relationModule
- ]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic
- propertiesModule))
- assertCleanFactAlias
- propertiesModule
- "asymmetric_implies_irreflexive"
- assertNoLocalFactEscapeKind
- propertiesModule
- Authority.Omitted
- assertNoLocalSourceAxiom propertiesModule
- checkRoot "relation/uniqueness.tex"
- \moduleAt -> do
- (_setParsed, setModule) <- moduleAt "set.tex"
- (_relationParsed, relationModule) <-
- moduleAt "relation.tex"
- (_uniquenessParsed, uniquenessModule) <-
- moduleAt "relation/uniqueness.tex"
- assertEqual "relation uniqueness semantic imports"
- [ preludeSemanticId
- , semanticId setModule
- , semanticId relationModule
- ]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic
- uniquenessModule))
- assertCleanFactAlias
- uniquenessModule
- "subseteq_of_injective_is_injective"
- assertFactAliasEscapeKind
- uniquenessModule
- "identity_injective"
- Authority.SourceAxiom
- assertNoLocalFactEscapeKind
- uniquenessModule
- Authority.Omitted
- assertNoLocalSourceAxiom uniquenessModule
- checkRoot "function.tex"
- \moduleAt -> do
- (_setParsed, setModule) <- moduleAt "set.tex"
- (_relationParsed, relationModule) <-
- moduleAt "relation.tex"
- (_uniquenessParsed, uniquenessModule) <-
- moduleAt "relation/uniqueness.tex"
- (_functionParsed, functionModule) <-
- moduleAt "function.tex"
- assertEqual "function semantic imports"
- [ preludeSemanticId
- , semanticId setModule
- , semanticId relationModule
- , semanticId uniquenessModule
- ]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic
- functionModule))
- assertCleanFactAlias
- functionModule
- "function_on_weaken_codom"
- assertFactAliasEscapeKind
- functionModule
- "function_apply_intro"
- Authority.SourceAxiom
- assertFactAliasEscapeKind
- functionModule
- "funs_circ"
- Authority.Omitted
- assertLocalDirectAuthorizationCount
- functionModule
- Authority.OmittedAuthorization
- 6
- assertNoLocalSourceAxiom functionModule
- checkRoot "set/cantor.tex"
- \moduleAt -> do
- (_powersetParsed, powersetModule) <-
- moduleAt "set/powerset.tex"
- (_functionParsed, functionModule) <-
- moduleAt "function.tex"
- (_cantorParsed, cantorModule) <-
- moduleAt "set/cantor.tex"
- assertEqual "Cantor semantic imports"
- [ preludeSemanticId
- , semanticId powersetModule
- , semanticId functionModule
- ]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic
- cantorModule))
- assertCleanFactAlias cantorModule "cantor"
- assertNoLocalFactEscapeKind
- cantorModule Authority.Omitted
- assertNoLocalSourceAxiom cantorModule
- checkRoot "set/fixpoint.tex"
- \moduleAt -> do
- (_powersetParsed, powersetModule) <-
- moduleAt "set/powerset.tex"
- (_functionParsed, functionModule) <-
- moduleAt "function.tex"
- (_fixpointParsed, fixpointModule) <-
- moduleAt "set/fixpoint.tex"
- assertEqual "fixpoint semantic imports"
- [ preludeSemanticId
- , semanticId powersetModule
- , semanticId functionModule
- ]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic
- fixpointModule))
- assertCleanFactAlias fixpointModule "fixpoint"
- assertCleanFactAlias
- fixpointModule "subseteqpreserving"
- assertFactAliasEscapeKind
- fixpointModule
- "knastertarski"
- Authority.SourceAxiom
- assertNoLocalFactEscapeKind
- fixpointModule Authority.Omitted
- assertNoLocalSourceAxiom fixpointModule
- where
- semanticId =
- Semantic.semanticInterfaceAssertedId
- . Module.sealedTypedModuleSemantic
-
-assertLocalAliasesAbsent
- :: Module.SealedTypedModule
- -> [Text]
- -> Assertion
-assertLocalAliasesAbsent sealed names =
- forM_ names \name ->
- assertBool
- ("protected module still publishes " <> show name)
- (Semantic.semanticName name `notElem` aliases)
- where
- aliases =
- [ Semantic.semanticAliasName alias
- | delta <- localSemanticDeltas sealed
- , alias <- Semantic.declarationDeltaAliases delta
- ]
+ visits <- Store.storeMemoVisits warmMemo
+ assertEqual "cached prelude validates one artifact root"
+ 1
+ (Store.storeArtifactsValidated visits)
+
+semanticStructureDescriptors
+ :: Semantic.SemanticInterface
+ -> [Semantic.SemanticStructureDescriptor]
+semanticStructureDescriptors semantic =
+ [ descriptor
+ | delta <- Semantic.semanticInterfaceDeclarations semantic
+ , descriptor <- Semantic.semanticEnvironmentStructures
+ (Semantic.declarationDeltaEnvironment delta)
+ ]
assertTransparentObjectAlias
:: Module.SealedTypedModule
@@ -983,18 +639,6 @@ assertTransparentObjectAlias sealed name = do
Identity.TransparentObject
(Identity.objectIdFamily target)
-assertOpaqueObjectKey
- :: Module.SealedTypedModule
- -> Text
- -> Semantic.SemanticGlobalKey
- -> Assertion
-assertOpaqueObjectKey sealed name key = do
- target <- localObjectKeyTarget sealed key
- assertEqual
- ("opaque object for " <> StrictText.unpack name)
- Identity.OpaqueObject
- (Identity.objectIdFamily target)
-
localObjectKeyTarget
:: Module.SealedTypedModule
-> Semantic.SemanticGlobalKey
@@ -1026,29 +670,6 @@ localObjectAliasTarget sealed name = do
(Semantic.semanticGlobalTargetObject
(Semantic.semanticGlobalBindingTarget binding))
-localTransparentObjectBody
- :: Module.SealedTypedModule
- -> Text
- -> IO (Core.CanonicalTerm Identity.ObjectId)
-localTransparentObjectBody sealed name = do
- identity <- localObjectAliasTarget sealed name
- object <- sole
- ("asserted object for " <> StrictText.unpack name)
- [ candidate
- | batch <- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed)
- , candidate <- Declaration.committedBatchObjects batch
- , Identity.assertedObjectId candidate == identity
- ]
- case Identity.assertedObjectContent object of
- Identity.TransparentObjectContent _theory _coreType body ->
- pure body
- content ->
- assertFailure
- ("object for " <> StrictText.unpack name
- <> " is not transparent: " <> show content)
- >> fail "unreachable"
-
checkedPropositionTermByAlias
:: Module.SealedTypedModule
-> Text
@@ -1057,30 +678,31 @@ checkedPropositionTermByAlias sealed name = do
batch <- batchByAlias
(Module.sealedTypedModulePrefix sealed)
name
+ alias <- sole
+ ("semantic alias for " <> StrictText.unpack name)
+ [ candidate
+ | candidate <- Semantic.declarationDeltaAliases
+ (Declaration.committedBatchDelta batch)
+ , Semantic.semanticAliasName candidate
+ == Semantic.semanticName name
+ ]
+ occurrence <- sole
+ ("semantic fact for " <> StrictText.unpack name)
+ [ candidate
+ | candidate <- Semantic.declarationDeltaFacts
+ (Declaration.committedBatchDelta batch)
+ , Semantic.semanticFactFingerprint candidate
+ == Semantic.semanticAliasTarget alias
+ ]
proposition <- sole
("checked proposition for " <> StrictText.unpack name)
- (Declaration.committedBatchPropositions batch)
+ [ candidate
+ | candidate <- Declaration.committedBatchPropositions batch
+ , Identity.checkedPropositionId candidate
+ == Semantic.semanticFactProposition occurrence
+ ]
pure (Identity.checkedPropositionTerm proposition)
-assertFactAliasEscapeKind
- :: Module.SealedTypedModule
- -> Text
- -> Authority.EscapeKind
- -> Assertion
-assertFactAliasEscapeKind sealed name expected = do
- delta <- localDeltaByAlias sealed name
- fact <- sole
- ("semantic fact for " <> StrictText.unpack name)
- (Semantic.declarationDeltaFacts delta)
- assertBool
- ("escape authority for " <> StrictText.unpack name)
- ( expected
- `elem` Authority.escapeKindsToList
- (Authority.authoritySafetyEscapeKinds
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority fact)))
- )
-
assertCleanFactAlias
:: Module.SealedTypedModule
-> Text
@@ -1107,114 +729,6 @@ assertCleanFactAlias sealed name = do
(Authority.factAuthoritySafety
(Semantic.semanticFactAuthority fact))
-assertAllLocalFactsClean
- :: Module.SealedTypedModule
- -> Assertion
-assertAllLocalFactsClean sealed =
- assertBool
- "all locally published facts have clean authority"
- (all hasCleanAuthority localFacts)
- where
- localFacts =
- [ fact
- | delta <- localSemanticDeltas sealed
- , fact <- Semantic.declarationDeltaFacts delta
- ]
- hasCleanAuthority fact =
- Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority fact)
- == Authority.cleanAuthoritySafety
-
-assertNoLocalFactEscapeKind
- :: Module.SealedTypedModule
- -> Authority.EscapeKind
- -> Assertion
-assertNoLocalFactEscapeKind sealed unexpected =
- assertBool
- ("no local fact has " <> show unexpected <> " authority")
- (all lacksEscapeKind localFacts)
- where
- localFacts =
- [ fact
- | delta <- localSemanticDeltas sealed
- , fact <- Semantic.declarationDeltaFacts delta
- ]
- lacksEscapeKind fact =
- unexpected
- `notElem` Authority.escapeKindsToList
- (Authority.authoritySafetyEscapeKinds
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority fact)))
-
-assertNoLocalSourceAxiom
- :: Module.SealedTypedModule
- -> Assertion
-assertNoLocalSourceAxiom sealed =
- assertBool
- "module introduces no source axiom"
- (all (/= Authority.SourceAxiomAuthorization) directAuthorizations)
- where
- directAuthorizations =
- [ Authority.validationDirectAuthorization certificate
- | batch <- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed)
- , validation <- maybeToList
- (Declaration.committedBatchDeclarationValidation batch)
- , certificate <-
- Semantic.declarationValidationRecordCertificates validation
- ]
-
-assertLocalDirectAuthorizationCount
- :: Module.SealedTypedModule
- -> Authority.DirectAuthorization
- -> Int
- -> Assertion
-assertLocalDirectAuthorizationCount sealed expected expectedCount =
- assertEqual
- ("local " <> show expected <> " authorization count")
- expectedCount
- (length
- [ ()
- | batch <- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed)
- , validation <- Declaration.committedBatchProofValidations batch
- , Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate validation)
- == expected
- ])
-
-assertSourceAxiomAlias
- :: Module.SealedTypedModule
- -> Text
- -> Assertion
-assertSourceAxiomAlias sealed name = do
- batch <- batchByAlias
- (Module.sealedTypedModulePrefix sealed)
- name
- fact <- sole
- ("source axiom fact " <> StrictText.unpack name)
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch))
- assertEqual
- ("source axiom safety for " <> StrictText.unpack name)
- (Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.SourceAxiom))
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority fact))
- validation <- maybe
- (assertFailure
- ("source axiom validation for " <> StrictText.unpack name)
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation batch)
- certificate <- sole
- ("source axiom certificate for " <> StrictText.unpack name)
- (Semantic.declarationValidationRecordCertificates validation)
- assertEqual
- ("source axiom authority for " <> StrictText.unpack name)
- Authority.SourceAxiomAuthorization
- (Authority.validationDirectAuthorization certificate)
-
batchByAlias
:: Declaration.PendingModulePrefix
-> Text
@@ -1350,18 +864,10 @@ coalescesSharedDirectSyntax = do
, (sourceMountId "library", root Posix.</> "library")
, (sourceMountId "debug", root Posix.</> "debug")
]
- selection <-
- expectRight
- (Migration.resolveMigrationSelection
- mounts
- Migration.typedMigrationModules)
let bootstrapSyntax =
Module.sealedTypedModuleSyntax
(Module.bootstrapPreludeModule session)
- syntaxInputs source
- | Migration.migrationSelectionContains selection source =
- [bootstrapSyntax]
- | otherwise = []
+ syntaxInputs _source = [bootstrapSyntax]
request <-
expectRight
(searchedRoot "test/phase3/typed-shared-root.tex")
@@ -1371,9 +877,6 @@ coalescesSharedDirectSyntax = do
mounts
request
syntaxInputs
- assertEqual "selected shared-syntax graph"
- Migration.TypedMigrationGraph
- (Migration.classifyMigrationGraph selection workspace)
case Parse.parsedWorkspaceModules workspace of
[firstParsed, secondParsed, rootParsed] -> do
first <- seal foundation session firstParsed []
@@ -1436,31 +939,6 @@ coalescesSharedDirectSyntax = do
assertFailure "empty typed module did not seal"
>> fail "unreachable"
-resetsGlossStatePerModule :: Assertion
-resetsGlossStatePerModule = do
- blocks <- Api.gloss "test/phase3/gloss-root.tex"
- binders <- traverse signatureBinder blocks
- assertEqual "fresh variables restart at each module boundary"
- [Internal.FreshVar 0, Internal.FreshVar 0, Internal.FreshVar 1]
- binders
- where
- signatureBinder = \case
- Internal.BlockSig
- _location
- _marker
- _assumptions
- (Internal.SignatureFormula
- (Internal.Quantified Internal.Universally scope)) ->
- case nubOrd [binder | B binder <- toList (fromScope scope)] of
- [binder] -> pure binder
- binders ->
- assertFailure
- ("unexpected signature binders: " <> show binders)
- >> fail "unreachable"
- block ->
- assertFailure ("unexpected glossed block: " <> show block)
- >> fail "unreachable"
-
rejectsUnsupportedTypedSource :: Assertion
rejectsUnsupportedTypedSource = do
result <-
@@ -1472,13 +950,16 @@ rejectsUnsupportedTypedSource = do
Provers.defaultMemoryLimit)
"test/phase3/typed-unsupported.tex")
case result of
- Left
- (failure@(Api.VerificationTypedModuleError
+ Right
+ ( Api.VerificationCheckingFailure _report
+ (failure@(Api.VerificationTypedModuleError
source
(Module.TypedActionFailed
(Module.TypedExactCompileFailed
(Exact.ExactUnsupportedDeclarationBody location)))
- prefix)) -> do
+ prefix))
+ , _measurements
+ ) -> do
assertEqual "failed source"
"test/phase3/typed-unsupported.tex"
(safeRelativePathFilePath
@@ -1670,6 +1151,566 @@ compilesExactDeclarationGraph = do
Identity.TransparentObjectContent{} -> "transparent"
Identity.IntrinsicObjectContent{} -> "intrinsic"
+compilesExactStructures :: Assertion
+compilesExactStructures = do
+ foundation <- expectRight Foundation.checkedFoundation
+ repository <- getCurrentDirectory
+ Temp.withSystemTempDirectory "felix-exact-structures" \directory -> do
+ let path = directory Posix.</> "store.sqlite"
+ executable = directory Posix.</> "vampire"
+ writeAcceptedFixtureVampire executable
+ runs <- newIORef (0 :: Int)
+ let resolver = countingAcceptedResolver executable runs
+ (_startup, store) <-
+ Store.openStore path (Identity.theoryId foundation)
+ >>= expectRight
+ bracket (pure store) Store.closeStore \opened -> do
+ prelude <-
+ expectRight
+ =<< acquireFinalPreludeSession
+ opened foundation resolver
+ carrierOperation <- sole "base carrier operation"
+ [ operation
+ | descriptor <- semanticStructureDescriptors
+ (Module.sealedTypedModuleSemantic
+ (Module.finalPreludeModule prelude))
+ , operation <-
+ Semantic.semanticStructureDescriptorOperations descriptor
+ ]
+ mounts <- exactFixtureMounts repository
+ workspace <- parseFinalExactWorkspace
+ prelude mounts "test/phase5/exact-structure-child.tex"
+ sealed <- compileFinalParsedWorkspaceWithResolver
+ foundation prelude resolver workspace
+ freshRuns <- readIORef runs
+ warm <- installAndLoadStructures
+ opened foundation prelude workspace sealed
+ warmRuns <- readIORef runs
+ assertEqual "warm structures preserve descriptors"
+ (structureDescriptors <$> sealed)
+ (structureDescriptors <$> warm)
+ assertEqual "warm structures make no prover calls"
+ freshRuns warmRuns
+ case sealed of
+ [parent, child] -> do
+ let parentBatches =
+ Declaration.pendingModulePrefixBatches
+ (Module.sealedTypedModulePrefix parent)
+ parentDeltas =
+ Semantic.semanticInterfaceDeclarations
+ (Module.sealedTypedModuleSemantic parent)
+ childBatches =
+ Declaration.pendingModulePrefixBatches
+ (Module.sealedTypedModulePrefix child)
+ childDeltas =
+ Semantic.semanticInterfaceDeclarations
+ (Module.sealedTypedModuleSemantic child)
+ parentBatch <- sole "parent structure batch"
+ (take 1 parentBatches)
+ parentDelta <- sole "parent structure delta"
+ (take 1 parentDeltas)
+ parentDescriptor <- sole "parent structure descriptor"
+ (Semantic.semanticEnvironmentStructures
+ (Semantic.declarationDeltaEnvironment parentDelta))
+ parentOperation <- sole "parent structure operation"
+ (Semantic.semanticStructureDescriptorOperations
+ parentDescriptor)
+ parentPredicate <-
+ maybe
+ (assertFailure "parent structure has no predicate"
+ >> fail "unreachable")
+ pure
+ (Semantic.semanticStructureDescriptorPredicate
+ parentDescriptor)
+ assertEqual "structure object family order"
+ ["opaque", "transparent"]
+ [ objectFamilyName
+ (Identity.assertedObjectContent object)
+ | object <- Declaration.committedBatchObjects parentBatch
+ ]
+ assertEqual "structure fact aliases"
+ [ Semantic.semanticName "pointed_set"
+ , Semantic.semanticName "pointed_refl"
+ ]
+ (Semantic.semanticAliasName
+ <$> Semantic.declarationDeltaAliases parentDelta)
+ definitionFact <- sole "structure definition fact"
+ (take 1 (Semantic.declarationDeltaFacts parentDelta))
+ definitionTarget <-
+ targetForOccurrence parentBatch definitionFact
+ assertEqual "pointwise structure definition"
+ (Core.CForall Core.TySet
+ (Core.CEq Core.TyProp
+ (Core.CApp
+ (Core.CGlobal parentPredicate)
+ (Core.CBound 0))
+ (Core.CEq Core.TySet
+ (Core.CBound 0)
+ (Core.CBound 0))))
+ definitionTarget
+ validations <-
+ maybe
+ (assertFailure "structure validation is absent"
+ >> fail "unreachable")
+ (pure
+ . Semantic.declarationValidationRecordCertificates)
+ (Declaration.committedBatchDeclarationValidation
+ parentBatch)
+ case validations of
+ definitionValidation : projectionValidation : [] -> do
+ assertEqual "structure definition authority"
+ (Authority.CheckedKernelConstruction
+ (Authority.CheckedDefinitionEquation
+ parentPredicate))
+ (Authority.validationDirectAuthorization
+ definitionValidation)
+ projectionFact <- sole
+ "structure projection fact"
+ (drop 1
+ (Semantic.declarationDeltaFacts
+ parentDelta))
+ assertEqual
+ "projection has independent authority"
+ (Semantic.semanticFactAuthority projectionFact)
+ (Authority.validationTarget
+ projectionValidation)
+ assertEqual "projection authority is clean"
+ Authority.cleanAuthoritySafety
+ (Authority.factAuthoritySafety
+ (Authority.validationTarget
+ projectionValidation))
+ records ->
+ assertFailure
+ ("expected two structure validations, got "
+ <> show records)
+ assertBool "all parent structure facts are clean"
+ (all
+ ((== Authority.cleanAuthoritySafety)
+ . Authority.factAuthoritySafety
+ . Semantic.semanticFactAuthority)
+ (Semantic.declarationDeltaFacts parentDelta))
+
+ let claimGlobals marker = do
+ batch <- batchWithAlias marker parentBatches
+ occurrence <- sole (marker <> " occurrence")
+ (Semantic.declarationDeltaFacts
+ (Declaration.committedBatchDelta batch))
+ Core.canonicalTermGlobals
+ <$> targetForOccurrence batch occurrence
+ carrierGlobals <- claimGlobals "pointed_carrier"
+ operationGlobals <- claimGlobals "pointed_operation"
+ assertBool "membership uses inherited carrier"
+ (Semantic.semanticStructureOperationObject carrierOperation
+ `Set.member` carrierGlobals)
+ assertBool "implicit and explicit operation share one object"
+ (Semantic.semanticStructureOperationObject parentOperation
+ `Set.member` operationGlobals)
+
+ childBatch <- sole "child structure batch" childBatches
+ childDelta <- sole "child structure delta" childDeltas
+ childDescriptor <- sole "child structure descriptor"
+ (Semantic.semanticEnvironmentStructures
+ (Semantic.declarationDeltaEnvironment childDelta))
+ assertEqual "child allocates no replacement operation"
+ []
+ (Semantic.semanticStructureDescriptorOperations
+ childDescriptor)
+ assertEqual "child owns only its transparent predicate"
+ ["transparent"]
+ [ objectFamilyName
+ (Identity.assertedObjectContent object)
+ | object <- Declaration.committedBatchObjects childBatch
+ ]
+ modules ->
+ assertFailure
+ ("expected parent and child structures, got "
+ <> show (length modules))
+ where
+ installAndLoadStructures store foundation prelude workspace sealed = do
+ memo <- Store.newStoreMemo store
+ case
+ ( toList
+ (Parse.parsedWorkspaceImportedBeforeImporter workspace)
+ , sealed
+ ) of
+ ([parentParsed, childParsed], [parent, child]) -> do
+ cachedParent <- persistAndLoad memo [] parentParsed parent
+ cachedChild <- persistAndLoad
+ memo [cachedParent] childParsed child
+ pure [cachedParent, cachedChild]
+ (parsed, modules) ->
+ assertFailure
+ ("expected two structure installations, got "
+ <> show (length parsed)
+ <> " parsed and "
+ <> show (length modules)
+ <> " checked modules")
+ >> fail "unreachable"
+ where
+ preludeModule = Module.finalPreludeModule prelude
+
+ persistAndLoad memo parents parsed sealedModule = do
+ let input = Module.identifiedPhysicalModule parsed
+ syntax = Module.sealedTypedModuleSyntax sealedModule
+ semantic = Module.sealedTypedModuleSemantic sealedModule
+ key <- expectRight
+ (Semantic.moduleArtifactKey
+ (Module.identifiedModuleOwner input)
+ (Parse.identifiedParsedModuleId
+ (Module.identifiedModuleParsed input))
+ (Semantic.semanticInterfaceDirectInputs semantic)
+ (Identity.theoryId foundation))
+ let artifact = Semantic.moduleArtifactResult
+ key
+ (Syntax.moduleSyntaxAssertedId syntax)
+ (Semantic.semanticInterfaceAssertedId semantic)
+ acknowledged <- expectRight
+ =<< Store.writeSealedModule
+ store
+ (Module.sealedTypedModulePrefix sealedModule)
+ [syntax]
+ [semantic]
+ artifact
+ assertEqual "cached structure artifact acknowledgement"
+ artifact acknowledged
+ loaded <- expectRight
+ =<< Store.loadCachedModuleInstallation
+ memo
+ store
+ key
+ (Syntax.moduleSyntaxAssertedId
+ (Parse.parsedModuleSyntaxInterface parsed))
+ installation <- maybe
+ (assertFailure "cached structure installation is absent"
+ >> fail "unreachable")
+ pure
+ loaded
+ expectRight
+ (Module.cachedSealedTypedModule
+ foundation
+ (preludeModule : parents)
+ installation)
+
+ structureDescriptors =
+ semanticStructureDescriptors
+ . Module.sealedTypedModuleSemantic
+
+ objectFamilyName :: Identity.ObjectContent -> String
+ objectFamilyName = \case
+ Identity.OpaqueObjectContent{} -> "opaque"
+ Identity.TransparentObjectContent{} -> "transparent"
+ Identity.IntrinsicObjectContent{} -> "intrinsic"
+
+ targetForOccurrence batch occurrence =
+ maybe
+ (assertFailure "structure proposition is absent"
+ >> fail "unreachable")
+ (pure . Core.frozenCoreTerm . Identity.checkedPropositionTerm)
+ (find
+ ((== Semantic.semanticFactProposition occurrence)
+ . Identity.checkedPropositionId)
+ (Declaration.committedBatchPropositions batch))
+
+ batchWithAlias marker batches =
+ maybe
+ (assertFailure ("missing batch alias " <> marker)
+ >> fail "unreachable")
+ pure
+ (find
+ (elem (Semantic.semanticName (StrictText.pack marker))
+ . fmap Semantic.semanticAliasName
+ . Semantic.declarationDeltaAliases
+ . Declaration.committedBatchDelta)
+ batches)
+
+compilesContextualAbbreviations :: Assertion
+compilesContextualAbbreviations = do
+ foundation <- expectRight Foundation.checkedFoundation
+ repository <- getCurrentDirectory
+ Temp.withSystemTempDirectory "felix-contextual-abbreviation" \directory -> do
+ let storePath = directory Posix.</> "store.sqlite"
+ executable = directory Posix.</> "vampire"
+ relative = "test/phase5/exact-contextual-abbreviation.tex"
+ writeAcceptedFixtureVampire executable
+ runs <- newIORef (0 :: Int)
+ let resolver = countingAcceptedResolver executable runs
+ (_startup, store) <-
+ Store.openStore storePath (Identity.theoryId foundation)
+ >>= expectRight
+ bracket (pure store) Store.closeStore \opened -> do
+ prelude <-
+ expectRight
+ =<< acquireFinalPreludeSession
+ opened foundation resolver
+ mounts <- exactFixtureMounts repository
+ workspace <- parseFinalExactWorkspace prelude mounts relative
+ sealed <- sole "contextual abbreviation module"
+ =<< compileFinalParsedWorkspaceWithResolver
+ foundation prelude resolver workspace
+ let deltas =
+ Semantic.semanticInterfaceDeclarations
+ (Module.sealedTypedModuleSemantic sealed)
+ contextualTargets =
+ [ (identity, requirements)
+ | delta <- deltas
+ , binding <- Semantic.semanticEnvironmentBindings
+ (Semantic.declarationDeltaEnvironment delta)
+ , Semantic.ContextualTransparentExpansion
+ identity requirements <-
+ [Semantic.semanticGlobalBindingTarget binding]
+ ]
+ assertEqual "contextual target count" 2
+ (length contextualTargets)
+ requirements <-
+ sole "canonical contextual requirement set"
+ (nubOrd (snd <$> contextualTargets))
+ assertEqual "one structure operation requirement" 1
+ (Map.size requirements)
+ let batches =
+ Declaration.pendingModulePrefixBatches
+ (Module.sealedTypedModulePrefix sealed)
+ traverse_
+ (assertReflexiveFact batches)
+ [ "phase5_context_dot_explicit"
+ , "phase5_context_inherited"
+ , "phase5_context_nested"
+ , "phase5_context_explicit_unique"
+ ]
+
+ parsed <- pure (Parse.parsedWorkspaceRootModule workspace)
+ let syntax = Module.sealedTypedModuleSyntax sealed
+ semantic = Module.sealedTypedModuleSemantic sealed
+ key <- expectRight
+ (Semantic.moduleArtifactKey
+ (moduleName (Parse.parsedModuleAddress parsed))
+ (Parse.parsedModuleId parsed)
+ (Semantic.semanticInterfaceDirectInputs semantic)
+ (Identity.theoryId foundation))
+ let artifact =
+ Semantic.moduleArtifactResult
+ key
+ (Syntax.moduleSyntaxAssertedId syntax)
+ (Semantic.semanticInterfaceAssertedId semantic)
+ void
+ (expectRight
+ =<< Store.writeSealedModule
+ opened
+ (Module.sealedTypedModulePrefix sealed)
+ [syntax]
+ [semantic]
+ artifact)
+ memo <- Store.newStoreMemo opened
+ loaded <- expectRight
+ =<< Store.loadCachedModuleInstallation
+ memo opened key
+ (Syntax.moduleSyntaxAssertedId
+ (Parse.parsedModuleSyntaxInterface parsed))
+ installation <- maybe
+ (assertFailure "contextual cached installation is absent"
+ >> fail "unreachable")
+ pure
+ loaded
+ cached <- expectRight
+ (Module.cachedSealedTypedModule
+ foundation
+ [Module.finalPreludeModule prelude]
+ installation)
+ assertEqual "cached contextual semantic target"
+ semantic
+ (Module.sealedTypedModuleSemantic cached)
+
+ runsBeforeConsumer <- readIORef runs
+ consumerWorkspace <-
+ parseFinalExactWorkspace prelude mounts
+ "test/phase5/exact-contextual-abbreviation-consumer.tex"
+ let consumerParsed =
+ Parse.parsedWorkspaceRootModule consumerWorkspace
+ consumerInput <- expectRight
+ (Module.typedModuleInput
+ foundation
+ (Module.finalPreludeReadiness prelude)
+ resolver
+ Declaration.FreshValidation
+ consumerParsed
+ [cached])
+ consumer <- Module.runTypedModule consumerInput >>= \case
+ Module.TypedModuleSucceeded sealedConsumer ->
+ pure sealedConsumer
+ Module.TypedModuleOpenFailed failure ->
+ assertFailure
+ ("contextual consumer did not open: " <> show failure)
+ >> fail "unreachable"
+ Module.TypedModuleFailed failure _prefix ->
+ assertFailure
+ ("contextual consumer did not seal: " <> show failure)
+ >> fail "unreachable"
+ let consumerTargets =
+ [ Semantic.semanticGlobalTargetObject
+ (Semantic.semanticGlobalBindingTarget binding)
+ | delta <- localSemanticDeltas consumer
+ , binding <- Semantic.semanticEnvironmentBindings
+ (Semantic.declarationDeltaEnvironment delta)
+ ]
+ assertEqual "two contextual consumer declarations" 2
+ (length consumerTargets)
+ void
+ (sole
+ "quantified contextual binder matches its explicit parameter"
+ (nubOrd consumerTargets))
+ runsAfterConsumer <- readIORef runs
+ assertEqual "contextual abbreviations require no prover call"
+ runsBeforeConsumer runsAfterConsumer
+
+ verifyFailure foundation resolver prelude mounts sealed
+ "test/phase5/exact-contextual-abbreviation-missing.tex"
+ (\case
+ Exact.ExactContextualExpansionNotAvailable location _key ->
+ assertEqual "missing context line" 5 (locLine location)
+ failure ->
+ assertFailure
+ ("unexpected missing-context failure: "
+ <> show failure))
+ verifyFailure foundation resolver prelude mounts sealed
+ "test/phase5/exact-contextual-abbreviation-ambiguous.tex"
+ (\case
+ Exact.ExactStructureOperationAmbiguous
+ location _symbol objects -> do
+ assertEqual "ambiguous operation line" 16
+ (locLine location)
+ assertEqual "two distinct operation objects" 2
+ (length objects)
+ failure ->
+ assertFailure
+ ("unexpected operation ambiguity failure: "
+ <> show failure))
+ where
+ assertReflexiveFact batches marker = do
+ batch <- maybe
+ (assertFailure ("missing contextual fact " <> marker)
+ >> fail "unreachable")
+ pure
+ (find
+ (elem (Semantic.semanticName (StrictText.pack marker))
+ . fmap Semantic.semanticAliasName
+ . Semantic.declarationDeltaAliases
+ . Declaration.committedBatchDelta)
+ batches)
+ proposition <- sole (marker <> " proposition")
+ (Declaration.committedBatchPropositions batch)
+ let body = stripClaimEnvelope
+ (Core.frozenCoreTerm
+ (Identity.checkedPropositionTerm proposition))
+ case body of
+ Core.CEq _ left right ->
+ assertEqual (marker <> " canonical sides") left right
+ _ ->
+ assertFailure
+ (marker <> " did not elaborate to reflexive equality: "
+ <> show body)
+
+ stripClaimEnvelope = \case
+ Core.CForall _ body -> stripClaimEnvelope body
+ Core.CImp _ body -> stripClaimEnvelope body
+ term -> term
+
+ verifyFailure foundation resolver prelude mounts imported relative checkFailure = do
+ workspace <- parseFinalExactWorkspace prelude mounts relative
+ let parsed = Parse.parsedWorkspaceRootModule workspace
+ input <- expectRight
+ (Module.typedModuleInput
+ foundation
+ (Module.finalPreludeReadiness prelude)
+ resolver
+ Declaration.FreshValidation
+ parsed
+ [imported])
+ Module.runTypedModule input >>= \case
+ Module.TypedModuleFailed
+ (Module.TypedActionFailed
+ (Module.TypedExactCompileFailed failure))
+ _prefix ->
+ checkFailure failure
+ Module.TypedModuleFailed
+ (Module.TypedActionFailed
+ (Module.TypedExactProofFailed
+ (ExactProof.ExactProofElaborationFailed failure)))
+ _prefix ->
+ checkFailure failure
+ Module.TypedModuleSucceeded{} ->
+ assertFailure (relative <> " was unexpectedly accepted")
+ Module.TypedModuleOpenFailed failure ->
+ assertFailure
+ (relative <> " did not open: " <> show failure)
+ Module.TypedModuleFailed failure _prefix ->
+ assertFailure
+ (relative <> " failed unexpectedly: " <> show failure)
+
+rejectsUnknownExactStructureParent :: Assertion
+rejectsUnknownExactStructureParent =
+ Temp.withSystemTempDirectory "felix-exact-structure-parent" \root -> do
+ let relative = "entry.tex"
+ path = root Posix.</> relative
+ source =
+ "\\begin{struct}\\label{known_structure}\n"
+ <> " A known structure $X$ is a onesorted structure.\n"
+ <> "\\end{struct}\n\n"
+ <> "\\begin{struct}\\label{invalid_structure}\n"
+ <> " An invalid structure $X$ is a future structure.\n"
+ <> "\\end{struct}\n\n"
+ <> "\\begin{struct}\\label{future_structure}\n"
+ <> " A future structure $X$ is a onesorted structure.\n"
+ <> "\\end{struct}\n"
+ ByteString.writeFile path
+ (Text.encodeUtf8 (StrictText.pack source))
+ foundation <- expectRight Foundation.checkedFoundation
+ Temp.withSystemTempDirectory "felix-exact-structure-store" \directory -> do
+ let storePath = directory Posix.</> "store.sqlite"
+ executable = directory Posix.</> "vampire"
+ writeAcceptedFixtureVampire executable
+ runs <- newIORef (0 :: Int)
+ let resolver = countingAcceptedResolver executable runs
+ (_startup, store) <-
+ Store.openStore storePath (Identity.theoryId foundation)
+ >>= expectRight
+ bracket (pure store) Store.closeStore \opened -> do
+ prelude <-
+ expectRight
+ =<< acquireFinalPreludeSession
+ opened foundation resolver
+ mounts <- exactFixtureMounts root
+ workspace <- parseFinalExactWorkspace prelude mounts relative
+ let parsed = Parse.parsedWorkspaceRootModule workspace
+ input <- expectRight
+ (Module.typedModuleInput
+ foundation
+ (Module.finalPreludeReadiness prelude)
+ resolver
+ Declaration.FreshValidation
+ parsed
+ [])
+ Module.runTypedModule input >>= \case
+ Module.TypedModuleFailed
+ (Module.TypedActionFailed
+ (Module.TypedExactCompileFailed
+ (Exact.ExactStructureNotVisible
+ location _phrase)))
+ prefix -> do
+ assertEqual "unknown parent line" 5 (locLine location)
+ assertEqual "only the valid structure was published"
+ 1
+ (length
+ (Declaration.pendingModulePrefixBatches prefix))
+ Module.TypedModuleSucceeded{} ->
+ assertFailure "unknown structure parent was accepted"
+ Module.TypedModuleOpenFailed failure ->
+ assertFailure
+ ("invalid structure module did not open: "
+ <> show failure)
+ Module.TypedModuleFailed failure _prefix ->
+ assertFailure
+ ("unexpected invalid structure failure: "
+ <> show failure)
+
compilesExactRelationExpressions :: Assertion
compilesExactRelationExpressions = do
foundation <- expectRight Foundation.checkedFoundation
@@ -1712,14 +1753,17 @@ compilesExactRelationExpressions = do
prover
"test/phase5/exact-relation-expression-missing-pair.tex")
case missingPair of
- Left
- (Api.VerificationTypedModuleError
+ Right
+ ( Api.VerificationCheckingFailure _report
+ (Api.VerificationTypedModuleError
_source
(Module.TypedActionFailed
(Module.TypedExactProofFailed
(ExactProof.ExactProofElaborationFailed
(Exact.ExactGlobalNotVisible location key))))
- prefix) -> do
+ prefix)
+ , _measurements
+ ) -> do
assertEqual "missing ordered-pair provider line"
2
(locLine location)
@@ -1752,7 +1796,7 @@ resolvesSourceOwnedApplication = do
\store -> do
prelude <-
expectRight
- =<< Module.buildFinalPreludeSession
+ =<< acquireFinalPreludeSession
store foundation resolver
mounts <- exactFixtureMounts repository
workspace <- parseFinalExactWorkspace
@@ -1788,14 +1832,17 @@ resolvesSourceOwnedApplication = do
prover
"test/phase5/exact-application-missing.tex")
case missing of
- Left
- (Api.VerificationTypedModuleError
+ Right
+ ( Api.VerificationCheckingFailure _report
+ (Api.VerificationTypedModuleError
_source
(Module.TypedActionFailed
(Module.TypedExactProofFailed
(ExactProof.ExactProofElaborationFailed
(Exact.ExactGlobalNotVisible location key))))
- prefix) -> do
+ prefix)
+ , _measurements
+ ) -> do
assertEqual "unresolved application line" 2 (locLine location)
assertEqual "unresolved application key"
(Semantic.SemanticExpressionFunction
@@ -1826,7 +1873,7 @@ confinesExactQuantifiedTerms = do
\store -> do
prelude <-
expectRight
- =<< Module.buildFinalPreludeSession
+ =<< acquireFinalPreludeSession
store foundation resolver
mounts <- exactFixtureMounts repository
workspace <- parseFinalExactWorkspace
@@ -1856,15 +1903,18 @@ confinesExactQuantifiedTerms = do
prover
"test/phase5/exact-quantified-subject-nested.tex")
case negative of
- Left
- (Api.VerificationTypedModuleError
+ Right
+ ( Api.VerificationCheckingFailure _report
+ (Api.VerificationTypedModuleError
_source
(Module.TypedActionFailed
(Module.TypedExactProofFailed
(ExactProof.ExactProofElaborationFailed
(Exact.ExactQuantifiedTermRequiresStatementSubject
location))))
- prefix) -> do
+ prefix)
+ , _measurements
+ ) -> do
assertEqual "nested quantified term line" 8 (locLine location)
assertEqual "earlier exact definition remains committed"
1
@@ -2307,6 +2357,209 @@ compilesAndReusesProofLocalSetDefinitions =
(Core.CImp left (Core.CImp right Core.CFalsum))
Core.CFalsum
+compilesAndReusesProofLocalFunctionGraphs :: Assertion
+compilesAndReusesProofLocalFunctionGraphs =
+ Temp.withSystemTempDirectory "felix-exact-local-function" \root -> do
+ let relative = "test/phase5/exact-local-function.tex"
+ failedRelative =
+ "test/phase5/exact-local-function-failure.tex"
+ executable = root Posix.</> "vampire"
+ storePath = root Posix.</> "store.sqlite"
+ writeAcceptedFixtureVampire executable
+ foundation <- expectRight Foundation.checkedFoundation
+ bootstrap <-
+ expectRight
+ =<< Module.buildBootstrapPreludeFixture
+ foundation unusedResolver
+ mounts <- exactFixtureMounts =<< getCurrentDirectory
+ workspace <- parseExactWorkspace bootstrap mounts relative
+ observations <- newIORef []
+ let resolver = Declaration.vampireResolver \prepared -> do
+ let problem =
+ Provers.preparedTypedProverLogicalProblem prepared
+ premises =
+ [ ( Backend.typedProblemRoute problem
+ , fmap snd
+ (Vector.toList
+ (Backend.supportedPropositionSupport
+ proposition))
+ , Backend.supportedPropositionTerm proposition
+ )
+ | premise <-
+ Vector.toList
+ (Backend.typedProblemLocalPremises problem)
+ , let proposition =
+ Backend.typedLocalPremiseProposition premise
+ ]
+ modifyIORef' observations (<> premises)
+ runNoLoggingT
+ (Provers.runPreparedTypedProver
+ (Provers.vampire
+ executable
+ Provers.defaultTimeLimit
+ Provers.defaultMemoryLimit)
+ prepared)
+ freshModules <-
+ compileParsedWorkspaceWithValidation
+ foundation bootstrap resolver
+ Declaration.FreshValidation workspace
+ allObserved <- readIORef observations
+ let observed =
+ [ (route, proposition)
+ | (route, support, proposition) <- allObserved
+ , support == [Core.TySet, Core.TySet]
+ , isJust (localFunctionPair proposition)
+ ]
+ assertBool
+ ("the local graph characteristic reaches a discharge: "
+ <> show allObserved)
+ (not (null observed))
+ for_ observed \(route, proposition) -> do
+ assertEqual "local function characteristic stays on FOF"
+ Backend.RouteFof route
+ assertExactLocalFunctionCharacteristic proposition
+ freshRoot <- sole "fresh local-function root"
+ (take 1 (reverse freshModules))
+ rootBatch <- sole "local function publishes only its theorem"
+ (drop 1
+ (Declaration.pendingModulePrefixBatches
+ (Module.sealedTypedModulePrefix freshRoot)))
+ assertEqual "local function publishes no object"
+ [] (Declaration.committedBatchObjects rootBatch)
+ assertEqual "local function publishes only its theorem"
+ 1
+ (length
+ (Declaration.committedBatchPropositions rootBatch))
+ assertEqual "local function publishes no semantic binding"
+ []
+ (Semantic.semanticEnvironmentBindings
+ (Semantic.declarationDeltaEnvironment
+ (Declaration.committedBatchDelta rootBatch)))
+ rootFact <- sole "local-function theorem"
+ (Semantic.declarationDeltaFacts
+ (Declaration.committedBatchDelta rootBatch))
+ assertEqual "local-function theorem remains clean"
+ Authority.cleanAuthoritySafety
+ (Authority.factAuthoritySafety
+ (Semantic.semanticFactAuthority rootFact))
+
+ bracket
+ (snd <$> (Store.openStore storePath
+ (Identity.theoryId foundation) >>= expectRight))
+ Store.closeStore
+ \store -> do
+ traverse_
+ (expectRightIO
+ . Store.writePendingModulePrefix store
+ . Module.sealedTypedModulePrefix)
+ freshModules
+ let validation =
+ Declaration.WarmValidation
+ (Declaration.validationLookup
+ (expectRightIO
+ . Store.loadProofValidation store)
+ (expectRightIO
+ . Store.loadDeclarationValidation store))
+ warmRuns <- newIORef (0 :: Int)
+ warmModules <-
+ compileParsedWorkspaceWithValidation
+ foundation bootstrap
+ (countingAcceptedResolver executable warmRuns)
+ validation workspace
+ assertEqual "warm local-function graph skips Vampire"
+ 0 =<< readIORef warmRuns
+ warmRoot <- sole "warm local-function root"
+ (take 1 (reverse warmModules))
+ assertEqual "warm local-function semantic interface"
+ (Module.sealedTypedModuleSemantic freshRoot)
+ (Module.sealedTypedModuleSemantic warmRoot)
+ assertEqual "warm local-function prefix"
+ (Declaration.pendingModulePrefixCurrent
+ (Module.sealedTypedModulePrefix freshRoot))
+ (Declaration.pendingModulePrefixCurrent
+ (Module.sealedTypedModulePrefix warmRoot))
+
+ failedWorkspace <-
+ parseExactWorkspace bootstrap mounts failedRelative
+ failedInput <- expectRight
+ (Module.typedModuleInput
+ foundation
+ (Module.bootstrapPreludeReadiness bootstrap)
+ unusedResolver
+ Declaration.FreshValidation
+ (Parse.parsedWorkspaceRootModule failedWorkspace)
+ [])
+ Module.runTypedModule failedInput >>= \case
+ Module.TypedModuleFailed
+ (Module.TypedActionFailed
+ (Module.TypedExactProofFailed
+ (ExactProof.ExactProofElaborationFailed
+ (Exact.ExactFreeVariable location
+ (Raw.NamedVar "f")))))
+ prefix -> do
+ assertEqual "self-reference rejection line"
+ 6 (locLine location)
+ assertBool "failed local function publishes no theorem"
+ (null
+ (Declaration.pendingModulePrefixBatches prefix))
+ Module.TypedModuleSucceeded{} ->
+ assertFailure "self-referential local function was accepted"
+ Module.TypedModuleOpenFailed failure ->
+ assertFailure
+ ("local-function failure fixture did not open: "
+ <> show failure)
+ Module.TypedModuleFailed failure _prefix ->
+ assertFailure
+ ("unexpected local-function failure: "
+ <> show failure)
+ where
+ assertExactLocalFunctionCharacteristic proposition = do
+ pair <-
+ maybe
+ (assertFailure "local function characteristic has wrong shape")
+ pure
+ (localFunctionPair proposition)
+ assertEqual "local function uses the exact replacement characteristic"
+ (expectedLocalFunctionCharacteristic pair)
+ proposition
+
+ localFunctionPair proposition =
+ case Set.toList (Core.canonicalTermGlobals proposition) of
+ [pair]
+ | proposition == expectedLocalFunctionCharacteristic pair ->
+ Just pair
+ _ ->
+ Nothing
+
+ expectedLocalFunctionCharacteristic pair =
+ Core.CForall Core.TySet
+ (Core.CEq Core.TyProp
+ (member (Core.CBound 0) (Core.CBound 1))
+ (existsP
+ (andP
+ (member (Core.CBound 0) (Core.CBound 3))
+ (Core.CEq Core.TySet
+ (Core.CBound 1)
+ (Core.CApp
+ (Core.CApp
+ (Core.CGlobal pair)
+ (Core.CBound 0))
+ (Core.CBound 0))))))
+
+ member element set =
+ Core.CApp
+ (Core.CApp (Core.CIntrinsic Core.Member) element)
+ set
+
+ andP left right =
+ notP (Core.CImp left (notP right))
+
+ existsP proposition =
+ notP (Core.CForall Core.TySet (notP proposition))
+
+ notP proposition =
+ Core.CImp proposition Core.CFalsum
+
confinesTerminalExactContradiction :: Assertion
confinesTerminalExactContradiction =
Temp.withSystemTempDirectory "felix-exact-contradiction" \directory -> do
@@ -3210,7 +3463,8 @@ assertExactDatatypeModule label sealed = do
(\binding ->
case Semantic.semanticGlobalBindingTarget binding of
Semantic.GlobalReference{} -> True
- Semantic.TransparentExpansion{} -> False)
+ Semantic.TransparentExpansion{} -> False
+ Semantic.ContextualTransparentExpansion{} -> False)
bindings)
assertEqual (label <> " datatype global targets")
(Set.fromList objectIds)
@@ -4537,9 +4791,6 @@ loadsCachedExactProducerForFreshImporter = do
executable
Provers.defaultTimeLimit
Provers.defaultMemoryLimit
- resolver = Declaration.vampireResolver \prepared ->
- runNoLoggingT
- (Provers.runPreparedTypedProver prover prepared)
verify mode source =
runNoLoggingT
(Api.verifyWithObserverAndStoreMode
@@ -4553,10 +4804,12 @@ loadsCachedExactProducerForFreshImporter = do
"test/phase5/exact-importer.tex"
assertTypedSuccess "fresh producer" producer
assertTypedSuccess "warm producer/fresh importer" importer
+ memo <- Store.newStoreMemo store
prelude <-
expectRight
- =<< Module.buildFinalPreludeSession
- store foundation resolver
+ =<< Module.acquireFinalPreludeSession
+ memo store foundation unusedResolver
+ preludeVisits <- Store.storeMemoVisits memo
repository <- getCurrentDirectory
mounts <- exactFixtureMounts repository
workspace <- parseFinalExactWorkspace
@@ -4566,11 +4819,11 @@ loadsCachedExactProducerForFreshImporter = do
(Parse.parsedWorkspaceImportedBeforeImporter workspace)
preludeSemantic =
Module.sealedTypedModuleSemantic
- (Module.migrationPreludeModule prelude)
+ (Module.finalPreludeModule prelude)
preludeId =
Semantic.semanticInterfaceAssertedId preludeSemantic
theory = Identity.theoryId foundation
- loadInstallation memo parsed direct = do
+ loadInstallation parsed direct = do
key <- expectRight
(Semantic.moduleArtifactKey
(moduleName (Parse.parsedModuleAddress parsed))
@@ -4598,16 +4851,25 @@ loadsCachedExactProducerForFreshImporter = do
]
case parsedModules of
[producerParsed, importerParsed] -> do
- memo <- Store.newStoreMemo store
producerInstallation <-
- loadInstallation memo producerParsed [preludeId]
+ loadInstallation producerParsed [preludeId]
+ producerVisits <- Store.storeMemoVisits memo
+ assertEqual "ordinary root adds one artifact validation"
+ (Store.storeArtifactsValidated preludeVisits + 1)
+ (Store.storeArtifactsValidated producerVisits)
+ assertEqual "ordinary root reuses prelude syntax validation"
+ (Store.storeSyntaxRowsValidated preludeVisits + 1)
+ (Store.storeSyntaxRowsValidated producerVisits)
+ assertEqual "ordinary root reuses prelude semantic validation"
+ (Store.storeSemanticRowsValidated preludeVisits + 1)
+ (Store.storeSemanticRowsValidated producerVisits)
let producerSemanticId =
Semantic.semanticInterfaceAssertedId
(Store.cachedInstallationSemantic
producerInstallation)
importerInstallation <-
loadInstallation
- memo importerParsed [preludeId, producerSemanticId]
+ importerParsed [preludeId, producerSemanticId]
case ( environmentBindings producerInstallation
, environmentBindings importerInstallation
) of
@@ -4666,6 +4928,832 @@ loadsCachedExactProducerForFreshImporter = do
<> show (length modules))
Store.closeStore store
+selectsConcurrentModuleFailureDeterministically :: Assertion
+selectsConcurrentModuleFailureDeterministically = do
+ foundation <- expectRight Foundation.checkedFoundation
+ Temp.withSystemTempDirectory "felix-concurrent-module-failure" \root -> do
+ let executable = root Posix.</> "vampire"
+ source = "test/phase7/concurrent-failure-root.tex"
+ prover =
+ Provers.vampire
+ executable
+ Provers.defaultTimeLimit
+ Provers.defaultMemoryLimit
+ ignored =
+ Api.verificationRequestObserver
+ (\_position _request -> pure ())
+ select amount =
+ Provers.selectEffectiveJobs
+ (Provers.effectiveJobs amount)
+ (fail "explicit jobs unexpectedly detected processors")
+ reportEntry escape =
+ ( Api.reportedEscapeKind escape
+ , locFile (Api.reportedEscapeLocation escape)
+ , locLine (Api.reportedEscapeLocation escape)
+ )
+ inspect label expectedPositions
+ (result, measurements, positions) = do
+ case result of
+ Api.VerificationFailure report failed -> do
+ assertEqual (label <> " selected earlier failure")
+ "test/phase7/concurrent-earlier.tex"
+ (locFile (Api.failedVerificationLocation failed))
+ assertEqual (label <> " admitted source prefix")
+ [ ( Api.ReportedSourceAxiom
+ , "test/phase7/concurrent-earlier.tex"
+ , 1
+ )
+ ]
+ (reportEntry
+ <$> Api.verificationDirectEscapes report)
+ other ->
+ assertFailure
+ (label <> " did not reject deterministically: "
+ <> show other)
+ assertEqual (label <> " executed only sibling obligations")
+ expectedPositions
+ (sort
+ [ ( Provers.workPositionModuleOrdinal position
+ , Provers.workPositionLocalRequestOrdinal position
+ )
+ | position <- positions
+ ])
+ pure measurements
+ runCase label jobsAmount = do
+ let storePath = root Posix.</> (label <> ".sqlite")
+ processLock = root Posix.</> (label <> ".process-lock")
+ processStarted =
+ root Posix.</> (label <> ".process-started")
+ writeAcceptedFixtureVampire executable
+ (_startup, store) <-
+ Store.openStore storePath (Identity.theoryId foundation)
+ >>= expectRight
+ bracket (pure store) Store.closeStore \openStore -> do
+ -- Seed only the final prelude. The unsupported ordinary
+ -- module cannot publish a root.
+ void
+ (runNoLoggingT
+ (Api.verifyMeasuredWithObserverAndStoreMode
+ openStore
+ Api.WarmStoreValidation
+ ignored
+ prover
+ "test/phase3/typed-unsupported.tex")
+ >>= expectRight)
+ writeFile executable
+ (unlines
+ [ "#!/bin/sh"
+ , "while ! mkdir \"" <> processLock
+ <> "\" 2>/dev/null; do sleep 0.01; done"
+ , "trap 'rmdir \"" <> processLock
+ <> "\"' EXIT"
+ , ": > \"" <> processStarted <> "\""
+ , "cat >/dev/null"
+ , "printf '%s\\n' '% SZS status CounterSatisfiable for concurrent-fixture'"
+ ])
+ permissions <- getPermissions executable
+ setPermissions executable
+ (setOwnerExecutable True permissions)
+ positionsRef <- newIORef []
+ let observer =
+ Api.verificationRequestObserver
+ (\position _request -> do
+ atomicModifyIORef' positionsRef
+ (\positions ->
+ (position : positions, ()))
+ when
+ (jobsAmount > 1
+ && Provers.workPositionModuleOrdinal
+ position == 1)
+ (waitForFileSignal
+ "later module process"
+ processStarted))
+ jobs <- select jobsAmount
+ (result, measurements) <-
+ runNoLoggingT
+ (Api.verifyMeasuredWithObserverAndStoreModeAndJobs
+ openStore
+ Api.WarmStoreValidation
+ jobs
+ observer
+ prover
+ source)
+ >>= expectRight
+ positions <- readIORef positionsRef
+ pure (result, measurements, positions)
+ parallel <-
+ runCase "parallel" 2
+ >>= inspect "parallel" [(1, 1), (2, 1)]
+ sequential <-
+ runCase "sequential" 1
+ >>= inspect "sequential" [(1, 1)]
+ assertEqual "parallel module checker bound"
+ 2
+ (Api.verificationMaximumLiveModuleCheckers parallel)
+ assertEqual "parallel Vampire bound"
+ 2
+ (Api.verificationMaximumLiveVampireProcesses parallel)
+ assertEqual "sequential module checker reference"
+ 1
+ (Api.verificationMaximumLiveModuleCheckers sequential)
+ assertEqual "sequential Vampire reference"
+ 1
+ (Api.verificationMaximumLiveVampireProcesses sequential)
+
+waitForFileSignal :: String -> FilePath -> Assertion
+waitForFileSignal label path = do
+ guarded <- Timeout.timeout 10000000 loop
+ case guarded of
+ Just () ->
+ pure ()
+ Nothing ->
+ assertFailure (label <> " was not observed")
+ where
+ loop = do
+ exists <- doesFileExist path
+ if exists
+ then pure ()
+ else do
+ threadDelay 10000
+ loop
+
+batchesStructureObligationsAtomically :: Assertion
+batchesStructureObligationsAtomically = do
+ foundation <- expectRight Foundation.checkedFoundation
+ Temp.withSystemTempDirectory "felix-structure-obligation-batch" \root -> do
+ let storePath = root Posix.</> "store.sqlite"
+ executable = root Posix.</> "vampire"
+ unavailable = root Posix.</> "must-not-run-vampire"
+ source = "test/phase7/structure-obligation-batch.tex"
+ prover path =
+ Provers.vampire
+ path
+ Provers.defaultTimeLimit
+ Provers.defaultMemoryLimit
+ select amount =
+ Provers.selectEffectiveJobs
+ (Provers.effectiveJobs amount)
+ (fail "explicit jobs unexpectedly detected processors")
+ run openStore jobs observer vampireCommand =
+ runNoLoggingT
+ (Api.verifyMeasuredWithObserverAndStoreModeAndJobs
+ openStore
+ Api.WarmStoreValidation
+ jobs
+ observer
+ vampireCommand
+ source)
+ >>= expectRight
+ inspectFailure label positions (result, measurements) = do
+ case result of
+ Api.VerificationFailure report failed -> do
+ assertEqual (label <> " selects first consequence")
+ (source, 12)
+ ( locFile (Api.failedVerificationLocation failed)
+ , locLine (Api.failedVerificationLocation failed)
+ )
+ assertEqual (label <> " retains preceding prefix")
+ [(Api.ReportedSourceAxiom, source, 1)]
+ [ ( Api.reportedEscapeKind escape
+ , locFile (Api.reportedEscapeLocation escape)
+ , locLine (Api.reportedEscapeLocation escape)
+ )
+ | escape <- Api.verificationDirectEscapes report
+ ]
+ other ->
+ assertFailure
+ (label <> " did not reject its structure batch: "
+ <> show other)
+ assertEqual (label <> " assigns consecutive positions")
+ [(1, 1), (1, 2)]
+ (sort positions)
+ assertEqual (label <> " observes one two-member batch")
+ (1, 2, 2)
+ ( Api.verificationObligationBatchCount measurements
+ , Api.verificationPreparedObligationCount measurements
+ , Api.verificationMaximumObligationBatchSize measurements
+ )
+ pure measurements
+ writeAcceptedFixtureVampire executable
+ (_startup, store) <-
+ Store.openStore storePath (Identity.theoryId foundation)
+ >>= expectRight
+ bracket (pure store) Store.closeStore \openStore -> do
+ let ignored =
+ Api.verificationRequestObserver
+ (\_position _request -> pure ())
+ -- Seed only the confined prelude so this fixture observes exactly
+ -- the ordinary structure module's ready batch.
+ void
+ (runNoLoggingT
+ (Api.verifyMeasuredWithObserverAndStoreMode
+ openStore
+ Api.WarmStoreValidation
+ ignored
+ (prover executable)
+ "test/phase3/typed-unsupported.tex")
+ >>= expectRight)
+ parallelJobs <- select 2
+ parallelPositions <- newIORef []
+ firstStarted <- newEmptyTMVarIO
+ secondStarted <- newEmptyTMVarIO
+ releaseFirst <- newEmptyTMVarIO
+ let laterCompleted = root Posix.</> "later-completed"
+ writeRejectingVampire executable laterCompleted
+ let parallelObserver =
+ Api.verificationRequestObserver \position _request -> do
+ let ordinal =
+ Provers.workPositionLocalRequestOrdinal position
+ atomicModifyIORef' parallelPositions
+ (\positions ->
+ ( ( Provers.workPositionModuleOrdinal position
+ , ordinal
+ ) : positions
+ , ()
+ ))
+ case ordinal of
+ 1 -> do
+ atomically (putTMVar firstStarted ())
+ atomically (takeTMVar releaseFirst)
+ 2 ->
+ atomically (putTMVar secondStarted ())
+ _ ->
+ assertFailure
+ ("unexpected structure request ordinal: "
+ <> show ordinal)
+ withAsync
+ (run openStore parallelJobs parallelObserver
+ (prover executable))
+ \verification -> do
+ void
+ (awaitSignal "first structure request"
+ (atomically (takeTMVar firstStarted)))
+ void
+ (awaitSignal "second structure request"
+ (atomically (takeTMVar secondStarted)))
+ -- Only the later member can reach the subprocess while
+ -- the first observer is gated. Its completed signal
+ -- therefore establishes reversed wall-clock completion.
+ waitForFileSignal
+ "later structure consequence"
+ laterCompleted
+ atomically (putTMVar releaseFirst ())
+ parallelResult <- wait verification
+ positions <- readIORef parallelPositions
+ parallelMeasurements <-
+ inspectFailure "parallel"
+ positions parallelResult
+ assertEqual "parallel obligations overlap"
+ 2
+ (Api.verificationMaximumLiveVampireProcesses
+ parallelMeasurements)
+
+ sequentialJobs <- select 1
+ sequentialPositions <- newIORef []
+ let sequentialCompleted = root Posix.</> "sequential-completed"
+ writeRejectingVampire executable sequentialCompleted
+ let sequentialObserver =
+ Api.verificationRequestObserver \position _request ->
+ atomicModifyIORef' sequentialPositions
+ (\positions ->
+ ( ( Provers.workPositionModuleOrdinal position
+ , Provers.workPositionLocalRequestOrdinal
+ position
+ ) : positions
+ , ()
+ ))
+ sequentialResult <-
+ run openStore sequentialJobs sequentialObserver
+ (prover executable)
+ sequentialObserved <- readIORef sequentialPositions
+ sequentialMeasurements <-
+ inspectFailure "sequential"
+ sequentialObserved sequentialResult
+ assertEqual "sequential batch is the semantic reference"
+ 1
+ (Api.verificationMaximumLiveVampireProcesses
+ sequentialMeasurements)
+
+ -- A rejected sibling wrote neither validation nor a module root:
+ -- the complete batch executes again, while the earlier source
+ -- axiom remains the admitted prefix. A subsequent hit executes
+ -- no request at all.
+ writeAcceptedFixtureVampire executable
+ acceptedPositions <- newIORef []
+ let acceptedObserver =
+ Api.verificationRequestObserver \position _request ->
+ modifyIORef' acceptedPositions
+ (position :)
+ (accepted, acceptedMeasurements) <-
+ run openStore parallelJobs acceptedObserver
+ (prover executable)
+ case accepted of
+ Api.VerificationCompleted report _presentation ->
+ assertEqual "successful retry retains only source axiom"
+ [Api.ReportedSourceAxiom]
+ (Api.reportedEscapeKind
+ <$> Api.verificationDirectEscapes report)
+ other ->
+ assertFailure
+ ("successful structure retry failed: " <> show other)
+ acceptedObserved <- readIORef acceptedPositions
+ assertEqual "successful retry executes the complete batch"
+ 2
+ (length acceptedObserved)
+ assertEqual "failed declaration published no root"
+ (1, 1)
+ ( Api.verificationModuleRootHitCount acceptedMeasurements
+ , Api.verificationModuleRootMissCount acceptedMeasurements
+ )
+ let forbiddenObserver =
+ Api.verificationRequestObserver \position _request ->
+ assertFailure
+ ("warm structure batch invoked Vampire at "
+ <> show position)
+ (warm, warmMeasurements) <-
+ run openStore parallelJobs forbiddenObserver
+ (prover unavailable)
+ case warm of
+ Api.VerificationCompleted{} -> pure ()
+ other ->
+ assertFailure
+ ("warm structure batch did not install: " <> show other)
+ assertEqual "warm module hit executes no batch"
+ (2, 0, 0)
+ ( Api.verificationModuleRootHitCount warmMeasurements
+ , Api.verificationModuleRootMissCount warmMeasurements
+ , Api.verificationVampireRunCount warmMeasurements
+ )
+ where
+ awaitSignal label action = do
+ result <- Timeout.timeout 10000000 action
+ maybe
+ (assertFailure (label <> " was not observed")
+ >> fail "unreachable")
+ pure
+ result
+
+ writeRejectingVampire executable completed = do
+ writeFile executable
+ (unlines
+ [ "#!/bin/sh"
+ , "cat >/dev/null"
+ , ": > \"" <> completed <> "\""
+ , "printf '%s\\n' '% SZS status CounterSatisfiable for structure-batch-fixture'"
+ ])
+ permissions <- getPermissions executable
+ setPermissions executable
+ (setOwnerExecutable True permissions)
+
+keepsDependentProofObligationsSequential :: Assertion
+keepsDependentProofObligationsSequential =
+ Temp.withSystemTempDirectory "felix-dependent-proof-chain" \root -> do
+ repository <- getCurrentDirectory
+ foundation <- expectRight Foundation.checkedFoundation
+ bootstrap <-
+ expectRight
+ =<< Module.buildBootstrapPreludeFixture
+ foundation
+ unusedResolver
+ mounts <- exactFixtureMounts repository
+ workspace <- parseExactWorkspace
+ bootstrap mounts "test/phase7/dependent-proof-chain.tex"
+ let executable = root Posix.</> "vampire"
+ writeAcceptedFixtureVampire executable
+ firstSubmitted <- newEmptyTMVarIO
+ secondSubmitted <- newEmptyTMVarIO
+ releaseFirst <- newEmptyTMVarIO
+ calls <- newIORef (0 :: Int)
+ let resolver =
+ Declaration.vampireBatchResolver \tasks -> do
+ assertEqual "dependent proof resolver batch is singleton"
+ 1
+ (NonEmpty.length tasks)
+ ordinal <- atomicModifyIORef' calls
+ (\current -> (current + 1, current + 1))
+ case ordinal of
+ 1 -> do
+ atomically (putTMVar firstSubmitted ())
+ atomically (takeTMVar releaseFirst)
+ 2 ->
+ atomically (putTMVar secondSubmitted ())
+ _ ->
+ assertFailure
+ ("unexpected dependent proof request: "
+ <> show ordinal)
+ traverse
+ (\prepared ->
+ runNoLoggingT
+ (Provers.runPreparedTypedProver
+ (Provers.vampire
+ executable
+ Provers.defaultTimeLimit
+ Provers.defaultMemoryLimit)
+ prepared))
+ tasks
+ withAsync
+ (compileParsedWorkspaceWithResolver
+ foundation bootstrap resolver workspace)
+ \checking -> do
+ void
+ (awaitSignal "local subclaim request"
+ (atomically (takeTMVar firstSubmitted)))
+ atomically (tryReadTMVar secondSubmitted) >>= \case
+ Nothing -> pure ()
+ Just () ->
+ assertFailure
+ "proof continuation was submitted before its local claim"
+ atomically (putTMVar releaseFirst ())
+ void
+ (awaitSignal "dependent continuation request"
+ (atomically (takeTMVar secondSubmitted)))
+ sealed <- wait checking
+ assertEqual "dependent proof module sealed" 1 (length sealed)
+ readIORef calls
+ >>= assertEqual "dependent proof executed two ordered requests" 2
+ where
+ awaitSignal label action = do
+ result <- Timeout.timeout 10000000 action
+ maybe
+ (assertFailure (label <> " was not observed")
+ >> fail "unreachable")
+ pure
+ result
+
+schedulesDiamondAfterSealedImports :: Assertion
+schedulesDiamondAfterSealedImports = do
+ foundation <- expectRight Foundation.checkedFoundation
+ Temp.withSystemTempDirectory "felix-concurrent-diamond" \root -> do
+ let storePath = root Posix.</> "store.sqlite"
+ executable = root Posix.</> "vampire"
+ unavailable = root Posix.</> "must-not-run-vampire"
+ source = "test/phase7/diamond-root.tex"
+ prover path =
+ Provers.vampire
+ path
+ Provers.defaultTimeLimit
+ Provers.defaultMemoryLimit
+ ignored =
+ Api.verificationRequestObserver
+ (\_position _request -> pure ())
+ writeAcceptedFixtureVampire executable
+ (_startup, store) <-
+ Store.openStore storePath (Identity.theoryId foundation)
+ >>= expectRight
+ bracket (pure store) Store.closeStore \openStore -> do
+ -- Acquire the final prelude before introducing scheduler gates.
+ void
+ (runNoLoggingT
+ (Api.verifyMeasuredWithObserverAndStoreMode
+ openStore
+ Api.WarmStoreValidation
+ ignored
+ (prover executable)
+ "test/phase3/typed-unsupported.tex")
+ >>= expectRight)
+ jobs <- Provers.selectEffectiveJobs
+ (Provers.effectiveJobs 2)
+ (fail "explicit jobs unexpectedly detected processors")
+ baseStarted <- newEmptyTMVarIO
+ branchStarted <- newTQueueIO
+ rootStarted <- newEmptyTMVarIO
+ releaseBase <- newTVarIO False
+ releaseBranches <- newTVarIO False
+ let awaitRelease released =
+ atomically (readTVar released >>= check)
+ observer =
+ Api.verificationRequestObserver
+ (\position _request ->
+ case Provers.workPositionModuleOrdinal position of
+ 1 -> do
+ atomically (putTMVar baseStarted ())
+ awaitRelease releaseBase
+ ordinal@2 -> do
+ atomically
+ (writeTQueue branchStarted ordinal)
+ awaitRelease releaseBranches
+ ordinal@3 -> do
+ atomically
+ (writeTQueue branchStarted ordinal)
+ awaitRelease releaseBranches
+ 4 ->
+ atomically (putTMVar rootStarted ())
+ _ ->
+ pure ())
+ verify vampireCommand requestObserver =
+ runNoLoggingT
+ (Api.verifyMeasuredWithObserverAndStoreModeAndJobs
+ openStore
+ Api.WarmStoreValidation
+ jobs
+ requestObserver
+ vampireCommand
+ source)
+ >>= expectRight
+ await label action = do
+ result <- Timeout.timeout 10000000 action
+ maybe
+ (assertFailure (label <> " was not observed")
+ >> fail "unreachable")
+ pure
+ result
+ withAsync (verify (prover executable) observer) \verification -> do
+ void (await "base request" (atomically (takeTMVar baseStarted)))
+ threadDelay 50000
+ atomically (tryReadTQueue branchStarted) >>= \case
+ Nothing -> pure ()
+ Just ordinal ->
+ assertFailure
+ ("dependent module started before base seal: "
+ <> show ordinal)
+ atomically (writeTVar releaseBase True)
+ firstBranch <- await "first branch"
+ (atomically (readTQueue branchStarted))
+ secondBranch <- await "second branch"
+ (atomically (readTQueue branchStarted))
+ assertEqual "both diamond branches became ready together"
+ [2, 3]
+ (sort [firstBranch, secondBranch])
+ atomically (tryReadTMVar rootStarted) >>= \case
+ Nothing -> pure ()
+ Just () ->
+ assertFailure
+ "diamond root started before both branch seals"
+ atomically (writeTVar releaseBranches True)
+ void (await "diamond root" (atomically (takeTMVar rootStarted)))
+ (coldResult, coldMeasurements) <- wait verification
+ case coldResult of
+ Api.VerificationCompleted{} -> pure ()
+ other ->
+ assertFailure
+ ("cold diamond did not complete: " <> show other)
+ assertEqual "cold diamond module misses plus prelude hit"
+ (1, 4)
+ ( Api.verificationModuleRootHitCount coldMeasurements
+ , Api.verificationModuleRootMissCount coldMeasurements
+ )
+ let forbiddenObserver =
+ Api.verificationRequestObserver
+ (\position _request ->
+ assertFailure
+ ("warm diamond invoked Vampire at "
+ <> show position))
+ (warmResult, warmMeasurements) <-
+ verify (prover unavailable) forbiddenObserver
+ case warmResult of
+ Api.VerificationCompleted{} -> pure ()
+ other ->
+ assertFailure
+ ("warm diamond did not install: " <> show other)
+ assertEqual "warm diamond installs each distinct root"
+ (5, 0)
+ ( Api.verificationModuleRootHitCount warmMeasurements
+ , Api.verificationModuleRootMissCount warmMeasurements
+ )
+ assertEqual "warm diamond runs no prover"
+ 0
+ (Api.verificationVampireRunCount warmMeasurements)
+
+reportsAdmittedSourceEscapes :: Assertion
+reportsAdmittedSourceEscapes = do
+ foundation <- expectRight Foundation.checkedFoundation
+ Temp.withSystemTempDirectory "felix-admitted-source-report" \root -> do
+ let storePath = root Posix.</> "store.sqlite"
+ executable = root Posix.</> "vampire"
+ unavailable = root Posix.</> "must-not-run-vampire"
+ observer =
+ Api.verificationRequestObserver \_ordinal _request -> pure ()
+ prover path =
+ Provers.vampire
+ path
+ Provers.defaultTimeLimit
+ Provers.defaultMemoryLimit
+ writeAcceptedFixtureVampire executable
+ (_startup, store) <-
+ Store.openStore storePath (Identity.theoryId foundation)
+ >>= expectRight
+ bracket (pure store) Store.closeStore \openStore -> do
+ let verify mode vampirePath source =
+ runNoLoggingT
+ (Api.verifyMeasuredWithObserverAndStoreMode
+ openStore
+ mode
+ observer
+ (prover vampirePath)
+ source)
+ >>= expectRight
+ reportEntries =
+ fmap
+ (\escape ->
+ ( Api.reportedEscapeKind escape
+ , locFile (Api.reportedEscapeLocation escape)
+ , locLine (Api.reportedEscapeLocation escape)
+ ))
+ . Api.verificationDirectEscapes
+ expectedConsumer =
+ [ ( Api.ReportedSourceAxiom
+ , "test/phase5/exact-escape-producer.tex"
+ , 1
+ )
+ , ( Api.ReportedOmitted
+ , "test/phase5/exact-escape-producer.tex"
+ , 9
+ )
+ , ( Api.ReportedOmitted
+ , "test/phase5/exact-escape-consumer.tex"
+ , 35
+ )
+ ]
+ (freshResult, freshMeasurements) <-
+ verify
+ Api.FreshStoreValidation
+ executable
+ "test/phase5/exact-escape-consumer.tex"
+ freshReport <- case freshResult of
+ Api.CompletedWithExplicitGaps report _presentation -> pure report
+ other ->
+ assertFailure
+ ("fresh escape report did not complete with gaps: "
+ <> show other)
+ >> fail "unreachable"
+ assertEqual "fresh direct escapes"
+ expectedConsumer
+ (reportEntries freshReport)
+ assertEqual "cold acquisition includes prelude and two modules"
+ (0, 3)
+ ( Api.verificationModuleRootHitCount freshMeasurements
+ , Api.verificationModuleRootMissCount freshMeasurements
+ )
+
+ (warmResult, warmMeasurements) <-
+ verify
+ Api.WarmStoreValidation
+ unavailable
+ "test/phase5/exact-escape-consumer.tex"
+ warmReport <- case warmResult of
+ Api.CompletedWithExplicitGaps report _presentation -> pure report
+ other ->
+ assertFailure
+ ("warm escape report did not complete with gaps: "
+ <> show other)
+ >> fail "unreachable"
+ assertEqual "warm report uses rebound current locations"
+ freshReport warmReport
+ assertEqual "warm acquisition includes prelude and two modules"
+ (3, 0)
+ ( Api.verificationModuleRootHitCount warmMeasurements
+ , Api.verificationModuleRootMissCount warmMeasurements
+ )
+ assertEqual "warm root hit invokes no Vampire process"
+ 0
+ (Api.verificationVampireRunCount warmMeasurements)
+
+ void
+ (verify
+ Api.FreshStoreValidation
+ executable
+ "test/phase5/exact-source-axiom.tex")
+ (failedResult, failedMeasurements) <-
+ verify
+ Api.WarmStoreValidation
+ unavailable
+ "test/phase6/admitted-prefix-failure.tex"
+ failedReport <- case failedResult of
+ Api.VerificationCheckingFailure report _failure -> pure report
+ other ->
+ assertFailure
+ ("typed suffix failure was not report-bearing: "
+ <> show other)
+ >> fail "unreachable"
+ assertEqual "failure report retains only admitted source prefix"
+ (take 2 expectedConsumer
+ <> [ ( Api.ReportedOmitted
+ , "test/phase6/admitted-prefix-failure.tex"
+ , 7
+ )
+ ])
+ (reportEntries failedReport)
+ assertEqual "failed root is not counted as acquired"
+ (2, 0)
+ ( Api.verificationModuleRootHitCount failedMeasurements
+ , Api.verificationModuleRootMissCount failedMeasurements
+ )
+ assertEqual "cached prefix failure invokes no Vampire process"
+ 0
+ (Api.verificationVampireRunCount failedMeasurements)
+
+classifiesTypedVampireFailures :: Assertion
+classifiesTypedVampireFailures = do
+ foundation <- expectRight Foundation.checkedFoundation
+ Temp.withSystemTempDirectory "felix-typed-failure-classification" \root -> do
+ let storePath = root Posix.</> "store.sqlite"
+ executable = root Posix.</> "vampire"
+ observer =
+ Api.verificationRequestObserver \_ordinal _request -> pure ()
+ prover =
+ Provers.vampire
+ executable
+ Provers.defaultTimeLimit
+ Provers.defaultMemoryLimit
+ writeAcceptedFixtureVampire executable
+ (_startup, store) <-
+ Store.openStore storePath (Identity.theoryId foundation)
+ >>= expectRight
+ bracket (pure store) Store.closeStore \openStore -> do
+ let verify source =
+ runNoLoggingT
+ (Api.verifyMeasuredWithObserverAndStoreMode
+ openStore
+ Api.WarmStoreValidation
+ observer
+ prover
+ source)
+ >>= expectRight
+ writeProtocol lines = do
+ writeFile executable
+ (unlines (["#!/bin/sh", "cat >/dev/null"] <> lines))
+ permissions <- getPermissions executable
+ setPermissions executable
+ (setOwnerExecutable True permissions)
+ expectTypedFailure classify = do
+ (result, _measurements) <-
+ verify "test/phase5/exact-runtime-failure.tex"
+ case result of
+ Api.VerificationFailure report failed -> do
+ assertEqual "typed failure has no direct escapes"
+ []
+ (Api.verificationDirectEscapes report)
+ assertEqual "typed failure retains source location"
+ "test/phase5/exact-runtime-failure.tex"
+ (locFile
+ (Api.failedVerificationLocation failed))
+ classify
+ (Api.failedVerificationReason failed)
+ (CommandLine.verificationCommandOutcome result)
+ other ->
+ assertFailure
+ ("typed prover outcome was misclassified: "
+ <> show other)
+
+ -- Populate only the confined prelude. The selected ordinary
+ -- module then remains a miss for each classified live failure.
+ (_preludeResult, _preludeMeasurements) <-
+ verify "test/phase3/typed-unsupported.tex"
+
+ writeProtocol
+ [ "printf '%s\\n' '% SZS status CounterSatisfiable for typed-failure'"
+ , "exit 0"
+ ]
+ expectTypedFailure \reason outcome -> do
+ case reason of
+ Api.CountermodelFailure{} -> pure ()
+ other -> assertFailure ("expected countermodel: " <> show other)
+ case outcome of
+ CommandLine.VerificationRejected{} -> pure ()
+ other -> assertFailure ("expected rejection: " <> show other)
+
+ writeProtocol
+ [ "printf '%s\\n' '% SZS status Timeout for typed-failure'"
+ , "exit 0"
+ ]
+ expectTypedFailure \reason outcome -> do
+ case reason of
+ Api.IndeterminateFailure{} -> pure ()
+ other -> assertFailure ("expected indeterminate result: " <> show other)
+ case outcome of
+ CommandLine.ProverFailed
+ _report _location CommandLine.ProverIndeterminate{} ->
+ pure ()
+ other -> assertFailure ("expected prover failure: " <> show other)
+
+ writeProtocol
+ [ "printf '%s\\n' '% SZS status Theorem for typed-failure'"
+ , "exit 7"
+ ]
+ expectTypedFailure \reason outcome -> do
+ case reason of
+ Api.ProtocolFailure{} -> pure ()
+ other -> assertFailure ("expected protocol failure: " <> show other)
+ case outcome of
+ CommandLine.ProverFailed
+ _report _location CommandLine.ProverProtocolFailure{} ->
+ pure ()
+ other -> assertFailure ("expected prover failure: " <> show other)
+
+ writeFile executable "not executable"
+ permissions <- getPermissions executable
+ setPermissions executable
+ (setOwnerExecutable False permissions)
+ expectTypedFailure \reason outcome -> do
+ case reason of
+ Api.TransportFailure{} -> pure ()
+ other -> assertFailure ("expected transport failure: " <> show other)
+ case outcome of
+ CommandLine.ProverFailed
+ _report _location CommandLine.ProverTransportFailure{} ->
+ pure ()
+ other -> assertFailure ("expected prover failure: " <> show other)
+
retainsExactPrefixBeforeFailure :: Assertion
retainsExactPrefixBeforeFailure = do
result <-
@@ -4675,13 +5763,16 @@ retainsExactPrefixBeforeFailure = do
prover
"test/phase5/exact-failure.tex")
case result of
- Left
- (Api.VerificationTypedModuleError
+ Right
+ ( Api.VerificationCheckingFailure _report
+ (Api.VerificationTypedModuleError
source
(Module.TypedActionFailed
(Module.TypedExactCompileFailed
(Exact.ExactUnsupportedDeclarationBody location)))
- prefix) -> do
+ prefix)
+ , _measurements
+ ) -> do
assertEqual "failed exact source"
"test/phase5/exact-failure.tex"
(safeRelativePathFilePath
@@ -4702,14 +5793,17 @@ retainsExactPrefixBeforeFailure = do
prover
"test/phase5/exact-proof-failure.tex")
case proofFailure of
- Left
- (Api.VerificationTypedModuleError
+ Right
+ ( Api.VerificationCheckingFailure _report
+ (Api.VerificationTypedModuleError
_source
(Module.TypedActionFailed
(Module.TypedExactProofFailed
(ExactProof.ExactProofGoalStatementMismatch
location)))
- prefix) -> do
+ prefix)
+ , _measurements
+ ) -> do
assertEqual "mismatched assumption line" 10 (locLine location)
assertEqual "failed proof publishes no theorem"
1
@@ -4727,12 +5821,15 @@ retainsExactPrefixBeforeFailure = do
prover
"test/phase5/unmatched-proof.tex")
case unmatched of
- Left
- (Api.VerificationTypedModuleError
+ Right
+ ( Api.VerificationCheckingFailure _report
+ (Api.VerificationTypedModuleError
_source
(Module.TypedActionFailed
(Module.TypedUnmatchedProof location))
- prefix) -> do
+ prefix)
+ , _measurements
+ ) -> do
assertEqual "unmatched proof line" 1 (locLine location)
assertEqual "unmatched proof publishes no declaration"
0
@@ -4821,14 +5918,17 @@ rejectsNestedExactSetInduction = do
prover
"test/phase5/exact-induction-nested.tex")
case result of
- Left
- (Api.VerificationTypedModuleError
+ Right
+ ( Api.VerificationCheckingFailure _report
+ (Api.VerificationTypedModuleError
_source
(Module.TypedActionFailed
(Module.TypedExactProofFailed
(ExactProof.ExactProofSetInductionNotOutermost
location)))
- prefix) -> do
+ prefix)
+ , _measurements
+ ) -> do
assertEqual "nested induction line" 7 (locLine location)
assertBool "failed proof publishes no theorem"
(null (Declaration.pendingModulePrefixBatches prefix))
@@ -4854,35 +5954,14 @@ routesProductionVerification =
setPermissions executable
(setOwnerExecutable True permissions)
producer <- verifyFixture executable "test/phase3/typed-producer.tex"
- assertRoute "selected producer"
- Api.TypedVerificationRoute
- producer
- setRoot <- verifyFixture executable "set.tex"
- assertRoute "protected set root"
- Api.TypedVerificationRoute
- setRoot
- natRoot <- verifyFixture executable "nat.tex"
- assertRoute "protected naturals root"
- Api.TypedVerificationRoute
- natRoot
- forM_
- [ ("bipartition", "set/bipartition.tex")
- , ("function", "function.tex")
- , ("Cantor", "set/cantor.tex")
- ]
- \(label, path) ->
- assertRoute ("typed " <> label)
- Api.TypedVerificationRoute
- =<< verifyFixture executable path
+ assertTypedSuccess "exact producer" producer
selectedRuns <- runCount counter
- assertBool "selected roots constructed the final prelude"
+ assertBool "ordinary roots construct the final prelude"
(selectedRuns > 0)
- importer <- verifyFixture executable "test/phase3/legacy-importer.tex"
- assertRoute "unselected importer"
- Api.LegacyVerificationRoute
- importer
- assertEqual "legacy root did not construct the final prelude"
- selectedRuns
+ importer <- verifyFixture executable "test/phase3/typed-importer.tex"
+ assertTypedSuccess "ordinary importer" importer
+ assertBool "every root constructs the final prelude"
+ . (> selectedRuns)
=<< runCount counter
where
verifyFixture executable path =
@@ -4899,16 +5978,6 @@ routesProductionVerification =
runCount path =
length . StrictText.lines . StrictText.pack <$> readFile path
- assertRoute label expected = \case
- Api.VerifiedWithTrustedVampire report ->
- assertEqual label expected (Api.verificationRoute report)
- Api.CompletedWithExplicitGaps report ->
- assertFailure
- (label <> " completed with gaps via "
- <> show (Api.verificationRoute report))
- Api.VerificationFailure failure ->
- assertFailure (label <> " failed: " <> show failure)
-
installsNonemptyImplicitPreludeEvidence :: Assertion
installsNonemptyImplicitPreludeEvidence = do
foundation <- expectRight Foundation.checkedFoundation
@@ -5330,13 +6399,13 @@ parseExactWorkspace bootstrap mounts relative =
relative
parseFinalExactWorkspace
- :: Module.MigrationPreludeSession
+ :: Module.FinalPreludeSession
-> SourceMounts
-> FilePath
-> IO Parse.ParsedSourceWorkspace
parseFinalExactWorkspace prelude mounts relative =
parseExactWorkspaceWithPrelude
- (Module.migrationPreludeModule prelude)
+ (Module.finalPreludeModule prelude)
mounts
relative
@@ -5401,7 +6470,7 @@ compileParsedWorkspaceWithValidation
compileFinalParsedWorkspaceWithResolver
:: Foundation.CheckedFoundation
- -> Module.MigrationPreludeSession
+ -> Module.FinalPreludeSession
-> Declaration.VampireResolver
-> Parse.ParsedSourceWorkspace
-> IO [Module.SealedTypedModule]
@@ -5468,14 +6537,13 @@ compileParsedWorkspaceWithReadiness
assertTypedSuccess :: String -> Api.VerificationResult -> Assertion
assertTypedSuccess label = \case
- Api.VerifiedWithTrustedVampire report ->
- assertEqual label Api.TypedVerificationRoute
- (Api.verificationRoute report)
- Api.CompletedWithExplicitGaps report ->
- assertFailure
- (label <> " completed with gaps via "
- <> show (Api.verificationRoute report))
- Api.VerificationFailure failure ->
+ Api.VerificationCompleted _report _presentation ->
+ pure ()
+ Api.CompletedWithExplicitGaps _report _presentation ->
+ assertFailure (label <> " completed with gaps")
+ Api.VerificationFailure _report failure ->
+ assertFailure (label <> " failed: " <> show failure)
+ Api.VerificationCheckingFailure _report failure ->
assertFailure (label <> " failed: " <> show failure)
sole :: String -> [value] -> IO value
@@ -5494,3 +6562,16 @@ expectRight = \case
expectRightIO :: Show error => IO (Either error value) -> IO value
expectRightIO action =
action >>= expectRight
+
+acquireFinalPreludeSession
+ :: Store.Store
+ -> Foundation.CheckedFoundation
+ -> Declaration.VampireResolver
+ -> IO
+ (Either
+ Module.FinalPreludeReadinessError
+ Module.FinalPreludeSession)
+acquireFinalPreludeSession store foundation resolver = do
+ memo <- Store.newStoreMemo store
+ Module.acquireFinalPreludeSession
+ memo store foundation resolver