summaryrefslogtreecommitdiff
path: root/source/Felix/Verification.hs
diff options
context:
space:
mode:
Diffstat (limited to 'source/Felix/Verification.hs')
-rw-r--r--source/Felix/Verification.hs1157
1 files changed, 1157 insertions, 0 deletions
diff --git a/source/Felix/Verification.hs b/source/Felix/Verification.hs
new file mode 100644
index 0000000..716beea
--- /dev/null
+++ b/source/Felix/Verification.hs
@@ -0,0 +1,1157 @@
+{-# LANGUAGE ExplicitForAll #-}
+{-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
+{-# LANGUAGE RankNTypes #-}
+
+module Felix.Verification
+ ( VerificationSession
+ , VerificationSessionError(..)
+ , withVerificationSession
+ , withVerificationSessionUsingStore
+ , CheckRequest(..)
+ , CheckOutcome(..)
+ , checkWorkspace
+ , StoreValidationMode(..)
+ , WorkPosition
+ , workPosition
+ , workPositionModuleOrdinal
+ , workPositionLocalRequestOrdinal
+ , VerificationRequestObserver
+ , verificationRequestObserver
+ , PreparedVerificationRequest
+ , SlowAtpOutcome(..)
+ , SlowAtpTask(..)
+ , SlowAtpReport(..)
+ , slowAtpOmittedTaskCount
+ , ProverAnswer
+ ( CounterSatisfiable
+ , ContradictoryAxioms
+ , Uncertain
+ , Error
+ )
+ , pattern Yes
+ , VerificationResult(..)
+ , VerificationPresentation
+ , verificationHtmlPresentation
+ , ReportedEscapeKind(..)
+ , ReportedEscape(..)
+ , VerificationReport(..)
+ , VerificationDriverError(..)
+ , VerificationDriverErrorKind(..)
+ , verificationDriverErrorKind
+ , renderVerificationDriverError
+ , FailedVerification(..)
+ , VerificationFailureReason(..)
+ ) where
+
+
+import Base
+import Felix.Checking.Declaration qualified as Declaration
+import Felix.Checking.Foundation qualified as Foundation
+import Felix.Checking.Identity qualified as Identity
+import Felix.Checking.Module qualified as Typed
+import Felix.Checking.Semantic qualified as Semantic
+import Felix.Module (localDeclarationOrdinal)
+import Felix.Parse (ParseWorkspaceError(..), ParsedSourceWorkspace)
+import Felix.Parse qualified as Felix
+import Felix.Prelude qualified as Prelude
+import Felix.Provers
+import Felix.Source
+import Felix.Source.Graph (ResolvedSourceGraph)
+import Felix.Store qualified as Store
+import Felix.Render.Html.Export qualified as HtmlExport
+import Felix.Report.Location
+import Felix.Syntax.Abstract qualified as Raw
+import Felix.Syntax.Interface qualified as Syntax
+
+import Control.Exception qualified as Exception
+import Control.Monad (unless)
+import Data.Bifunctor (first)
+import Data.IORef (atomicModifyIORef', newIORef)
+import Data.List.NonEmpty qualified as NonEmpty
+import Data.Map.Strict qualified as Map
+import Data.Text qualified as Text
+import Numeric.Natural (Natural)
+import UnliftIO.Async qualified as Async
+
+data VerificationResult
+ = VerificationCompleted
+ !VerificationReport
+ !VerificationPresentation
+ | CompletedWithExplicitGaps
+ !VerificationReport
+ !VerificationPresentation
+ | VerificationFailure !VerificationReport !FailedVerification
+ | VerificationCheckingFailure
+ !VerificationReport
+ !VerificationDriverError
+ deriving (Show)
+
+-- | Strict owner-independent source presentation retained only after the
+-- complete typed workspace succeeds.
+data VerificationPresentation = VerificationPresentation
+ !HtmlExport.HtmlPresentation
+
+instance Show VerificationPresentation where
+ show _presentation =
+ "VerificationPresentation <HTML presentation>"
+
+verificationHtmlPresentation
+ :: VerificationPresentation
+ -> HtmlExport.HtmlPresentation
+verificationHtmlPresentation (VerificationPresentation presentation) =
+ presentation
+
+data ReportedEscapeKind
+ = ReportedSourceAxiom
+ | ReportedOmitted
+ deriving (Show, Eq)
+
+data ReportedEscape = ReportedEscape
+ { reportedEscapeKind :: !ReportedEscapeKind
+ , reportedEscapeLocation :: !Location
+ }
+ deriving (Show, Eq)
+
+data VerificationReport = VerificationReport
+ { verificationDirectEscapes :: ![ReportedEscape]
+ }
+ deriving (Show, Eq)
+
+newtype VerificationRequestObserver = VerificationRequestObserver
+ { observeVerificationRequest
+ :: WorkPosition
+ -> PreparedVerificationRequest
+ -> IO ()
+ }
+
+verificationRequestObserver
+ :: (WorkPosition
+ -> PreparedVerificationRequest
+ -> IO ())
+ -> VerificationRequestObserver
+verificationRequestObserver =
+ VerificationRequestObserver
+
+data FailedVerification = FailedVerification
+ { failedVerificationLocation :: !Location
+ , failedVerificationReason :: !VerificationFailureReason
+ }
+ deriving (Show)
+
+data VerificationFailureReason
+ = CountermodelFailure !Text
+ | ContradictoryInputFailure !Text
+ | IndeterminateFailure !Text
+ | ProtocolFailure !Text !Text
+ | TransportFailure !ProverProcessError
+ deriving (Show)
+
+verificationFailureReason
+ :: Either ProverProcessError ProverAnswer
+ -> Maybe VerificationFailureReason
+verificationFailureReason = \case
+ Left processError ->
+ Just (TransportFailure processError)
+ Right Yes ->
+ Nothing
+ Right (CounterSatisfiable tptp) ->
+ Just (CountermodelFailure tptp)
+ Right (ContradictoryAxioms tptp) ->
+ Just (ContradictoryInputFailure tptp)
+ Right (Uncertain tptp) ->
+ Just (IndeterminateFailure tptp)
+ Right (Error taskLabel message) ->
+ Just (ProtocolFailure taskLabel message)
+
+data VerificationDriverError
+ = VerificationWorkspaceError
+ !ParseWorkspaceError
+ | VerificationMissingImportedModule
+ !ResolvedSourceAddress
+ | VerificationMissingRootModule
+ !ResolvedSourceAddress
+ | VerificationFinalPreludeReadinessError
+ !Typed.FinalPreludeReadinessError
+ | VerificationTypedInputError
+ !ResolvedSource
+ !Typed.TypedModuleInputError
+ | VerificationTypedOpenError
+ !ResolvedSource
+ !Declaration.DriverOpenError
+ | VerificationTypedCachedModuleError
+ !ResolvedSource
+ !Typed.CachedTypedModuleError
+ | VerificationTypedModuleError
+ !ResolvedSource
+ !Typed.TypedModuleFailure
+ !Declaration.PendingModulePrefix
+ | VerificationValidationIntegrityError
+ !ResolvedSource
+ !Declaration.ValidationIntegrityError
+ | VerificationAdmittedViewError
+ !ResolvedSource
+ !AdmittedViewError
+ | VerificationParsedArtifactIntegrityError
+ !ResolvedSource
+ !Felix.ParsedArtifactIntegrityError
+ | VerificationStoreFailure !Store.StoreFailure
+ | VerificationModuleArtifactKeyError !Semantic.ModuleArtifactKeyError
+ | VerificationModuleSchedulerInvariant !Text
+ deriving (Show)
+
+instance Exception.Exception VerificationDriverError
+
+data VerificationDriverErrorKind
+ = VerificationSourceFailure
+ | VerificationInfrastructureFailure
+ deriving (Show, Eq)
+
+verificationDriverErrorKind
+ :: VerificationDriverError
+ -> VerificationDriverErrorKind
+verificationDriverErrorKind = \case
+ VerificationWorkspaceError{} -> VerificationSourceFailure
+ VerificationTypedInputError{} -> VerificationSourceFailure
+ VerificationTypedModuleError _source failure _prefix ->
+ case failure of
+ Typed.TypedActionFailed{} -> VerificationSourceFailure
+ _ -> VerificationInfrastructureFailure
+ VerificationMissingImportedModule{} -> VerificationInfrastructureFailure
+ VerificationMissingRootModule{} -> VerificationInfrastructureFailure
+ VerificationFinalPreludeReadinessError{} ->
+ VerificationInfrastructureFailure
+ VerificationTypedOpenError{} -> VerificationInfrastructureFailure
+ VerificationTypedCachedModuleError{} -> VerificationInfrastructureFailure
+ VerificationValidationIntegrityError{} ->
+ VerificationInfrastructureFailure
+ VerificationAdmittedViewError{} -> VerificationInfrastructureFailure
+ VerificationParsedArtifactIntegrityError{} ->
+ VerificationInfrastructureFailure
+ VerificationStoreFailure{} -> VerificationInfrastructureFailure
+ VerificationModuleArtifactKeyError{} ->
+ VerificationInfrastructureFailure
+ VerificationModuleSchedulerInvariant{} ->
+ VerificationInfrastructureFailure
+
+renderVerificationDriverError :: VerificationDriverError -> Text
+renderVerificationDriverError = \case
+ VerificationWorkspaceError failure ->
+ "Verification input failed: "
+ <> Felix.renderParseWorkspaceError failure
+ VerificationTypedInputError source failure ->
+ "Typed module input failed in "
+ <> resolvedSourceDisplay source
+ <> ": " <> Typed.renderTypedModuleInputError failure
+ VerificationTypedOpenError source failure ->
+ "Typed module startup failed in "
+ <> resolvedSourceDisplay source
+ <> ": " <> Declaration.renderDriverOpenError failure
+ VerificationTypedCachedModuleError source failure ->
+ "Cached typed module is invalid in "
+ <> resolvedSourceDisplay source
+ <> ": " <> Typed.renderCachedTypedModuleError failure
+ VerificationTypedModuleError source failure _prefix ->
+ "Typed module checking failed in "
+ <> resolvedSourceDisplay source
+ <> ": " <> Typed.renderTypedModuleFailure failure
+ VerificationValidationIntegrityError source failure ->
+ "Typed module validation store is inconsistent in "
+ <> resolvedSourceDisplay source
+ <> ": " <> Declaration.renderValidationIntegrityError failure
+ VerificationAdmittedViewError source failure ->
+ "Typed admitted-source association is inconsistent in "
+ <> resolvedSourceDisplay source
+ <> ": " <> Text.pack (show failure)
+ VerificationParsedArtifactIntegrityError source failure ->
+ "Parsed artifact is inconsistent in "
+ <> resolvedSourceDisplay source
+ <> ": " <> Text.pack (show failure)
+ VerificationStoreFailure failure ->
+ "Verification store failed: " <> Store.renderStoreFailure failure
+ VerificationModuleArtifactKeyError{} ->
+ "Typed module artifact inputs are inconsistent."
+ VerificationModuleSchedulerInvariant message ->
+ "Typed module scheduler invariant failed: " <> message
+ VerificationMissingImportedModule address ->
+ "Verification could not find checked imported module "
+ <> Text.pack (show address) <> "."
+ VerificationMissingRootModule address ->
+ "Verification could not find checked root module "
+ <> Text.pack (show address) <> "."
+ VerificationFinalPreludeReadinessError{} ->
+ "The packaged final prelude failed."
+
+resolvedSourceDisplay :: ResolvedSource -> Text
+resolvedSourceDisplay source =
+ sourceMountIdText (resolvedSourceMount source)
+ <> ":"
+ <> Text.pack (resolvedSourceLocationPath source)
+
+data TypedWorkspaceOutcome
+ = TypedWorkspaceSucceeded
+ !AdmittedTypedWorkspace
+ | TypedWorkspaceRejected
+ !AdmittedTypedWorkspace
+ !TypedWorkspaceFailure
+
+data TypedWorkspaceFailure
+ = TypedWorkspaceCheckingRejected !VerificationDriverError
+ | TypedWorkspaceProverRejected !FailedVerification
+
+data ModuleTask = ModuleTask
+ { moduleTaskOrdinal :: !Natural
+ , moduleTaskParsed :: !Felix.ParsedModule
+ , moduleTaskDirectAddresses :: ![ResolvedSourceAddress]
+ }
+
+data ModuleCheckResult
+ = ModuleCheckSucceeded
+ !ResolvedSourceAddress
+ !Typed.SealedTypedModule
+ !AdmittedTypedModule
+ | ModuleCheckRejected
+ !AdmittedTypedModule
+ !TypedWorkspaceFailure
+
+data ModuleFailureCandidate = ModuleFailureCandidate
+ !Natural
+ !AdmittedTypedModule
+ !TypedWorkspaceFailure
+
+data AdmittedTypedDeclaration = AdmittedTypedDeclaration
+ !Semantic.DeclarationSlot
+ !Typed.TypedSourceDeclaration
+
+newtype AdmittedTypedModule = AdmittedTypedModule
+ [AdmittedTypedDeclaration]
+
+newtype AdmittedTypedWorkspace = AdmittedTypedWorkspace
+ [AdmittedTypedModule]
+
+data AdmittedViewError
+ = AdmittedDeclarationCountMismatch
+ !Int
+ !Int
+ | AdmittedDeclarationSlotMismatch
+ ![Semantic.DeclarationSlot]
+ ![Semantic.DeclarationSlot]
+ deriving (Show, Eq)
+
+completeAdmittedModule
+ :: Typed.IdentifiedModuleInput
+ -> AdmittedTypedModule
+completeAdmittedModule input =
+ AdmittedTypedModule
+ (uncurry AdmittedTypedDeclaration <$> expectedDeclarations input)
+
+checkedAdmittedModule
+ :: Bool
+ -> Typed.IdentifiedModuleInput
+ -> Declaration.PendingModulePrefix
+ -> Either AdmittedViewError AdmittedTypedModule
+checkedAdmittedModule requireComplete input prefix = do
+ let expected = expectedDeclarations input
+ expectedSlots = fst <$> expected
+ actualSlots =
+ Declaration.committedBatchSlot
+ <$> Declaration.pendingModulePrefixBatches prefix
+ admittedCount = length actualSlots
+ if requireComplete
+ then unless
+ (admittedCount == length expected)
+ (Left
+ (AdmittedDeclarationCountMismatch
+ (length expected)
+ admittedCount))
+ else unless
+ (admittedCount <= length expected)
+ (Left
+ (AdmittedDeclarationCountMismatch
+ (length expected)
+ admittedCount))
+ unless
+ (actualSlots == take admittedCount expectedSlots)
+ (Left
+ (AdmittedDeclarationSlotMismatch
+ (take admittedCount expectedSlots)
+ actualSlots))
+ pure
+ (AdmittedTypedModule
+ [ AdmittedTypedDeclaration slot declaration
+ | (slot, declaration) <- take admittedCount expected
+ ])
+
+expectedDeclarations
+ :: Typed.IdentifiedModuleInput
+ -> [(Semantic.DeclarationSlot, Typed.TypedSourceDeclaration)]
+expectedDeclarations input =
+ zipWith
+ (\ordinal declaration ->
+ ( Semantic.declarationSlot
+ (Typed.identifiedModuleOwner input)
+ (localDeclarationOrdinal ordinal)
+ , declaration
+ ))
+ [0..]
+ (Typed.typedSourceDeclarations
+ (Typed.identifiedModuleParsed input))
+
+data StoreValidationMode
+ = FreshStoreValidation
+ | WarmStoreValidation
+ deriving (Show, Eq)
+
+data VerificationSession = VerificationSession
+ !Foundation.CheckedFoundation
+ !Store.Store
+
+data VerificationSessionError
+ = VerificationSessionFoundationError
+ !(NonEmpty Foundation.FoundationManifestError)
+ | VerificationSessionStoreError !Store.StoreLifecycleError
+ | VerificationSessionTheoryMismatch !Identity.TheoryId !Identity.TheoryId
+ deriving (Show)
+
+withVerificationSession
+ :: Store.StoreLease
+ -> (VerificationSession -> IO value)
+ -> IO (Either VerificationSessionError value)
+withVerificationSession lease action =
+ case Foundation.checkedFoundation of
+ Left failure ->
+ pure (Left (VerificationSessionFoundationError failure))
+ Right foundation -> do
+ opened <- Store.withOpenStore
+ lease
+ (Identity.theoryId foundation)
+ (\_startup store ->
+ action (VerificationSession foundation store))
+ pure (first VerificationSessionStoreError opened)
+
+-- | Borrow an already-open store while preserving the session's
+-- foundation/store identity invariant. The caller retains ownership of the
+-- store lifetime; ordinary hosts should prefer 'withVerificationSession'.
+withVerificationSessionUsingStore
+ :: Store.Store
+ -> (VerificationSession -> IO value)
+ -> IO (Either VerificationSessionError value)
+withVerificationSessionUsingStore store action =
+ case Foundation.checkedFoundation of
+ Left failure ->
+ pure (Left (VerificationSessionFoundationError failure))
+ Right foundation ->
+ let expected = Identity.theoryId foundation
+ actual = Store.storeTheoryId store
+ in if expected == actual
+ then Right <$> action (VerificationSession foundation store)
+ else pure
+ (Left
+ (VerificationSessionTheoryMismatch expected actual))
+
+data CheckRequest = CheckRequest
+ { checkSourceGraph :: !ResolvedSourceGraph
+ , checkStoreValidationMode :: !StoreValidationMode
+ , checkEffectiveJobs :: !EffectiveJobs
+ , checkVampire :: !Vampire
+ , checkRequestObserver :: !VerificationRequestObserver
+ }
+
+data CheckOutcome = CheckOutcome
+ { checkVerificationResult :: !VerificationResult
+ , checkSlowAtpReport :: !SlowAtpReport
+ }
+ deriving (Show)
+
+checkWorkspace
+ :: VerificationSession
+ -> CheckRequest
+ -> IO (Either VerificationDriverError CheckOutcome)
+checkWorkspace session request =
+ Exception.try (checkWorkspaceThrowing session request)
+
+checkWorkspaceThrowing
+ :: VerificationSession
+ -> CheckRequest
+ -> IO CheckOutcome
+checkWorkspaceThrowing
+ (VerificationSession foundation store)
+ request = do
+ memo <- Store.newStoreMemo store
+ storeCoordinator <- Store.newStoreCoordinator
+ withVampireExecutor
+ (checkEffectiveJobs request)
+ (checkVampire request)
+ (observeVerificationRequest (checkRequestObserver request))
+ \executor -> do
+ prelude <- withVampireRequestOwner executor \owner -> do
+ preludeResolver <- typedVampireResolver owner 0
+ Typed.acquireFinalPreludeSession
+ memo store foundation preludeResolver
+ >>= either
+ (throwIO . VerificationFinalPreludeReadinessError)
+ pure
+ let preludeSyntax =
+ Typed.sealedTypedModuleSyntax
+ (Typed.finalPreludeModule prelude)
+ syntaxInputs _source = [preludeSyntax]
+ parsed <-
+ Felix.parseResolvedSourceGraphWithStoreAndSyntaxInputsAndGraphValidation
+ store
+ (checkSourceGraph request)
+ syntaxInputs
+ (Prelude.rejectOrdinaryPreludeSourceGraph
+ (Typed.finalPreludeSource prelude))
+ >>= either throwParseExecutionError pure
+ admittedResult <-
+ checkTypedWorkspace
+ memo
+ storeCoordinator
+ foundation
+ prelude
+ executor
+ (checkEffectiveJobs request)
+ (checkStoreValidationMode request)
+ parsed
+ store
+ slowReport <- vampireExecutorSlowAtpReport executor
+ let result =
+ case admittedResult of
+ TypedWorkspaceRejected admitted failure ->
+ let report = admittedWorkspaceReport admitted
+ in case failure of
+ TypedWorkspaceCheckingRejected checkingFailure ->
+ VerificationCheckingFailure
+ report checkingFailure
+ TypedWorkspaceProverRejected proverFailure ->
+ VerificationFailure report proverFailure
+ TypedWorkspaceSucceeded admitted ->
+ completedResult
+ (admittedWorkspaceReport admitted)
+ (VerificationPresentation
+ (HtmlExport.htmlPresentationFromParsedWorkspace
+ parsed))
+ pure (CheckOutcome result slowReport)
+ where
+ throwParseExecutionError = \case
+ Felix.ParseExecutionWorkspaceError failure ->
+ throwIO (VerificationWorkspaceError failure)
+ Felix.ParseExecutionStoreFailure failure ->
+ throwIO (VerificationStoreFailure failure)
+ Felix.ParseExecutionArtifactIntegrityFailure source failure ->
+ throwIO
+ (VerificationParsedArtifactIntegrityError source failure)
+
+checkTypedWorkspace
+ :: Store.StoreMemo
+ -> Store.StoreCoordinator
+ -> Foundation.CheckedFoundation
+ -> Typed.FinalPreludeSession
+ -> VampireExecutor
+ -> EffectiveJobs
+ -> StoreValidationMode
+ -> ParsedSourceWorkspace
+ -> Store.Store
+ -> IO TypedWorkspaceOutcome
+checkTypedWorkspace
+ memo
+ storeCoordinator
+ foundation
+ prelude
+ executor
+ selectedJobs
+ validationMode
+ workspace
+ store = do
+ let modules =
+ zipWith
+ makeTask
+ [1..]
+ (toList
+ (Felix.parsedWorkspaceImportedBeforeImporter workspace))
+ rootAddress =
+ Felix.parsedModuleAddress
+ (Felix.parsedWorkspaceRootModule workspace)
+ scheduleModules
+ rootAddress
+ modules
+ Map.empty
+ Map.empty
+ Map.empty
+ Nothing
+ where
+ workerBound = effectiveJobsValue selectedJobs
+
+ makeTask ordinal parsed =
+ ModuleTask
+ { moduleTaskOrdinal = ordinal
+ , moduleTaskParsed = parsed
+ , moduleTaskDirectAddresses =
+ nubOrd
+ (Felix.parsedImportedAddress
+ <$> Felix.parsedModuleImports parsed)
+ }
+
+ scheduleModules
+ rootAddress
+ pending
+ running
+ sealedByAddress
+ admittedByOrdinal
+ candidate = do
+ (pending', running') <-
+ startReadyModules
+ pending
+ running
+ sealedByAddress
+ candidate
+ Exception.onException
+ (if Map.null running'
+ then case candidate of
+ Just selected
+ | any
+ (\task ->
+ moduleTaskOrdinal task
+ < candidateOrdinal selected)
+ pending' ->
+ throwIO
+ (VerificationModuleSchedulerInvariant
+ "an earlier module is not terminal")
+ | otherwise ->
+ pure
+ (TypedWorkspaceRejected
+ (admittedWorkspaceThrough
+ admittedByOrdinal
+ selected)
+ (candidateFailure selected))
+ Nothing
+ | null pending' -> do
+ unless
+ (Map.member rootAddress sealedByAddress)
+ (throwIO
+ (VerificationMissingRootModule
+ rootAddress))
+ pure
+ (TypedWorkspaceSucceeded
+ (completeAdmittedWorkspace
+ admittedByOrdinal))
+ | otherwise ->
+ throwIO
+ (VerificationModuleSchedulerInvariant
+ "no ready module and no running module")
+ else do
+ (_completedAsync, (ordinal, completed)) <-
+ Async.waitAny (Map.elems running')
+ let runningWithoutCompleted =
+ Map.delete ordinal running'
+ case completed of
+ Left fatal -> do
+ cancelModuleCheckers runningWithoutCompleted
+ Exception.throwIO fatal
+ Right (ModuleCheckSucceeded
+ address sealed admittedModule) ->
+ scheduleModules
+ rootAddress
+ pending'
+ runningWithoutCompleted
+ (Map.insert address sealed sealedByAddress)
+ (Map.insert
+ ordinal
+ admittedModule
+ admittedByOrdinal)
+ candidate
+ Right (ModuleCheckRejected
+ admittedModule failure) -> do
+ let selected =
+ chooseEarlierFailure
+ candidate
+ (ModuleFailureCandidate
+ ordinal
+ admittedModule
+ failure)
+ cutoff = candidateOrdinal selected
+ (later, retained) =
+ Map.partitionWithKey
+ (\runningOrdinal _async ->
+ runningOrdinal > cutoff)
+ runningWithoutCompleted
+ cancelModuleCheckers later
+ scheduleModules
+ rootAddress
+ pending'
+ retained
+ sealedByAddress
+ admittedByOrdinal
+ (Just selected)
+ )
+ (cancelModuleCheckers running')
+
+ startReadyModules
+ pending
+ running
+ sealedByAddress
+ candidate
+ | Map.size running >= workerBound =
+ pure (pending, running)
+ | otherwise =
+ case extractFirstReady candidate sealedByAddress pending of
+ Nothing ->
+ pure (pending, running)
+ Just (task, remaining) -> do
+ checker <- Async.async do
+ completed <-
+ (Exception.try
+ (checkModule task sealedByAddress)
+ :: IO
+ (Either
+ Exception.SomeException
+ ModuleCheckResult))
+ pure (moduleTaskOrdinal task, completed)
+ startReadyModules
+ remaining
+ (Map.insert
+ (moduleTaskOrdinal task)
+ checker
+ running)
+ sealedByAddress
+ candidate
+
+ checkModule task sealedByAddress =
+ withVampireRequestOwner executor \requestOwner -> do
+ let parsed = moduleTaskParsed task
+ source = Felix.parsedModuleResolved parsed
+ address = Felix.parsedModuleAddress parsed
+ direct <-
+ traverse
+ (\directAddress ->
+ maybe
+ (throwIO
+ (VerificationMissingImportedModule
+ directAddress))
+ pure
+ (Map.lookup directAddress sealedByAddress))
+ (moduleTaskDirectAddresses task)
+ resolver <-
+ typedVampireResolver
+ requestOwner
+ (moduleTaskOrdinal task)
+ input <-
+ either
+ (throwIO . VerificationTypedInputError source)
+ pure
+ (Typed.typedModuleInput
+ foundation
+ (Typed.finalPreludeReadiness prelude)
+ resolver
+ validationRun
+ parsed
+ direct)
+ loadCachedModule parsed direct >>= \case
+ Just sealed -> do
+ pure
+ (ModuleCheckSucceeded
+ address
+ sealed
+ (completeAdmittedModule
+ (Typed.identifiedPhysicalModule parsed)))
+ Nothing -> do
+ typedResult <-
+ Exception.catch
+ (Typed.runTypedModule input)
+ (\failure ->
+ throwIO
+ (VerificationValidationIntegrityError
+ source
+ failure))
+ case typedResult of
+ Typed.TypedModuleOpenFailed err ->
+ throwIO (VerificationTypedOpenError source err)
+ Typed.TypedModuleFailed err prefix -> do
+ let driverFailure =
+ VerificationTypedModuleError
+ source err prefix
+ case classifyTypedModuleFailure err of
+ TypedIntegrityFailure ->
+ throwIO driverFailure
+ TypedCheckingRejection ->
+ reportFailure
+ parsed
+ prefix
+ (TypedWorkspaceCheckingRejected
+ driverFailure)
+ TypedVerificationRejection failed ->
+ reportFailure
+ parsed
+ prefix
+ (TypedWorkspaceProverRejected failed)
+ TypedProverFailure failed ->
+ reportFailure
+ parsed
+ prefix
+ (TypedWorkspaceProverRejected failed)
+ Typed.TypedModuleSucceeded sealed -> do
+ admittedModule <-
+ either
+ (throwIO
+ . VerificationAdmittedViewError source)
+ pure
+ (checkedAdmittedModule
+ True
+ (Typed.identifiedPhysicalModule parsed)
+ (Typed.sealedTypedModulePrefix sealed))
+ persistSealed
+ (Typed.identifiedPhysicalModule parsed)
+ sealed
+ pure
+ (ModuleCheckSucceeded
+ address sealed admittedModule)
+
+ reportFailure parsed prefix failure = do
+ let source = Felix.parsedModuleResolved parsed
+ admittedModule <-
+ either
+ (throwIO . VerificationAdmittedViewError source)
+ pure
+ (checkedAdmittedModule
+ False
+ (Typed.identifiedPhysicalModule parsed)
+ prefix)
+ Store.withStoreCoordinator storeCoordinator
+ (Store.writePendingModulePrefix store prefix)
+ >>= either
+ (throwIO . VerificationStoreFailure)
+ pure
+ pure (ModuleCheckRejected admittedModule failure)
+
+ storeValidationLookup lookupStore =
+ Declaration.validationLookup
+ (\key ->
+ Store.withStoreCoordinator storeCoordinator
+ (Store.loadProofValidation lookupStore key)
+ >>= either
+ (throwIO . VerificationStoreFailure)
+ pure)
+ (\key ->
+ Store.withStoreCoordinator storeCoordinator
+ (Store.loadDeclarationValidation lookupStore key)
+ >>= either
+ (throwIO . VerificationStoreFailure)
+ pure)
+
+ validationRun =
+ case validationMode of
+ FreshStoreValidation ->
+ Declaration.FreshValidation
+ WarmStoreValidation ->
+ Declaration.WarmValidation
+ (storeValidationLookup store)
+
+ persistSealed input sealed = do
+ artifactKey <-
+ either
+ (throwIO . VerificationModuleArtifactKeyError)
+ pure
+ (Semantic.moduleArtifactKey
+ (Typed.identifiedModuleOwner input)
+ (Felix.identifiedParsedModuleId
+ (Typed.identifiedModuleParsed input))
+ (Semantic.semanticInterfaceDirectInputs
+ (Typed.sealedTypedModuleSemantic sealed))
+ (Identity.theoryId foundation))
+ let artifact =
+ Semantic.moduleArtifactResult
+ artifactKey
+ (Syntax.moduleSyntaxAssertedId
+ (Typed.sealedTypedModuleSyntax sealed))
+ (Semantic.semanticInterfaceAssertedId
+ (Typed.sealedTypedModuleSemantic sealed))
+ acknowledged <-
+ Store.withStoreCoordinator storeCoordinator
+ (Store.writeSealedModule
+ store
+ (Typed.sealedTypedModulePrefix sealed)
+ [Typed.sealedTypedModuleSyntax sealed]
+ [Typed.sealedTypedModuleSemantic sealed]
+ artifact)
+ >>= either
+ (throwIO . VerificationStoreFailure)
+ pure
+ unless
+ (acknowledged == artifact)
+ (throwIO
+ (VerificationStoreFailure
+ Store.StoreModuleArtifactIdMismatch))
+
+ loadCachedModule parsed direct =
+ case validationMode of
+ WarmStoreValidation -> do
+ let owner =
+ Typed.identifiedModuleOwner
+ (Typed.identifiedPhysicalModule parsed)
+ directSemantic =
+ Semantic.semanticInterfaceAssertedId
+ (Typed.sealedTypedModuleSemantic
+ (Typed.finalPreludeModule prelude))
+ : ( Semantic.semanticInterfaceAssertedId
+ . Typed.sealedTypedModuleSemantic
+ <$> direct
+ )
+ artifactKey <-
+ either
+ (throwIO . VerificationModuleArtifactKeyError)
+ pure
+ (Semantic.moduleArtifactKey
+ owner
+ (Felix.identifiedParsedModuleId
+ (Typed.identifiedModuleParsed
+ (Typed.identifiedPhysicalModule parsed)))
+ directSemantic
+ (Identity.theoryId foundation))
+ loaded <-
+ Store.withStoreCoordinator storeCoordinator
+ (Store.loadCachedModuleInstallation
+ memo
+ store
+ artifactKey
+ (Syntax.moduleSyntaxAssertedId
+ (Felix.parsedModuleSyntaxInterface parsed)))
+ case loaded of
+ Left failure ->
+ throwIO (VerificationStoreFailure failure)
+ Right Nothing ->
+ pure Nothing
+ Right (Just installation) ->
+ either
+ (throwIO
+ . VerificationTypedCachedModuleError
+ (Felix.parsedModuleResolved parsed))
+ (pure . Just)
+ (Typed.cachedSealedTypedModule
+ foundation
+ (Typed.finalPreludeModule prelude : direct)
+ installation)
+ FreshStoreValidation ->
+ pure Nothing
+
+ taskMayStart candidate sealedByAddress task =
+ maybe True
+ (moduleTaskOrdinal task <)
+ (candidateOrdinal <$> candidate)
+ && all
+ (`Map.member` sealedByAddress)
+ (moduleTaskDirectAddresses task)
+
+ extractFirstReady candidate sealedByAddress = go []
+ where
+ go _before [] = Nothing
+ go before (task : after)
+ | taskMayStart candidate sealedByAddress task =
+ Just (task, reverse before <> after)
+ | otherwise =
+ go (task : before) after
+
+ chooseEarlierFailure Nothing incoming = incoming
+ chooseEarlierFailure (Just current) incoming
+ | candidateOrdinal incoming < candidateOrdinal current = incoming
+ | otherwise = current
+
+ candidateOrdinal (ModuleFailureCandidate ordinal _admitted _failure) =
+ ordinal
+
+ candidateFailure (ModuleFailureCandidate _ordinal _admitted failure) =
+ failure
+
+ candidateAdmitted (ModuleFailureCandidate _ordinal admitted _failure) =
+ admitted
+
+ completeAdmittedWorkspace admittedByOrdinal =
+ AdmittedTypedWorkspace
+ ( completeAdmittedModule (Typed.finalPreludeInput prelude)
+ : fmap snd (Map.toAscList admittedByOrdinal)
+ )
+
+ admittedWorkspaceThrough admittedByOrdinal selected =
+ let cutoff = candidateOrdinal selected
+ earlier = Map.filterWithKey
+ (\ordinal _admitted -> ordinal < cutoff)
+ admittedByOrdinal
+ in AdmittedTypedWorkspace
+ ( completeAdmittedModule (Typed.finalPreludeInput prelude)
+ : ( fmap snd (Map.toAscList earlier)
+ <> [candidateAdmitted selected]
+ )
+ )
+
+ cancelModuleCheckers running = do
+ traverse_ Async.cancel (Map.elems running)
+ traverse_ Async.waitCatch (Map.elems running)
+
+data TypedFailureClassification
+ = TypedCheckingRejection
+ | TypedVerificationRejection !FailedVerification
+ | TypedProverFailure !FailedVerification
+ | TypedIntegrityFailure
+
+-- | Classify failures at the typed checking boundary conservatively.
+--
+-- Only source elaboration and recognized prover outcomes may retain an
+-- admitted source report. Every declaration/sealing invariant, including a
+-- future constructor not explicitly recognized below, remains fatal.
+classifyTypedModuleFailure
+ :: Typed.TypedModuleFailure
+ -> TypedFailureClassification
+classifyTypedModuleFailure = \case
+ Typed.TypedActionFailed{} ->
+ TypedCheckingRejection
+ Typed.TypedDeclarationFailed
+ (Declaration.ProofObligationFailedAt
+ location
+ (Declaration.VampireProcessFailed processError)) ->
+ classifyTypedProverResult location (Left processError)
+ Typed.TypedDeclarationFailed
+ (Declaration.ProofObligationFailedAt
+ location
+ (Declaration.VampireObligationRejected answer)) ->
+ classifyTypedProverResult location (Right answer)
+ _failure ->
+ TypedIntegrityFailure
+
+classifyTypedProverResult
+ :: Location
+ -> Either ProverProcessError ProverAnswer
+ -> TypedFailureClassification
+classifyTypedProverResult location result =
+ case verificationFailureReason result of
+ Nothing ->
+ TypedIntegrityFailure
+ Just reason ->
+ let failed = FailedVerification location reason
+ in case reason of
+ CountermodelFailure{} ->
+ TypedVerificationRejection failed
+ ContradictoryInputFailure{} ->
+ TypedVerificationRejection failed
+ IndeterminateFailure{} ->
+ TypedProverFailure failed
+ ProtocolFailure{} ->
+ TypedProverFailure failed
+ TransportFailure{} ->
+ TypedProverFailure failed
+
+typedVampireResolver
+ :: VampireRequestOwner
+ -> Natural
+ -> IO Declaration.VampireResolver
+typedVampireResolver
+ requestOwner moduleOrdinal = do
+ localOrdinalRef <- newIORef 1
+ let reserve requests = do
+ let batchSize = NonEmpty.length requests
+ ordinalCount = fromIntegral batchSize
+ firstOrdinal <- atomicModifyIORef' localOrdinalRef
+ (\current -> (current + ordinalCount, current))
+ let positions =
+ NonEmpty.fromList
+ [ workPosition moduleOrdinal ordinal
+ | ordinal <-
+ [firstOrdinal .. firstOrdinal + ordinalCount - 1]
+ ]
+ pure positions
+ submit requests = do
+ positions <- reserve requests
+ traverse
+ (\(position, Declaration.VampireSubmission location request) ->
+ submitVampireRequest
+ requestOwner position location request)
+ (NonEmpty.zip positions requests)
+ pure (Declaration.vampireSubmissionResolver submit)
+
+admittedWorkspaceReport
+ :: AdmittedTypedWorkspace
+ -> VerificationReport
+admittedWorkspaceReport (AdmittedTypedWorkspace modules) =
+ VerificationReport
+ { verificationDirectEscapes =
+ concatMap admittedModuleEscapes modules
+ }
+
+admittedModuleEscapes
+ :: AdmittedTypedModule
+ -> [ReportedEscape]
+admittedModuleEscapes (AdmittedTypedModule declarations) =
+ concatMap admittedDeclarationEscapes declarations
+
+admittedDeclarationEscapes
+ :: AdmittedTypedDeclaration
+ -> [ReportedEscape]
+admittedDeclarationEscapes
+ (AdmittedTypedDeclaration _slot declaration) =
+ axiomEscape <> proofEscapes
+ where
+ axiomEscape =
+ case Typed.typedSourceDeclarationHead declaration of
+ Raw.BlockAxiom location _title _marker _axiom ->
+ [ReportedEscape ReportedSourceAxiom location]
+ _ ->
+ []
+ proofEscapes =
+ maybe [] omittedProofEscapes
+ (Typed.typedSourceDeclarationProof declaration)
+
+omittedProofEscapes :: Raw.Proof -> [ReportedEscape]
+omittedProofEscapes = \case
+ Raw.Omitted location ->
+ [ReportedEscape ReportedOmitted location]
+ Raw.Qed{} ->
+ []
+ Raw.Contradiction{} ->
+ []
+ Raw.ByCase _location cases ->
+ concatMap (omittedProofEscapes . Raw.caseProof) cases
+ Raw.ByContradiction _location proof ->
+ omittedProofEscapes proof
+ Raw.BySetInduction _location _term proof ->
+ omittedProofEscapes proof
+ Raw.ByOrdInduction _location proof ->
+ omittedProofEscapes proof
+ Raw.Assume _location _statement proof ->
+ omittedProofEscapes proof
+ Raw.FixSymbolic _location _variables _bound proof ->
+ omittedProofEscapes proof
+ Raw.FixSuchThat _location _variables _statement proof ->
+ omittedProofEscapes proof
+ Raw.Calc _location _quantifier _calculation proof ->
+ omittedProofEscapes proof
+ Raw.TakeVar _location _variables _bound _statement _justification proof ->
+ omittedProofEscapes proof
+ Raw.TakeNoun _location _noun _justification proof ->
+ omittedProofEscapes proof
+ Raw.Have _location _condition _statement _justification proof ->
+ omittedProofEscapes proof
+ Raw.Suffices _location _statement _justification proof ->
+ omittedProofEscapes proof
+ Raw.Subclaim _location _statement subproof continuation ->
+ omittedProofEscapes subproof <> omittedProofEscapes continuation
+ Raw.Define _location _variable _expression proof ->
+ omittedProofEscapes proof
+ Raw.DefineFunction
+ _location _function _argument _value _domainVariable _domain
+ proof ->
+ omittedProofEscapes proof
+ Raw.DefineFunctionLocal
+ _location _function _argument _domain _target _ruleVariable
+ _rules proof ->
+ omittedProofEscapes proof
+
+completedResult
+ :: VerificationReport
+ -> VerificationPresentation
+ -> VerificationResult
+completedResult report presentation
+ | any ((== ReportedOmitted) . reportedEscapeKind)
+ (verificationDirectEscapes report) =
+ CompletedWithExplicitGaps report presentation
+ | otherwise =
+ VerificationCompleted report presentation